会议集成指南

简介

本文档主要介绍如何使用 JusTalk Cloud SDK for Android(以下简称 SDK)实现基本的音频或视频会议功能。请根据需要集成其他扩展功能。
本文涉及的接口类和对象有:

会议对象

会议对象包括会场和会议成员。

会场

会场是会议的基础,当第一个会议成员进入会议时,会场自动创建。最后一个成员离开会场时,会场自动销毁。

会议成员

会议成员分为会议参与者和会议观察者。

  • 会议参与者:即会议中可以参与交互的成员。一个会议中参与者人数可以多达16人。
  • 会议观察者:即仅能观看会议的普通成员。一个会议中观察者人数可以多达500名。会议参与者和会议观察者可以互相转化,但会议参与者最多不超过 16 人。

交互说明

SDK 封装了来自服务器的通知和异步执行的用户操作结果通知,您可以通过注册监听器(Listener)来监听事件通知。事件通知分为会场事件通知和成员事件通知。

会场事件通知

当您调用 JCConference 中的接口与服务器交互,或者会场属性发生改变时,这些事件会以会场事件通知的形式反馈到 UI,您可以按照需要监听这些事件。会场事件监听器接口如下:

    public interface JCEventListener {
        void JCEventPosted(int event, int eventCode);
    }

您可以实现事件接口,并调用 JCConference.registerJCEventListener(JCEventListener listener) 接口注册监听器。具体事件类型,请参考会议事件和事件码说明

    public class ConferencePresenter implements JCConference.JCEventListener {
        @Override
        public void JCEventPosted(int event, int eventCode) {
            // 处理会议事件
        }

        public void registerListener {
            // 注册监听器
            JCConference.getInstance().registerJCEventListener(this);
        }
    }

成员事件通知

当会议中成员发生改变,如成员加入、退出或者成员角色状态发生改变时,这些事件会以成员事件通知的形式反馈到 UI,您可以按照需要监听这些事件。成员事件监听器接口如下:

    public interface JCParticipantListener {
        void JCParticipantUpdated(String userId, int event, int eventCode);
    }

您可以实现事件接口,并调用 JCConference.registerJCEventListener(JCEventListener listener) 接口注册监听器。具体成员事件类型,请参考成员事件和事件码

    public class ConferencePresenter implements JCConference.JCParticipantListener {
        @Override
        public void JCParticipantUpdated(int event, int eventCode) {
            // 处理成员事件
        }

        public void registerListener {
            // 注册监听器
            JCConference.getInstance().registerJCParticipantListener(this);
        }
    }

会议操作

加入会议

加入会议前,需要定义一个 roomId 作为该会议实例的唯一标识。在多个设备上使用同一个 AppKey 初始化 SDK,并使用同一个 roomId,即可加入同一个会议。
1.调用加入会议接口。加入会议接口为异步调用,调用后等待会议事件通知。

    int ret = JCConference.getInstance().join(roomId, password, displayName);

2.处理会议事件通知。

void JCEventPosted(int event, int eventCode);
    switch (event) {
        case JCConferenceConstants.EVENT_CONF_JOIN:
            if (eventCode == JCConferenceConstants.REASON_JOIN_OK) {
                // 加入会议成功
            } else {
                // 加入会议失败,根据 eventCode 值,显示失败原因
            }
            break;
    }

离开会议

离开会议只需调用离开会议接口,如下。您必须先离开会议才能加入上一个会议。
1.调用离开会议接口。离开会议接口为异步调用,调用后等待会议事件通知。

    JCConference.getInstance().leave();

2.处理会议时间通知

void JCEventPosted(int event, int eventCode);
    switch (event) {
        case JCConferenceConstants.EVENT_CONF_END:
            if (eventCode == JCConferenceConstants.REASON_END_QUIT) {
                // 已离开会议
            } else {
                // 被动离开会议,具体根据 eventCode 处理。
            }
            break;
    }

会议成员变化

加入会议后,您可以调用以下接口获取会议中的成员列表:

    ArrayList<JCParticipant> list = JCConference.getInstance().getParticipants();

按照成员事件通知章节,注册成员事件监听后,会议成员发生变化时都可以得到通知。

    public class ConferencePresenter implements JCConference.JCParticipantListener {
        @Override
        public void JCParticipantUpdated(int event, int eventCode) {
            switch (event) {
            case JCConferenceConstants.EVENT_PARTP_JOIN:
                // 成员加入
                break;
            case JCConferenceConstants.EVENT_PARTP_LEAVE:
                // 成员离开,根据 eventCode 显示离开具体原因
                break;
            case JCConferenceConstants.EVENT_PARTP_STATE_CHANGED:
                // 成员状态变化,如音视频发送状态。
                break;
            case JCConferenceConstants.EVENT_PARTP_ROLE_CHANGED:
                // 成员角色变化。
                break;
            }
        }
    }

渲染会议成员视频

您可以根据实际需求和会议成员状态决定是否订阅成员的视频及视频大小:

    JCParticipant partp = JCConference.getInstance().getParticipant(userId);
    if (partp.hasVideo()) {
        JCConference.getInstance().requestVideo(userId, JCConferenceConstants.PICTURE_SIZE_LARGE);
    }

您可以预先在界面布局中留出视频渲染位置,也可以在界面上动态添加。以预先留出位置为例:

<RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <FrameLayout
            android:id="@+id/video_container"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
</RelativeLayout >

在界面代码中找到 View,并参考以下示例添加渲染控件,并开始渲染:

    FrameLayout layout = findViewById(R.id.video_container);
    SurfaceView surfaceView = ZmfVideo.renderNew(getApplicationContext());
    layout.addView(surfaceView);
    JCConference.getInstance().startRender(surfaceView, userId, ZmfVideo.RENDER_FULL_CONTENT);

需要停止渲染视频时,参考以下示例停止渲染并释放控件:

    JCConference.getInstance().stopRender(surfaceView);
    layout.removeView(surfaceView);

停止渲染后不要忘记停止视频请求:

    JCConference.getInstance().cancelVideoRequest(userId, JCConferenceConstants.PICTURE_SIZE_LARGE);

发送音频

加入会议后,默认是关闭语音发送的,此时会议中的其它成员是听不到该成员的声音。需要如下操作来开始发送音频数据。
1.调用打开/关闭音频发送接口

    JCConference.getInstance().enableLocalAudioStream(enable);

2.监听成员变化通知,关注自己的 JCConferenceConstants.EVENT_PARTP_STATE_CHANGED 成员状态变化。

    public class ConferencePresenter implements JCConference.JCParticipantListener {
        @Override
        public void JCParticipantUpdated(int event, int eventCode) {
            switch (event) {
            case JCConferenceConstants.EVENT_PARTP_STATE_CHANGED:
                if(JCUtils.isSelf(userId)) {
                    JCParticipant self = JCConference.getInstance().getParticipant(JCApi.getInstance().getOwnUserId());
                    if (self.hasAudio()) {
                        // 音频发送打开
                    } else {
                        // 音频发送关闭
                    }
                }
                break;
            }
        }
    }

发送视频

加入会议后,默认是关闭视频发送的,此时会议中的其它成员是订阅不到该成员的视频。需要如下操作来开始发送视频数据。
1.调用打开/关闭音频发送接口

    JCConference.getInstance().enableLocalVideoStream(enable);

2.监听成员变化通知,关注自己的 JCConferenceConstants.EVENT_PARTP_STATE_CHANGED 成员状态变化。

    public class ConferencePresenter implements JCConference.JCParticipantListener {
        @Override
        public void JCParticipantUpdated(int event, int eventCode) {
            switch (event) {
            case JCConferenceConstants.EVENT_PARTP_STATE_CHANGED:
                if(JCUtils.isSelf(userId)) {
                    JCParticipant self = JCConference.getInstance().getParticipant(JCApi.getInstance().getOwnUserId());
                    if (self.hasVideo()) {
                        // 音频发送打开
                    } else {
                        // 音频发送关闭(失败)
                    }
                }
                break;
            }
        }
    }