# 实现视频会议

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

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

  • Android SDK 下载

  • Android SDK 配置和初始化

  • Android 登录

    TIP

    您在 AndroidManifest 中进行权限配置时,请确保您能够获得打开摄像头、音视频录制等相关权限

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

# 模块初始化

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

// 初始化各模块,因为这些模块实例将被频繁使用,建议声明在单例中
JCClient client = JCClient.create(Context, "your appkey", this, null);
JCMediaDevice mediaDevice = JCMediaDevice.create(client, this);
JCConference conference = JCConference.create(client, mediaDevice, this);

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

/**
 * 创建JCConference对象
 *
 * @param client      JCClient 对象
 * @param mediaDevice JCMediaDevice 对象
 * @param callback    实现 JCConferenceCallback 接口的对象,用于接收 JCConference 相关通知
 * @return JCConference对象
 */
public static JCConference create(JCClient client, JCMediaDevice mediaDevice, JCConferenceCallback callback)

会控模块涉及以下类:

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

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

# 基础业务接口调用

fullsizeoutput_1.jpeg

# 创建会议

/**
 * 创建并加入一个会议,结果回调 onConferenceJoin
 *
 * @param confNumber 传 "0" 由服务器生成10位的会议号,可传数字作为自定义会议号
 * @param video      true 视频会议,false 语音会议
 * @param config     会议的其他配置,具体查看JCConference JoinParam的配置参数
 * @return true 表示接口调用成功
 */
public abstract boolean start(String confNumber, boolean video, Map<String, String> 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

示例代码:

JSONObject object = new JSONObject();
object.put(CONFIG_CAPACITY,"6");
object.put(CONFIG_TITLE,"会议title");
conference.start("12345",true,object);

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

/**
 * 加入会议结果回调
 *
 * @param result    true 表示成功,false 表示失败
 * @param reason    当 result 为 false 时该值有效: 2为加入超时;5为已有会议加入;10为成员满;11无效密码;12   会议被锁定;100为其他错误;
 */
void onConferenceJoin(boolean result, @JCConference.JCConferenceReason int reason);

其中,加入失败的原因 JCConferenceReason 有:

/**
 * 无异常
 */
public static final int REASON_NONE = 0;
/**
 * 未登录
 */
public static final int REASON_NOT_LOGIN = 1;
/**
 * 超时
 */
public static final int REASON_TIMEOUT = 2;
/**
 * 网络异常
 */
public static final int REASON_NETWORK = 3;
/**
 * 被踢
 */
public static final int REASON_KICKED = 6;
/**
 * 掉线
 */
public static final int REASON_OFFLINE = 7;
/**
 * 主动离开
 */
public static final int REASON_QUIT = 8;
/**
 * 会议关闭
 */
public static final int REASON_OVER = 9;
/**
 * 成员满
 */
public static final int REASON_FULL = 10;
/**
 * 无效密码
 */
public static final int REASON_INVALID_PASSWORD = 11;
/**
 * 会议被锁定
 */
public static final int REASON_LOCK = 12;

/**
 * 群组已有会议
 */
public static final int REASON_GROUP_CONF_EXIST = 13;

/**
 * 群组没有会议
 */
public static final int REASON_NO_CONF_IN_GROUP = 14;

/**
 * 该会议号的会议不存在
 */
public static final int REASON_CONF_NUMBER_NOT_FOUND = 15;

/**
 * 会议号已存在
 */
public static final int REASON_CONF_NUMBER_EXIST = 16;

/**
 * 服务器会议成员总数上限(移动端会议人数)
 */
public static final int REASON_CONF_APP_CONCURRENCY_FUL = 17;

/**
 * 服务器会议成员总数上限(总会议人数)
 */
public static final int REASON_CONF_ALL_CONCURRENCY_FUL = 18;

/**
 * 该会议已经结束(已经结束的预约会议不能重新通过join接口加入)
 */
public static final int REASON_CONF_ALREADY_ENDED = 19;

/**
 * 其他错误
 */
public static final int REASON_OTHER = 100;

示例代码:

public void onConferenceJoin(boolean result, @JCConference.JCConferenceReason int reason)
{
    if (result) {
    // 加入成功的处理
    } else {
    // 加入失败的处理
    }
}

# 加入已经存在的会议

joinconf.png

如果要加入已经存在的会议,则调用下面的接口,调用该接口会收到 onConferenceJoin (opens new window) 回调。

/**
 * 加入会议,结果回调 onConferenceJoin
 *
 * @param confNumber 会议号
 * @param video      接口暂时没用该参数
 * @param config     具体查看JCConference JoinParam的配置参数
 * @return true 表示接口调用成功
 */
public abstract boolean join(String confNumber, boolean video, Map<String, String> config);

示例代码:

conference.join("12345",true, null);

其他成员加入会收到 onConferenceParticipantJoin (opens new window) 回调接口。

/**
* 成员加入回调
*
* @param participant 成员对象
* @see JCConferenceParticipant
*/
void onConferenceParticipantJoin(JCConferenceParticipant participant);

# 本地视频渲染

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

/**
* 获得视频预览对象,通过此对象能获得视图用于UI显示
*
* @param renderType    渲染模式
* @return              JCMediaDeviceVideoCanvas 对象
* @see RenderType
*/
public abstract JCMediaDeviceVideoCanvas startCameraVideo(@RenderType int renderType);

示例代码:

// 创建本地视频画面
JCMediaDeviceVideoCanvas localCanvas = mediaDevice.startCameraVideo(JCMediaDevice.RENDER_FULL_CONTENT);
viewGroup.addView(localCanvas.getVideoView(), 0);

# 请求用户视频流

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

/**
 * 请求用户的视频流
 * 当 pictureSize 为 PictureSizeNone 标识关闭请求
 *
 * @param userId      用户对象userId
 * @param pictureSize 视频请求尺寸类型
 * @return 返回 true 表示正常执行调用流程,false 表示调用异常
 * @see JCConferencePictureSize
 */
public abstract boolean requestVideo(String userId, @JCConferencePictureSize int pictureSize);

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

/**
 * 不请求
 */
public static final int PICTURESIZE_NONE = 0;
/**
 * 最小尺寸
 */
public static final int PICTURESIZE_MIN = 1;
/**
 * 小尺寸
 */
public static final int PICTURESIZE_SMALL = 2;
/**
 * 大尺寸
 */
public static final int PICTURESIZE_LARGE = 3;
/**
 * 最大尺寸
 */
public static final int PICTURESIZE_MAX = 4;

TIP

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

示例代码:

conference.requestVideo("userId", PICTURESIZE_LARGE);

# 远端视频渲染

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

TIP

需要调用请求用户视频流接口后再调用远端视频渲染接口。

/**
 * 获得视频对象,通过此对象能获得视图用于UI显示
 *
 * @param videoSource   渲染标识串,比如 JCMediaChannelParticipant JCCallItem 中的 renderId
 * @param renderType    渲染模式
 * @return              JCMediaDeviceVideoCanvas 对象
 * @see RenderType
 */
public abstract JCMediaDeviceVideoCanvas startVideo(String videoSource, @RenderType int renderType);

示例代码:

// 创建远端视频画面
JCMediaDeviceVideoCanvas remoteCanvas = mediaDevice.startVideo(renderId, JCMediaDevice.RENDER_FULL_CONTENT);
viewGroup.addView(remoteCanvas.getVideoView(), 0);

# 停止视频

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

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

# 离开会议

leaveconf.png

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

/**
 * 离开会议,结果回调 onConferenceLeave
 *
 * @return true 表示接口调用成功
 */
public abstract boolean leave();

示例代码

conference.leave();

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

/**
 * 离开会议结果回调
 *
 * @param reason    离开原因 6被踢;7掉线;8主动离开;100为其他错误;
 */
void onConferenceLeave(@JCConference.JCConferenceReason int reason);

# 结束会议

stopconf.png

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

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

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

示例代码:

conference.stop();

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

sendlocaldata.png

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

/**
 * 开启关闭发送本地音频流,会议中的成员会收到 onConferenceParticipantUpdate 回调
 * 当前的状态@see JCConferenceInfo 对象的接口 getUploadAudio()
 *
 * @param enable 是否开启本地音频流
 * @return 返回 true 表示正常执行调用流程,false 表示调用异常
 */
public abstract boolean enableUploadAudioStream(boolean enable);

示例代码:

conference.enableUploadAudioStream(true);

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

/**
 * 成员更新回调
 *
 * @param participant 成员对象
 * @param changedParam 变化标识集合
 * @see JCConferenceParticipant
 */
void onConferenceParticipantUpdate(JCConferenceParticipant participant, JCConferenceParticipant.ChangedParam changedParam);

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

subscriberemote.png

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

/**
 * 开启关闭发送本地视频流,会议中的成员会收到 onConferenceParticipantUpdate 回调
 * 当前的状态@see JCConferenceInfo 对象的接口 getUploadVideo()
 *
 * @param enable 是否开启本地视频流
 * @return 返回 true 表示正常执行调用流程,false 表示调用异常
 */
public abstract boolean enableUploadVideoStream(boolean enable);

示例代码:

conference.enableUploadVideoStream(true);

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

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

/**
 * 是否订阅会议音频流,关闭订阅将无法听到会议中其他成员的声音
 * 当前的状态@see JCConferenceInfo 对象的接口 getAudioOutput()
 *
 * @param enable 是否开启音频输出
 * @return 返回 true 表示正常执行调用流程,false 表示调用异常
 */
public abstract boolean enableAudioOutput(boolean enable);

示例代码:

conference.enableAudioOutput(true);

# 查询会议

queryconf.png

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

/**
 * 查询进行中的会议,结果回调 onQueryGoingConfResult
 *
 * @param confNumber 会议号或者
 * @return 返回操作Id,返回-1表示接口调用失败
 */
public abstract int queryGoingConf(String confNumber);

示例代码:

conference.queryGoingConf("confNumber");

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

/**
 * 查询进行中的会议结果
 *
 * @param operationId 操作id
 * @param result true表示成功,false表示失败
 * @param reason 原因
 * @param confInfo 会议对象
 * @param memberList 会议中的成员
 * @see JCConferenceInfo
 */
void onQueryGoingConfResult(int operationId, boolean result, int reason, JCConferenceInfo confInfo, List<JCConferenceParticipant> memberList);

示例代码:

public void onQueryGoingConfResult(int operationId, boolean result, int reason, JCConferenceInfo confInfo, List<JCConferenceParticipant> memberList) {
    if (result) {
        // 查询成功
        String title = confInfo.title;
        String creator = confInfo.creator;
        ...
    }
}

# 发送消息

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

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

/**
 * 接收会议消息的回调
 *
 * @param type 消息类型
 * @param content 消息内容
 * @param fromUserId 消息发送者的userId
 */
void onMessageReceive(String type, String content, String fromUserId);

# 获取会议持续时长

/**
* 获取当前会议已经持续时间,单位毫秒(加入成功后获取有效)
*/
public long getConfDuration()

示例代码:

conference.getConferenceInfo.getConfDuration();