本章将介绍如何实现多方视频通话,多方视频通话的 API 调用时序见下图:

/cn/document/V2.1/images/doc_python_image/multivideoworkflow.png

初始化

调用 JCMediaDevice.create()JCMediaChannel.create() 以初始化实现多方通话需要的模块::

// 声明对象
JCMediaDevice mMediaDevice;
JCMediaChannel mMediaChannel;

// 初始化函数
public boolean initialize(Context context) {

    //1. 媒体类
    mMediaDevice = JCMediaDevice.create(mClient, new JCMediaDeviceCallback() {
        @Override
        public void onCameraUpdate() {

        }
        @Override
        public void onAudioOutputTypeChange(int i) {

        }
        @Override
        public void onRenderReceived(JCMediaDeviceVideoCanvas jcMediaDeviceVideoCanvas) {

        }
        @Override
        public void onRenderStart(JCMediaDeviceVideoCanvas jcMediaDeviceVideoCanvas) {

        }
    });
    // 2. 媒体通道类
    mMediaChannel = JCMediaChannel.create(client, mediaDevice, new JCMediaChannelCallback() {
        @Override
        public void onMediaChannelStateChange(int i, int i1) {

        }
        @Override
        public void onMediaChannelPropertyChange(JCMediaChannel.PropChangeParam propChangeParam) {

        }
        @Override
        public void onJoin(boolean b, int i, String s) {

        }
        @Override
        public void onLeave(int i, String s) {

        }
        @Override
        public void onStop(boolean b, int i) {

        }
        @Override
        public void onQuery(int i, boolean b, int i1, JCMediaChannelQueryInfo jcMediaChannelQueryInfo) {

        }
        @Override
        public void onParticipantJoin(JCMediaChannelParticipant jcMediaChannelParticipant) {

        }
        @Override
        public void onParticipantLeft(JCMediaChannelParticipant jcMediaChannelParticipant) {

        }
        @Override
        public void onParticipantUpdate(JCMediaChannelParticipant jcMediaChannelParticipant, JCMediaChannelParticipant.ChangeParam changeParam) {

        }
        @Override
        public void onMessageReceive(String s, String s1, String s2) {

        }
        @Override
        public void onInviteSipUserResult(int i, boolean b, int i1) {

        }
        @Override
        public void onParticipantVolumeChange(JCMediaChannelParticipant jcMediaChannelParticipant) {

        }
    });
}

加入频道

  1. 调用 enableUploadAudioStream() 开启音频流。若要开启视频,调用 enableUploadVideoStream() 开启视频流。

    // 1. 开启音频流
    mMediaDeviceChannel.enableUploadAudioStream(true);
    // 2. 开启视频流(语音无需调用此方法)
    mMediaDeviceChannel.enableUploadVIdeoStream(true);
    
  2. 创建并加入频道,需要传入 channelIdOrUriJCMediaChannel.JoinParam

    • channelIdOrUri 表示频道 ID 或频道 Uri。

    • JCMediaChannelJoinParamuriMode 参数设置为 true 时表示传入频道 Uri,设置其他参数时表示传入频道 ID。传入相同的频道 ID 或相同的频道 Uri 的用户会进入同一个频道。

    mMediaChannel.join("222", null);
    
  3. 加入频道后收到 onJoin() 回调。

    @Override
    public void onJoin(boolean result, @JCMediaChannel MediaChannelReason int reason, String channelId) {
        if (result) {
            // 加入频道成功
        } else {
            // 加入频道失败
        }
    }
    

创建本地视频画面

加入频道后,调用 JCMediaChannel 中的 getSelfParticipant() 获取频道内自身对象, 然后调用 JCMediaChannelParticipant 中的 startVideo() 方法打开本地视频预览。返回对象为 JCMediaDeviceVideoCanvas。(调用此方法会打开摄像头)

// 打开本地视频预览
mMediaChannel.getSelfParticipant().startVideo(JCMediaDevice.RENDER_FULL_CONTENT, JCMediaChannel.PICTURESIZE_NONE);

创建远端视频画面

视频通话中,通常需要看到其他用户。加入频道后,调用 JCMediaChannel 中的 getParticipants() 获取频道内所有成员对象。

然后调用 JCMediaChannelParticipant 类中的 startVideo() 获取远端视频画面。返回对象为 JCMediaDeviceVideoCanvas

startVideo() 方法调用后,还需要调用 JCMediaChannel 中的 requestVideo() 方法请求频道中其他用户的视频流。

// 获取所有成员对象
List<JCMediaChannelParticipant> participants = mMediaChannel.getSelfParticipant();
// 调用创建视频画面的方法
participants.get(0).startVideo(JCMediaDevice.RENDER_FULL_CONTENT, JCMediaChannel.PICTURESIZE_NONE);
// 请求远端视频流, 此处调用大尺寸视频窗口
mMediaChannel.requestVideo(participants.get(0), PICTURESIZE_LARGE);

离开频道

调用 leave() 方法可以离开当前频道。

mMediaChannel.leave();

在多方视频通话中,离开频道还需要调用 stopVideo() 移除视频画面。

mParticipant.stopVideo();

离开频道后,自身收到 onLeave() 回调,其他成员同时收到 onParticipantLeft() 回调。

销毁本地和远端视频画面

调用 JCMediaChannelParticipant 里的 stopVideo() 销毁本地和远端视频画面。

// 离开频道结果回调
@Override
public void onLeave(@JCMediaChannel.MediaChannelReason int reason, String channelId) {
    ...
    // 销毁视频画面
    mParticipant.stopVideo();
}

解散频道

如果想解散频道,可以调用下面的接口,此时所有成员都将被退出。

// 结束频道
mMediaChannel.stop();

在多方视频通话中,离开频道还需要调用 stopVideo() 移除视频画面。

mParticipant.stopVideo();

解散频道后,发起结束的成员收到 onStop() 回调,其他成员同时收到 onLeave() 回调。 解散失败原因枚举值请参考 MediaChannelReason

@Override
public void onStop(boolean result, @JCMediaChannel.MediaChannelReason int reason) {
    // 销毁视频, canvas 为 JCMediaDeviceVideoCanvas 对象实例
    mParticipant.stopVideo();
    canvas = null;
}