菊风云平台
菊风云平台视频互动直播快速开始

快速开始

参考接入教程,快速了解开发流程

1. 前提条件

Microsoft Visual Studio 2013 或以上版本

支持 Windows 7 或以上版本的 Windows 设备

有效的菊风开发者账号 免费注册

2. 准备工作

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

2.1 SDK 下载

点击 Windows SDK 进行下载。

2.2 AppKey 获取

AppKey 是应用在 菊风云平台 中的唯一标识。需要在 SDK 初始化的时候使用,AppKey 获取请参考 创建应用

2.3 SDK 配置

准备工作:

下载 Visual Studio 2013,请参考: Visual Studio Downloads

安装 Directx End-User Runtime Web,请参考: DirectX End-User Runtime Web

菊风云平台 SDK Windows 版本(以下简称 SDK)支持 .net Framework 4.5及以上。

解压 SDK:

下载 Windows 版 SDK 并解压,解压后可以看到 bin 目录包含以下文件:

2.3.1 导入 Windows SDK

打开visual studio,新建WPF应用程序。

点击“项目 > 添加引用”,将 bin 目录中的 JCSDK.dll,mtc.dll,mtcmanaged.dll,mtcwrap.dll,Newtonsoft.Json.dll,zmf.dll 和 zmfmanaged.dll 七个文件添加到您的工程目录中

在 Reference Manager 窗口中,可以看到添之后的文件,如下图:

设置应用输出路径与库所在文件夹一致

导入完成后编译运行,如果没有报错,恭喜您,您已经成功配置 SDK,可以进行 SDK 初始化了。

2.4 SDK 初始化

在实现初始化的文件中实现 JCClientCallback 回调,用于接收 JCClient 相关通知。

在初始化的时候还可以设置 SDK 信息存储目录,日志路径以及日志打印的等级,具体通过 CreateParam 对象设置,如果不设置则使用默认值。

CreateParam 对象有以下属性

/// <summary>
/// SDK 相关信息存放目录,包括账号信息,日志信息等
/// </summary>
public String sdkInfoDir;
/// <summary>
/// SDK 日志目录
/// </summary>
public String sdkLogDir;
/// <summary>
/// SDK 日志打印等级
/// </summary>
public JCLogLevel sdkLogLevel;

调用下面的接口初始化 SDK

appKey 为准备工作中“获取 AppKey”步骤中取得的 AppKey。如果还未获取 AppKey,请参考 创建应用 来获取。

示例代码

public bool initialize(Application app)
{
    // 初始化各模块,因为这些模块实例将被频繁使用,建议声明在单例中
     JCClient.CreateParam createParam = new JCClient.CreateParam();
     createParam.sdkInfoDir = "SDK 信息存放路径";
     createParam.sdkLogDir = "日志存放路径";
     createParam.sdkLogLevel = JCLogLevel.Info;
     JCClient client = JCClient.create(app, "your appkey", this, createParam);
     return true;
}

SDK 初始化之后,即可进行登录的集成。

3. 登录

登录涉及 JCClient 类及其回调 JCClientCallback,其主要作用是负责登录、登出管理及帐号信息存储。

登录之前,可以通过 loginParam 登录参数进行登录的相关配置,如服务器地址的设置或者使用代理服务器登录,如不设置则按照默认值登录,具体如下:

登录之前,可以通过配置关键字进行登录的相关配置,如是否使用代理服务器登录以及服务器地址的设置,具体如下:

/// <summary>
/// 登录服务器地址
/// </summary>
public String serverAddress = "http:cn.router.justalkcloud.com:8080";
/// <summary>
/// https代理地址,例如 192.168.1.100:3128
/// </summary>
public String httpsProxy;
/// <summary>
/// 设备id,一般模拟器使用,因为模拟器可能获得的设备id都一样
/// </summary>
public String deviceId;
/// <summary>
/// 登录账号不存在的情况下是否内部自动创建该账号,默认为 true
/// </summary>
public bool autoCreateAccount = true;

其中,服务器地址包括国际环境服务器地址和国内环境服务器地址:

国际环境 服务器地址为 http:intl.router.justalkcloud.com:8080
国内环境 服务器地址为 http:cn.router.justalkcloud.com:8080

开发者可以使用自定义服务器地址。

示例代码

JCClient.LoginParam loginParam = new JCClient.LoginParam();
loginParam.serverAddress = "服务器地址";

还可以通过 displayName 属性设置昵称,例如:

client.displayName = "小张";

3.1 发起登录

调用下面的接口发起登录,userId 为英文、数字和’+’ ‘-‘ ‘_’ ‘.’,大小写不敏感,长度不要超过64字符,’-‘ ‘_’ ‘.’不能作为第一个字符

/// <summary>
/// 登陆 Juphoon Cloud 平台,只有登陆成功后才能进行平台上的各种业务
/// 登陆结果通过 JCCallCallback 通知
/// </summary>
/// <param name="username">用户标识</param>
/// <param name="password">密码,不能为空</param>
/// <param name="loginParam">登入参数</param>
/// <returns>true 表示正常执行调用流程,false 表示调用异常</returns>
/// <remarks>注意:用户名为英文数字和'+' '-' '_' '.',长度不要超过64字符, '-' '_' '.'不能作为首字符</remarks>
/// <remarks>当用户不存在时会自动创建该用户</remarks>
public bool login(string username, string password, LoginParam loginParam)

示例代码

JCClient.LoginParam loginParam = new JCClient.LoginParam();
loginParam.serverAddress = "服务器地址";
client.login("账号", "密码", loginParam);

登录成功之后,首先会触发登录状态改变(onClientStateChange)回调

/// <summary>
/// 登陆状态变化通知
/// </summary>
/// <param name="state">当前状态值</param>
/// <param name="oldState">之前状态值</param>
void onClientStateChange(JCClientState state, JCClientState oldState);

JCClientState 有:

// 未初始化
NotInit,
// 未登录
Idle,
// 登录中
Logining,
// 登录成功
Logined,
// 登出中
Logouting,

示例代码

public void onClientStateChange(JCClientState state, JCClientState oldState)
    {
        if (state == JCClientState.Idle) { // 未登录
           ...
        }
        else if (state == JCClientState.Logining) { // 登录中
           ...
        }
        else if (state == JCClientState.Logined) { // 登录成功
            ...
        }
        else if (state == JCClientState.Logouting) { // 登出中
            ...
        }
    }

之后通过 onLogin 回调上报登录结果

/// <summary>
/// 登陆结果回调
/// </summary>
/// <param name="result">true 表示登陆成功,false 表示登陆失败</param>
/// <param name="reason">当 result 为 false 时该值有效,了解具体原因</param>
void onLogin(bool result, JCClientReason reason);

其中,JCClientReason 有

/// <summary>
/// 正常
/// </summary>
None,
/// <summary>
/// sdk 未初始化
/// </summary>
SDKNotInit,
/// <summary>
/// 无效参数
/// </summary>
InvalidParam,
/// <summary>
/// 函数调用失败
/// </summary>
CallFucntionError,
/// <summary>
/// 当前状态无法再次登录
/// </summary>
StateCannotLogin,
/// <summary>
/// 超时
/// </summary>
TimeOut,
/// <summary>
/// 网络异常
/// </summary>
NetWork,
/// <summary>
/// appkey 错误
/// </summary>
AppKey,
/// <summary>
/// 账号密码错误
/// </summary>
Auth,
/// <summary>
/// 无该用户
/// </summary>
NoUser,
/// <summary>
/// 强制登出
/// </summary>
ServerLogout,
/// <summary>
/// 其他错误
/// </summary>
Other = 100,

登录成功之后,SDK 会自动保持与服务器的连接状态,直到用户主动调用登出接口,或者因为帐号在其他设备登录导致该设备登出。

3.2 登出

登出调用下面的接口,登出后不能进行平台上的各种业务操作

/// <summary>
/// 登出 Juphoon Cloud 平台
/// </summary>
/// <returns>返回 true 表示正常执行调用流程,false 表示调用异常,异常错误通过 JCClientCallback 通知</returns>
public bool logout();

登出同样会触发登录状态改变(onClientStateChange)回调

之后将通过 onlogout 回调上报登出结果

/// <summary>
/// 登出回调
/// </summary>
/// <param name="reason">登出原因</param>
void onLogout(JCClientReason reason);

完成以上步骤,就做好了基础工作,您可以开始集成业务了。

4. 业务集成

视频互动直播涉及以下类

名称 描述
JCMediaChannel 媒体频道模块,类似音视频房间的概念,可以通过频道号加入此频道,从而进行音视频通话
JCMediaChannelParticipant 媒体频道成员,主要用于成员基本信息以及状态等的管理
JCMediaChannelQueryInfo 媒体频道查询信息结果
JCMediaChannelCallback 媒体频道回调代理
JCMediaDevice 设备模块,主要用于视频、音频设备的管理
JCMediaDeviceVideoCanvas 视频对象,主要用于 UI 层视频显示、渲染的控制
JCMediaDeviceCallback 设备模块回调代理

更多接口的详细信息请参考 API 说明文档

开始集成视频互动直播功能前,请先实现 JCMediaDeviceCallback, JCMediaChannelCallback 回调,用于接收 JCMediaDevice 和 JCMediaChannel 的相关通知,之后进行模块的初始化。

创建 JCMediaDevice 实例

/// <summary>
/// 创建JCMediaDevice实例
/// </summary>
/// <param name="client">JCClient实例</param>
/// <param name="callback">JCMediaDeviceCallback回调函数,用于接收JCMediaDevice相关事件</param>
/// <returns>JCMediaDevice实例</returns>
public static JCMediaDevice create(JCClient.JCClient client, JCMediaDeviceCallback callback)

创建 JCMediaChannel 实例

/// <summary>
/// 创建JCMediaChannel对象
/// </summary>
/// <param name="client"> JCClient 对象</param>
/// <param name="mediaDevice">JCMediaDevice 对象</param>
/// <param name="callback">JCMediaChannelCallback 对象,用于接收JCMediaDevice通知</param>
/// <returns>JCMediaChannel对象</returns>
public static JCMediaChannel create(JCClient.JCClient client, JCMediaDevice.JCMediaDevice mediaDevice, JCMediaChannelCallback callback)

示例代码

// 初始化各模块,因为这些模块实例将被频繁使用,建议声明在单例中
JCMediaDevice mediaDevice = JCMediaDevice.create(client, this);
JCMediaChannel mediaChannel = JCMediaChannel.create(client, mediaDevice, this);

4.1 角色设置

加入频道前要先进行角色的设置。其中角色设置包括主播和观众。

角色值可以根据 JCMediaChannelCustomRole 枚举值进行自定义,JCMediaChannelCustomRole 有以下几种

/// <summary>
/// 无自定义角色
/// </summary>
CUSTOM_ROLE_NONE = 0,
/// <summary>
/// 自定义角色0
/// </summary>
CUSTOM_ROLE_0 = 1 << 12,
/// <summary>
/// 自定义角色1
/// </summary>
CUSTOM_ROLE_1 = 1 << 13,
/// <summary>
/// 自定义角色2
/// </summary>
CUSTOM_ROLE_2 = 1 << 14,
/// <summary>
/// 自定义角色3
/// </summary>
CUSTOM_ROLE_3 = 1 << 15

例如:

//自定义主播角色
JCMediaChannelCustomRole ROLE_BROASCASTER = JCMediaChannelConstants.CUSTOM_ROLE_0;
//自定义观众角色
JCMediaChannelCustomRole ROLE_AUDIENCE = JCMediaChannelConstants.CUSTOM_ROLE_1;

角色定义之后,调用下面的接口设置角色

/// <summary>
/// 设置自定义角色
/// </summary>
/// <param name="customRole">自定角色</param>
/// <param name="participant">成员,null 则默认设置自己</param>
public void setCustomRole(JCMediaChannelCustomRole customRole, JCMediaChannelParticipant participant)

4.1.1 发送本地音频流

如果角色为主播,则需要在加入会议前打开音频,上传本地音频流。如果为观众,则不需要。

在加入频道时,SDK 会 自动打开音频设备,因此可以在加入频道之前直接调用 enableUploadAudioStream 方法打开或关闭“上传音频”的标识,这样加入频道后其他成员就可以听到您的声音

/// <summary>
/// 开启关闭发送本地音频流
/// 1.在频道中将会与服务器进行交互,服务器会更新状态并同步给其他用户
/// 2.未在频道中则标记是否上传音频流,在Join时生效
/// 2.建议每次Join前设置
/// </summary>
/// <param name="enable">开启关闭本地音频流</param>
/// <returns>返回true表示调用成功,false表示调用失败</returns>
public bool enableUploadAudioStream(bool enable)
该接口可以在加入频道之前调用,也可以在加入频道之后调用。两者区别具体如下:

如果在加入频道前调用,只是打开或关闭“上传音频”的标识,但不会发送数据,当加入频道成功时会根据 enableUploadAudioStream 设定的值来确定是否上传音频数据。同时,频道中的其他成员会收到该成员“是否上传音频“的状态变化回调(onParticipantUpdate)。

如果在加入频道后调用,则会开启或者关闭发送本地音频流数据,服务器也会根据 enableUploadAudioStream 设定的值来确定是否上传音频数据。同时,频道中的其他成员会收到该成员“是否上传音频“的状态变化回调(onParticipantUpdate)。

此外,此方法还可以实现开启或关闭静音的功能。当 enable 值为 false ,将会停止发送本地音频流,此时其他成员将听不到您的声音,从而实现静音功能。

4.1.2 发送本地视频流

如果角色为主播,则需要在加入会议前打开视频设备,上传本地视频流。如果为观众,则不需要。

发送本地视频流(enableUploadVideoStream)接口如下

/// <summary>
/// 开启关闭发送本地视频流
/// 1.在频道中将会与服务器进行交互,服务器会更新状态并同步给其他用户
/// 2.未在频道中则标记是否上传视频流,在Join时生效
/// 2.建议每次Join前设置
/// </summary>
/// <param name="enable">开启关闭本地视频流</param>
/// <returns>返回true表示调用成功,false表示调用失败</returns>
public bool enableUploadVideoStream(bool enable)
该接口可以在加入频道之前调用,也可以在加入频道之后调用。两者区别具体如下:

如果在加入频道前调用,只是打开或关闭“上传视频流”的标识,但不发送数据,当加入频道后会根据 enableUploadVideoStream 设定的值来确定是否上传视频流数据。同时,频道中的其他成员会收到该成员”是否上传视频“的状态变化回调(onParticipantUpdate)。如果设定的值为 false,则在加入频道后自动开启语音通话模式。

如果在加入频道后调用,则会开启或关闭发送本地视频流数据。服务器会根据 enableUploadVideoStream 设定的值来确定是否上传视频流数据。同时,频道中的其他成员会收到该成员”是否上传视频“的状态变化回调(onParticipantUpdate),从而进行语音通话和视频通话的切换。

此外,调用该方法发送本地视频流数据还要依赖摄像头是否已经打开。

4.1.3 加入频道

调用下面的接口加入频道

/// <summary>
/// 加入频道
/// 当 params 中不设置 JOIN_PARAM_REGION 参数,则默认为中国区域,如果业务主要集中在国外则选择 REGION_OTHER
/// <code>
///joinparams.Add(JCMediaChannelConstants.JOIN_PARAM_CDN, "推流地址");
///joinparams.Add(JCMediaChannelConstants.JOIN_PARAM_RECORD, "{"MtcConfIsVideoKey": true,
///              "Storage": {
///              "Protocol": "qiniu",
///              "BucketName": "用户填入",
///              "SecretKey": "用户填入",
///              "AccessKey": "用户填入",
///              "FileKey": "**.mp4"
///              }
///            }"
///          );
///joinparams.Add(JCMediaChannelConstants.JOIN_PARAM_REGION, JCMediaChannelRegion.REGION_CHINA.ToString());
///JCManager.shared().MediaChannel.join(confid, joinparams);
/// </code>
/// </summary>
/// <param name="channelIdOrUri">频道标识或频道Uri</param>
/// <param name="joinParam">加入会议参数</param>
/// <returns>返回true表示调用成功,false表示调用失败</returns>
public bool join(string channelIdOrUri, JoinParam joinParam)
加入频道会自动打开音频设备。

加入频道之前可以通过 JoinParam(加入参数,第一个加入者有效)设置频道属性,如频道允许加入的最大人数,推流参数、录制参数等。具体如下:

/// <summary>
/// 会议最大人数
/// </summary>
public int capacity = 16;
/// <summary>
/// 推流参数
/// </summary>
public String cdn = null;
/// <summary>
/// 录制参数
/// </summary>
public RecordParam record = null;
/// <summary>
/// 密码
/// </summary>
public String password = "123456";
/// <summary>
/// 平滑模式
/// </summary>
public bool smooth = true;
/// <summary>
/// 会议最大分辨率
/// </summary>
public JCMediaChannelMaxResolution maxResolution = JCMediaChannelMaxResolution.MaxResolution360P;
/// <summary>
/// uri 模式, join 函数的参数为会议 uri
/// </summary>
public bool uriMode = false;
/// <summary>
/// 心跳间隔
/// </summary>
public int heartbeatTime = 20;
/// <summary>
/// 心跳超时
/// </summary>
public int heartbeatTimeout = 60;
/// <summary>
/// 帧率 1-30, 默认 24
/// </summary>
public int framerate = 24;
///// <summary>
///// 最大码率
///// </summary>
//public int maxBitrate = 2000;
/// <summary>
/// 自定义属性
/// </summary>
public String customProperty = "";

示例代码

//自定义主播角色
JCMediaChannelCustomRole ROLE_BROASCASTER = CUSTOM_ROLE_0;
//自定义观众角色
JCMediaChannelCustomRole ROLE_AUDIENCE = CUSTOM_ROLE_1;
//设置自己的角色
mediaChannel.setCustomRole(ROLE_BROASCASTER, null);
public void joinRoom(JCMediaChannelCustomRole customRole) {
    //主播可以上传本地音视频流
    mediaChannel.enableUploadVideoStream(customRole == ROLE_BROASCASTER);
    mediaChannel.enableUploadAudioStream(customRole == ROLE_BROASCASTER);
    mediaChannel.enableAudioOutput(true);
    // 设置频道参数
    JCMediaChannel.JoinParam joinParam = new JCMediaChannel.JoinParam();
    joinParam.password = "会议密码";
    joinParam.smooth = true;
    //加入直播
    mediaChannel.join("channelId", joinParam);
}

加入频道接口调用后,首先会触发 onMediaChannelStateChange 回调,该回调返回自身当前的状态

/// <summary>
/// 自身状态变化回调
/// </summary>
/// <param name="state">当前状态</param>
/// <param name="oldState">变化前状态值</param>
void onMediaChannelStateChange(JCMediaChannelState state, JCMediaChannelState oldState);

JCMediaChannelState 有以下值

/// <summary>
/// 空闲
/// </summary>
Idle,
/// <summary>
/// 加入中
/// </summary>
Joining,
/// <summary>
/// 已加入
/// </summary>
Joined,
/// <summary>
/// 离开中
/// </summary>
Leaving

加入频道的结果通过 onJoin 回调

/// <summary>
/// 加入频道结果回调
/// </summary>
/// <param name="result">true表示加入成功,false表示加入失败</param>
/// <param name="reason">加入失败原因,在result为false时该值有效</param>
/// <param name="channelId">媒体频道标识</param>
void onJoin(bool result, JCMediaChannelReason reason, string channelId);

示例代码

// 加入频道结果回调
public void onJoin(bool result, JCMediaChannelReason reason, string channelId)
{
    if (result)
    {
        // 加入频道成功
    } else {
        // 加入频道失败
    }
}

4.1.4 本地视频画面渲染

主播加入频道后,需要打开摄像头以创建本地视频画面。

创建视频画面需要用到 JCMediaDevice 类和 JCMediaDeviceVideoCanvas 类。

进行视频渲染前可通过 获取摄像头列表 接口获取摄像头列表。

本地视频渲染调用 JCMediaDevice 类中的 startCameraVideo 接口,该接口会打开摄像头

/// <summary>
/// 获取预览视频对象,通过此对象能获得视图用于UI显示
/// </summary>
/// <param name="mode">渲染方式</param>
/// <returns>JCMediaDeviceVideoCanvas对象</returns>
public JCMediaDeviceVideoCanvas startCameraVideo(JCMediaDeviceRenderMode mode)

其中,JCMediaDeviceRenderMode(渲染模式)有以下几种:

/// <summary>
/// 铺满窗口
/// </summary>
FULLSCREEN,
/// <summary>
/// 全图像显示,会有黑边
/// </summary>
FULLCONTENT,
/// <summary>
/// 自适应
/// </summary>
FULLAUTO
调用该方法后,在挂断通话或者关闭摄像头时需要对应调用 stopVideo 方法停止视频。

如果想自定义摄像头采集参数,如采集的高度、宽度和帧速率以及旋转角度等,请参考 视频采集和渲染

示例代码

// 创建本地视频画面
JCMediaDeviceVideoCanvas loacalCanvas = mediaDevice.startCameraVideo(JCMediaDeviceRenderMode.FULLCONTENT);
ImageBrush image = new ImageBrush(loacalCanvas.videoView);
image.Stretch = Stretch.Uniform;
this.smVideoGrid.Background = image;

现在您可以开始视频直播了。

直播中如果有新成员加入,会收到 onParticipantJoin 回调,此时可以进行界面更新

/// <summary>
/// 成员加入回调
/// </summary>
/// <param name="participant">成员对象</param>
void onParticipantJoin(JCMediaChannelParticipant participant);

4.1.5 远端视频画面渲染

当新加入的成员想要看到主播的画面时,需要进行远端视频渲染并请求主播的视频流。

远端视频渲染

远端视频渲染调用 startVideo 获取视频对象

/// <summary>
/// 获得视频对象,通过此对象能获得视图用于UI显示
/// </summary>
/// <param name="videoSource">渲染标识串,比如 JCMediaChannelParticipant JCCallItem 中的 renderId,当videoSource 为 videoFileId 时,内部会调用 startVideoFile</param>
/// <param name="mode">渲染模式</param>
/// <returns>JCMediaDeviceVideoCanvas对象</returns>
public JCMediaDeviceVideoCanvas startVideo(string videoSource, JCMediaDeviceRenderMode mode)

其中,JCMediaDeviceRenderMode(渲染模式)有以下几种:

/// <summary>
/// 铺满窗口
/// </summary>
FULLSCREEN,
/// <summary>
/// 全图像显示,会有黑边
/// </summary>
FULLCONTENT,
/// <summary>
/// 自适应
/// </summary>
FULLAUTO
调用该方法后,在挂断通话或者关闭摄像头时需要对应调用 stopVideo 方法停止视频。

请求远端成员视频流

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

/// <summary>
/// 请求频道中的其他用户视频流
/// 当pictureSize为None表示关闭请求
/// </summary>
/// <param name="participant">用户对象</param>
/// <param name="pictureSize">视频请求尺寸类型</param>
/// <returns>返回true表示调用成功,false表示调用失败</returns>
public bool requestVideo(JCMediaChannelParticipant participant, JCMediaChannelPictureSize pictureSize)

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

/// <summary>
/// 不渲染
/// </summary>
None,
/// <summary>
/// 最小尺寸
/// </summary>
 Min,
/// <summary>
/// 小尺寸
/// </summary>
Small,
/// <summary>
/// 大尺寸
/// </summary>
Large,
/// <summary>
/// 最大尺寸
/// </summary>
Max
您可以根据相应的窗口大小使用相应的视频尺寸,避免造成不必要的流量浪费和额外的功耗。比如窗口的大小是 160x90,则应该使用 JCMediaChannelPictureSizeMin。

示例代码

// 成员加入回调
public void onParticipantJoin(JCMediaChannelParticipant participant) {
    // 创建远端视频画面对象,renderId来源JCMediaChannelParticipant对象
    List<JCMediaChannelParticipant> partps = mediaChannel.getParticipants();
    JCMediaChannelParticipant item = partps.get(0);
    String renderId = item.renderId;
    JCMediaDeviceVideoCanvas remoteCanvas = mediaDevice.startVideo(renderId, JCMediaDevice.JCMediaDeviceRenderMode.FULLSCREEN);
    ImageBrush image = new ImageBrush(remoteCanvas.videoView);
    image.Stretch = Stretch.Uniform;
    this.label.Background = image;
    // 请求远端视频流,participant为JCMediaChannelParticipant对象
    mediaChannel.requestVideo(participant, JCMediaChannelPictureSize.Large);
}

4.2 离开频道

如果非主播成员想离开直播,可以调用下面的接口

/// <summary>
/// 离开频道,当前只支持同时加入一个频道
/// </summary>
/// <returns>返回true表示调用成功,false表示调用失败</returns>
public bool leave()

示例代码:

// 离开频道
mediaChannel.leave();

离开操作发起后,会触发自身状态变化回调

/// <summary>
/// 自身状态变化回调
/// </summary>
/// <param name="state">当前状态</param>
/// <param name="oldState">变化前状态值</param>
void onMediaChannelStateChange(JCMediaChannelState state, JCMediaChannelState oldState);

离开频道的结果及原因通过 onLeave 回调上报

/// <summary>
/// 离开频道结果标识
/// </summary>
/// <param name="reason">离开原因</param>
/// <param name="channelId">媒体频道标识</param>
void onLeave(JCMediaChannelReason reason, string channelId);

离开原因枚举值请参考 JCMediaChannelReason

离开频道后,自身在频道中的状态变为 Idle。

示例代码:

public void onLeave(JCMediaChannelReason reason, string channelId)
{
    // 界面处理
}

4.3 解散频道

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

/// <summary>
/// 结束频道,所有成员都将被退出
/// </summary>
/// <returns>返回true表示调用成功,false表示调用失败</returns>
public bool stop()

示例代码:

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

关闭频道的结果通过 onStop 回调

/// <summary>
 /// 解散频道结果回调
 /// </summary>
 /// <param name="result">true 表示成功,false 表示失败</param>
 /// <param name="reason">解散失败原因,当 result 为 false 时该值有效</param>
 void onStop(bool result, JCMediaChannelReason reason);

解散失败原因枚举值请参考 JCMediaChannelReason

示例代码:

public void onStop(bool result, JCMediaChannelReason reason)
{
    // 界面处理
}

4.3.1 媒体资源释放

在视频直播中,还需要在离开频道后调用 stopVideo 接口移除视频画面

/// <summary>
/// 停止视频
/// </summary>
/// <param name="canvas">JCMediaDeviceVideoCanvas对象,由startVideo获得</param>
public void stopVideo(JCMediaDeviceVideoCanvas canvas)

示例代码:

public void onLeave(JCMediaChannelReason reason, string channelId)
{
    // 停止视频
    // 销毁canvas
}