# 实现视频双录

本文档为您展示通过 SDK 实现视频双录(无排队机)的相关步骤,帮助您在多人视频通话场景下实现创建会议、邀请新成员加入、结束/离开会议的相关能力。

# 加入会议

通过JCMediaChannelJoinParam (opens new window)可在加入会议前设置是否参会最大人数,参会密码,最大分辨率,全局长宽比等。

JCMediaChannelJoinParam *param  = [[JCMediaChannelJoinParam alloc] init];
param.isUploadLocalAudio = true;//是否上传本地音频流
param.isUploadLocalVideo = true;//是否上传本地视频流
[JCManager.shared.mediaChannel join:channelId joinParam:param];

加入频道结果通过 onJoin (opens new window) 回调。

/**
 *  @brief 加入频道结果回调
 *  @param result true 表示成功,false 表示失败
 *  @param reason 加入失败原因,当 result 为 false 时该值有效
 *  @param channelId 媒体频道标识符
 *  @see JCMediaChannelReason
 */
 - (void)onJoin:(bool)result reason:(JCMediaChannelReason)reason channelId:(NSString *)channelId mediaChannel:(JCMediaChannel *)mediaChannel;

示例代码:

// 加入频道结果回调
-(void)onJoin:(bool)result reason:(JCMediaChannelReason)reason channelId:(NSString*)channelId mediaChannel:(JCMediaChannel *)mediaChannel
    if (result) {
        // 加入频道成功
    } else {
        // 加入频道失败
    }
}

TIP

当加入会议后可通过 mediaChannel.participants (opens new window) 获取已经在会议中的成员 然后渲染当前所有成员(requestVideo,startVideo)

# 创建本地视频画面

加入频道后,如果想看到本地视图画面,需要打开摄像头以创建视图画面。

创建视图画面需要用到 JCMediaDevice (opens new window) 类和 JCMediaDeviceVideoCanvas (opens new window) 类。

本地视图渲染调用 JCMediaDevice (opens new window) 类中的 startCameraVideo (opens new window) 接口。

TIP

startCameraVideo (opens new window) 接口会打开摄像头

/**
 *  @brief 获得预览视频对象,通过此对象能获得视图用于UI显示
 *  @param type 渲染模式,@ref JCMediaDeviceRender
 *  @return JCMediaDeviceVideoCanvas 对象
 */
-(JCMediaDeviceVideoCanvas*)startCameraVideo:(int)type;

TIP

调用该方法后,在挂断通话或者关闭摄像头时需要对应调用 stopVideo (opens new window) 方法停止视频。

示例代码:

// 创建本地视频画面对象
JCMediaDeviceVideoCanvas *local = [mediaDevice startCameraVideo:JCMediaDeviceRenderFullContent];
local.videoView.frame = CGRectMake(0, 0, 100, 100);
[self.view addSubview:local.videoView];

# 新成员加入

当新成员加入频道后,其他成员会收到成员加入的回调。

/**
 *  @brief              新成员加入回调
 *  @param participant  成员对象
 */
-(void)onParticipantJoin:(JCMediaChannelParticipant*)participant mediaChannel:(JCMediaChannel *)mediaChannel;

此时可以进行远端视图渲染并请求远端成员的视频流。

# 创建远端视频画面

远端视图渲染调用 startVideo (opens new window) 接口获得预览视频对象。

/**
 *  @brief                  获得预览视频对象,通过此对象能获得视图用于UI显示
 *  @param videoSource      渲染标识串,比如 JCMediaChannelParticipant JCCallItem 中的 renderId
 *  @param type             渲染模式,@ref JCMediaDeviceRender
 *  @return JCMediaDeviceVideoCanvas 对象
 */
-(JCMediaDeviceVideoCanvas*)startVideo:(NSString*)videoSource renderType:(int)type;

TIP

调用该方法后,在挂断通话或者关闭摄像头时需要对应调用 stopVideo (opens new window) 方法停止视频。

由于服务器默认是不转发视频数据的,所以如果想看到远端成员画面需要调用 requestVideo (opens new window) 接口请求远端成员的视频流。

/**
 *  @brief                 请求频道中其他用户的视频流
 *  @param participant     频道中其他成员对象
 *  @param pictureSize     视频请求尺寸类型
 *  @return                返回 true 表示正常执行调用流程,false 表示调用异常
 *  @see JCMediaChannelPictureSize
 *  @warning 当 pictureSize 为 JCMediaChannelPictureSizeNone 表示关闭请求
 */
-(bool)requestVideo:(JCMediaChannelParticipant*)participant pictureSize:(JCMediaChannelPictureSize)pictureSize;

其中,视频尺寸(JCMediaChannelPictureSize)有以下几种:

名称 描述
JCMediaChannelPictureSizeNone 不请求
JCMediaChannelPictureSizeMin 最小尺寸,160x90
JCMediaChannelPictureSizeSmall 小尺寸,320x180,小窗口模式下可以使用小尺寸
JCMediaChannelPictureSizeLarge 大尺寸,640x360
JCMediaChannelPictureSizeMax 最大尺寸,360P 的会议为 640x360 ,720P 的会议为 1280x720

TIP

您可以根据相应的窗口大小使用相应的视频尺寸,比如窗口的大小是 160x90,则应该使用 JCMediaChannelPictureSizeMin,避免造成不必要的流量浪费和额外的功耗。

现在您可以开始多方视频通话了。

示例代码:

-(void)onParticipantJoin:(JCMediaChannelParticipant*)participant mediaChannel:(JCMediaChannel *)mediaChannel{
    // 创建远端视频画面对象,renderId来源JCMediaChannelParticipant对象
    NSArray *partps = mediaChannel.participants;
    for (JCMediaChannelParticipant * partp in partps) {
         // 如果是本端
        if ([partp.userId isEqualToString:client.userId]) {
            // 本地视频渲染
            ...
        } else {
            // 远端视频渲染
            JCMediaDeviceVideoCanvas *remote = [mediaDevice startVideo:partp.renderId renderType:JCMediaDeviceRenderFullContent];
            // 请求远端视频流
            [mediaChannel requestVideo:partp pictureSize:JCMediaChannelPictureSizeMin];
            remote.videoView.frame = CGRectMake(100, 0, 100, 100);
            [self.view addSubview:remote.videoView];
        }
    }
}

# 离开会议

如果想离开会议,可以调用 leave (opens new window) 接口。

/**
 *  离开媒体频道
 *  @return  返回 true 表示正常执行调用流程,false 表示调用异常
 */
-(bool)leave;

示例代码:

// 离开频道
[mediaChannel leave];

如果是多方视频通话,还需要在离开会议后调用 stopVideo (opens new window) 接口移除视频画面。

/**
 *  @brief 停止视频
 *  @param canvas JCMediaDeviceVideoCanvas 对象,由 startVideo 获得
 */
-(void)stopVideo:(JCMediaDeviceVideoCanvas*)canvas;

离开频道后,UI 监听回调离开的原因:

/**
 *  @brief             离开频道结果回调
 *  @param reason      离开原因
 *  @param channelId   频道标识符
 *  @see JCMediaChannelReason
 */
-(void)onLeave:(JCMediaChannelReason)reason channelId:(NSString*)channelId mediaChannel:(JCMediaChannel *)mediaChannel;

示例代码:

// 离开频道回调
-(void)onLeave:(JCMediaChannelReason)reason channelId:(NSString*)channelId mediaChannel:(JCMediaChannel *)mediaChannel;
{
    // 销毁视图画面
    if (item.canvas) {
        [item.canvas.videoView removeFromSuperview];
        [JCManager.shared.mediaDevice stopVideo:item.canvas];
        item.canvas = nil;
    }
}

# 成员离开

当成员离开频道后,其他成员会收到成员离开的回调。

/**
 *  @brief 成员离开回调
 *  @param participant 成员对象
 *  @param reason 操作原因
 */
- (void)onParticipantLeft:(JCMediaChannelParticipant*)participant reason:(int)reason mediaChannel:(JCMediaChannel *)mediaChannel;

# 结束会议

如果想结束会议,可以调用 stop (opens new window) 接口,此时所有成员都将被退出。

/**
*  @brief 关闭频道,所有成员都将被退出
*  @return 返回 true 表示正常执行调用流程,false 表示调用异常
*/
-(bool)stop;

示例代码:

// 结束频道
[mediaChannel stop];

关闭频道的结果通过 onStop (opens new window) 回调

/**
 * brief 解散频道结果回调
 * @param result    true 表示成功,false 表示失败
 * @param reason    解散失败原因,当 result 为 false 时该值有效
 */
-(void)onStop:(bool)result reason:(JCMediaChannelReason)reason mediaChannel:(JCMediaChannel *)mediaChannel;