# 实现视频会议

本文档为您展示通过 SDK 实现视频会议的相关步骤,帮助您在多人会议场景下实现创建/加入会议、查询会议、结束/离开会议、发送消息等相关能力。

开始之前,请您先做好如下准备工作:

  • iOS SDK 下载
  • iOS SDK 配置和初始化
  • iOS 登录

如果您已经做好相关准备工作,即可继续以下的内容。

# 模块初始化

开始集成会控功能前,请先进行模块的初始化。

// 初始化各模块,因为这些模块实例将被频繁使用,建议声明在单例中
JCClient *client = [JCClient create:@"your AppKey" callback:self extraParams:nil];
JCMediaDevice *mediaDevice = [JCMediaDevice create:client callback:self];
JCConference *conference = [JCConference create:client mediaDevice:mediaDevice callback:self];

其中,创建 JCConference (opens new window) 实例的接口如下

/**
 *  @brief 创建              JCConference 对象
 *  @param client           JCClient 对象
 *  @param mediaDevice      JCMediaDevice 对象
 *  @param callback         JCConferenceCallback 回调接口,用于接收 JCConference 相关通知
 *  @return                 返回 JCConference 对象
 */
+ (JCConference *)create:(JCClient *)client mediaDevice:(JCMediaDevice *)mediaDevice callback:(id<JCConferenceCallback>)callback;

会控模块涉及以下类:

名称 描述
JCConference 会控模块类
JCConferenceInfo 会议对象类
JCConferenceParticipant 会议成员类
JCConferenceReserveInfo 预约会议信息类
JCConferenceInviteInfo 邀请成员类
JCConferenceCommandInfo 会议属性变化或会议其他通知
JCConferenceQueryConfResult 预约会议查询结果类
JCConferenceCandidate 被邀请者对象类
JCConferenceCallback 回调代理
JCConferenceRecordRemoteParams 远程录制参数类
JCConferenceSipInviteInfo Sip呼叫参数类

更多关于类的详细信息请查看对应的API文件。

# 基础业务接口调用

fullsizeoutput_1.jpeg

# 创建并加入会议

/**
 * @brief           创建并加入一个会议,结果回调 onConferenceJoin
 *
 * @param confNumber  传 "0" 由服务器生成10位的会议号,可传字母或数字作为自定义会议号
 * @param video     true 视频会议,false 语音会议
 * @param config    会议的其他配置,具体查看"JCConferenceConstants.h"的配置参数
 * @return          true 表示接口调用成功
 */
- (bool)start:(NSString *)confNumber video:(bool)video config:(nullable NSDictionary<NSString *, NSString *> *)config;

其中,配置关键字有:

配置项 描述 关键字
设置会议人数 默认8人,发起会议时可携带 JCConferenceConfigCapacity
设置会议title 发起会议时可携带 JCConferenceConfigTitle
设置会议密码 发起或加入会议时可携带 JCConferenceConfigPassword
会议的扩展字段 用于设置会议的自定义信息,发起会议时可携带 JCConferenceConfigConfExpand
设置会议中视频的比例 比例为16:9或正方形,正方形设置 true,16:9设置 false,默认视频为16:9,发起会议时可携带 JCConferenceConfigVideoSquare
设置会议平滑模式 开启设置 true,不开启设置 false,默认不开启。发起会议时可携带 JCConferenceConfigSmoothMode
最大分辨率 360p设置”0” 720p设置”1” 1080p设置”2”,默认360p, 发起会议时可携带,取值枚举JCConferenceMaxResolution JCConferenceConfigMaxResolution
CDN地址参数 发起会议时可携带 JCConferenceConfigCDN
设置会议最大发送路数 范围1~16,默认16,发起会议时可携带 JCConferenceConfigMaxSender
设置当会议中只剩一个成员时是否结束会议 结束设置 true,不结束设置 false,默认不结束,发起会议时可携带 JCConferenceConfigConfCloseWhenAlone
设置昵称(自己) 发起或加入会议时可携带 JCConferenceConfigParticipantDisplayName
成员的扩展字段 用于设置成员(自己)的自定义信息,发起或加入会议时可携带 JCConferenceConfigParticipantExpand
创会者决定其他成员入会时的默认角色 视频设置”0” 音频设置”1” 观众设置”2”,默认视频,取值枚举JCConferenceParticipantType JCConferenceConfigDefaultMemberRole
是否开启服务器录制 开启传true,不开启传false JCConferenceRemoteRecord
是否固定会议分辨率(360p) 固定传true,不固定传false JCConferenceFixedResolution
加入会议时如果会议不存在是否创建并加入 创建设置 true,不创建设置 false,默认不创建 JCConferenceConfigCreateAndJoin
是否音视频默认开启 开启传@true,则加入会议成功后选择默认音频输入输出设备以及默认摄像头打开,否则传@false,需要应用实现打开关闭音频设备和摄像头,默认开启 JCConferenceConfigMediaHosting
CDN推流和服务器录制分辨率 360p设置”0”,720p设置”1”, 发起会议时可携带,取值枚举JCConferenceCDRecResolution JCConferenceConfigCDRecResolution
成员入会时的角色 视频设置”0” 音频设置”1” 观众设置”2”,默认视频,取值枚举JCConferenceParticipantType JCConferenceConfigParticipantJoinRole
设置(自己)主持人 发起或加入会议时可携带 JCConferenceConfigParticipantSetChairman
设置成员(自己)的音频发送状态 发送设置@true,不发送设置@false,默认不发送,发起或加入会议时可携带 JCConferenceConfigParticipantUploadAudio
设置成员(自己)的视频发送状态 发送设置@true,不发送设置@false,默认不发送,发起或加入会议时可携带 JCConferenceConfigParticipantUploadVideo

示例代码:

NSMutableDictionary *dic = [NSMutableDictionary dictionary];
[dic setObject:@"6" forKey:JCConferenceConfigCapacity];
[dic setObject:@YES forKey:JCConferenceConfigSmoothMode];
[conference start:@"confNumber" video:true config:dic];

调用该方法后会收到 onConferenceJoin (opens new window) 回调,该回调返回加入的结果:

/**
 *  @brief                  加入会议结果回调
 *  @param result           true 表示成功,false 表示失败
 *  @param reason           当 result 为 false 时该值有效 目前加入失败的原因有 JCConferenceReasonTimeOut、JCConferenceReasonFull、JCConferenceReasonInvalidPassword、JCConferenceResasonLocked、JCConferenceReasonAlreadyJoined、JCConferenceReasonOther
 *  @param channelId        媒体频道标识符
 *  @see JCConferenceReason
 */
- (void)onConferenceJoin:(bool)result reason:(JCConferenceReason)reason;

其中,加入失败的原因 JCConferenceReason (opens new window) 有:

/// 正常
JCConferenceReasonNone = 0,
/// 未登录
JCConferenceReasonNotLogin,
/// 超时
JCConferenceReasonTimeOut,
/// 网络异常
JCConferenceReasonNetWork,
/// 被踢
JCConferenceReasonKicked,
/// 掉线
JCConferenceReasonOffline,
/// 主动离开
JCConferenceReasonQuit,
/// 会议关闭
JCConferenceReasonOver,
/// 成员满
JCConferenceReasonFull,
/// 密码无效
JCConferenceReasonInvalidPassword,
/// 会议被锁定
JCConferenceResasonLocked,
/// 群组已有会议
JCConferenceResasonGroupConfExist,
/// 群组没有会议
JCConferenceResasonNoConfInGroup,
/// 该会议号的会议不存在
JCConferenceResasonConfNumberNotFound,
/// 会议号已存在
JCConferenceResasonConfNumberExist,
/// 服务器会议成员总数上限(移动端会议人数)
JCConferenceResasonConfAppConcurrencyFul,
///服务器会议成员总数上限(总会议人数)
JCConferenceResasonConfAllConcurrencyFul,
///该会议已经结束(已经结束的预约会议不能重新通过join接口加入)
JCConferenceResasonConfAlreadyEnded,
/// 其他错误
JCConferenceReasonOther = 100,

示例代码:

- (void)onConferenceJoin:(bool)result reason:(JCConferenceReason)reason
{
    if (result) {
    // 加入成功的处理
    } else {
    // 加入失败的处理
    }
}

# 结束会议

stopconf.png

如果想结束会议,可以调用下面的方法,只有主持人才能调用该接口结束会议。

/**
 * @brief           结束会议,主持人才能调用接口结束会议,结果回调 onConferenceLeave
 *
 * @return          true 表示接口调用成功
 */
- (bool)stop;

调用该方法会收到 onConferenceLeave (opens new window) 回调。

示例代码:

[conference stop];

# 加入已经存在的会议

joinconf.png

如果要加入已经存在的会议,则调用下面的接口。

/**
 * @brief            加入会议,结果回调 onConferenceJoin
 *
 * @param confNumber 会议号
 * @param video     接口暂时没用该参数
 * @param config    会议的其他配置,具体查看"JCConferenceConstants.h"的配置参数
 */
- (bool)join:(NSString *)confNumber video:(bool)video config:(nullable NSDictionary<NSString *, NSString *> *)config;

示例代码:

[conference join:@"12345" video:true config:nil];

加入会议成功后会自动打开音频设备。

调用该接口会收到 onConferenceJoin (opens new window) 回调。

/**
 *  @brief                  成员加入会议回调
 *  @param participant      成员对象
 */
- (void)onConferenceParticipantJoin:(JCConferenceParticipant *)participant;

# 离开会议

leaveconf.png

如果想离开会议,则调用下面的接口。

/**
 *  @brief          离开会议,当前只支持同时加入一个会议
 *  @return         返回 true 表示正常执行调用流程,false 表示调用异常
 */
- (bool)leave;

示例代码:

[conference leave];

离开会议成功后会收到 onConferenceLeave (opens new window) 回调,该回调会返回离开会议的原因。

/**
 *  @brief                  离开会议结果回调
 *  @param reason           离开原因 目前离开的原因有 JCConferenceReasonKicked、JCConferenceReasonOffline、JCConferenceReasonQuit、JCConferenceReasonOver、JCConferenceReasonOther
 *  @see JCConferenceReason
 */
- (void)onConferenceLeave:(JCConferenceReason)reason;

# 请求用户的视频流

加入会议后,调用下面的方法请求用户的视频流。

/**
 *  @brief              请求用户的视频流
 *  @param userId       用户对象userId
 *  @param pictureSize  视频请求尺寸类型
 *  @return             返回 true 表示正常执行调用流程,false 表示调用异常
 *  @see JCConferencePictureSize
 *  @warning 当 pictureSize 为 JCConferencePictureSizeNone 标识关闭请求
 */
- (bool)requestVideo:(NSString *__nonnull)userId pictureSize:(JCConferencePictureSize)pictureSize;

其中,视频请求尺寸 JCConferencePictureSize (opens new window) 有:

/// 不请求
JCConferencePictureSizeNone,
/// 最小尺寸
JCConferencePictureSizeMin,
/// 小尺寸
JCConferencePictureSizeSmall,
/// 大尺寸
JCConferencePictureSizeLarge,
/// 最大尺寸
JCConferencePictureSizeMax,

TIP

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

示例代码:

[conference requestVideo:@"userId" pictureSize:JCConferencePictureSizeSmall];

# 视频渲染

  • 本地视频渲染

您可以调用 JCMediaDevice (opens new window) 类中的 startCameraVideo (opens new window) 方法进行本地视频画面的渲染,调用该方法会打开摄像头。

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

示例代码:

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

调用 JCMediaDevice (opens new window) 类中的 startVideo (opens new window) 方法进行远端视频画面的渲染。

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

示例代码:

// 创建远端视频画面
JCMediaDeviceVideoCanvas *remote = [mediaDevice startVideo:renderId renderType:JCMediaDeviceRenderFullContent];
remote.videoView.frame = CGRectMake(100, 0, 100, 100);
[self.view addSubview:remote.videoView];

# 停止视频

如果想停止视频,可以调用下面的方法,该方法会关闭摄像头。

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

# 开启关闭发送本地音频流

sendlocaldata.png

加入会议后,可以调用下面的接口开启或者关闭发送本地音频流。

/**
 *  @brief              开启关闭发送本地音频流,会议中的成员会收到 onConferenceParticipantUpdate 回调。
 *                      当前的状态@see JCConferenceInfo 对象属性 uploadAudio
 *
 *  @param enable       是否开启本地音频流
 *  @return             返回 true 表示正常执行调用流程,false 表示调用异常
 */
- (bool)enableUploadAudioStream:(bool)enable;

示例代码:

[conference enableUploadAudioStream:true];

该方法调用后,会议中的成员会收到 onConferenceParticipantUpdate (opens new window) 回调。

/**
 *  @brief                  成员更新回调
 *  @param participant      成员对象
 *  @param changedParam     变化标识集合
 */
- (void)onConferenceParticipantUpdate:(JCConferenceParticipant *)participant changedParam:(JCConferenceParticipantChangedParam *)changedParam;

# 开启关闭发送本地视频流

如果想开启或者关闭发送本地视频流,可以调用下面的方法,该方法调用成功后,会议中的成员会收到 onConferenceParticipantUpdate (opens new window) 回调。

/**
 *  @brief              开启关闭发送本地视频流,会议中的成员会收到 onConferenceParticipantUpdate 回调。
 *                      当前的状态@see JCConferenceInfo 对象属性 uploadVideo
 *  @param enable       是否开启本地视频流
 *  @return             返回 true 表示正常执行调用流程,false 表示调用异常
 */
- (bool)enableUploadVideoStream:(bool)enable;

示例代码:

[conference enableUploadVideoStream:true];

# 开启关闭订阅会议音频流

subscriberemote.png

还可以调用下面的方法开启或者关闭会议音频流订阅。

/**
 *  @brief 是否订阅会议音频流,关闭订阅将无法听到会议中其他成员的声音
 *         当前的状态@see JCConferenceInfo 对象属性 audioOutput
 *  @param enable 是否订阅
 *  @return 返回 true 表示正常执行调用流程,false 表示调用异常
 */
- (bool)enableAudioOutput:(bool)enable;

示例代码:

[conference enableAudioOutput:true];

# 查询会议

queryconf.png

加入会议之前,可以调用下面的方法查询进行中的会议。

/**
 * @brief                 查询进行中的会议,结果回调 onQueryGoingConfResult
 *
 * @param confNumber      会议号
 * @return                返回操作id
 */
- (int)queryGoingConf:(NSString *)confNumber;

示例代码:

[conference queryGoingConf:@"confNumber"];

调用该接口后会收到 onQueryGoingConfResult (opens new window) 回调,该方法返回操作 id、查询会议的结果、查询结果的原因、会议对象和会议中的成员。

/**
 * @brief                   查询进行中的会议结果
 *
 * @param operationId       操作id
 * @param succ              true 表示成功,false 表示失败
 * @param reason            原因
 * @param confInfo          会议对象
 * @param participants      会议中的成员
 */
- (void)onQueryGoingConfResult:(int)operationId succ:(bool)succ reason:(int)reason confInfo:(JCConferenceInfo *)confInfo participants:(NSArray<JCConferenceParticipant *> *)participants;

示例代码:

- (void)onQueryGoingConfResult:(int)operationId succ:(bool)succ reason:(int)reason confInfo:(JCConferenceInfo *)confInfo participants:(NSArray<JCConferenceParticipant *> *)participants
{
    if (succ) {
        // 查询成功
        NSString *title = confInfo.title;
        NSString *creator = confInfo.creator;
        ...
    }
}

# 发送消息

/**
 * @brief 发送消息,其他成员会收到回调 onMessageReceive
 *
 * @param type 消息类型
 * @param content 消息内容,当 toUserId 不为 nil 时,content 不能大于 4k
 * @param toUserId 接收者id,null则发给所有会议人员
 * @return true 表示成功,false表示失败
 */
- (bool)sendMessage:(NSString *)type content:(NSString *)content toUserId:(NSString *)toUserId;

其他成员会收到 onMessageReceive (opens new window) 回调:

/**
 * @brief 收到其他成员发送的消息
 *
 * @param type 消息类型
 * @param content 消息内容
 * @param fromUserId 接收消息UserId
 */
- (void)onMessageReceive:(NSString *)type content:(NSString *)content fromUserId:(NSString *)fromUserId;