iOS

# 实现视频通话

本文档为您展示通过 SDK 实现多方视频通话的相关步骤,帮助您在多人视频通话场景下实现创建房间、邀请新成员加入、结束/离开房间的相关能力。

# 1. 前提条件

请确认您已完成以下操作:

  • 已获取 App Key。

AppKey 作为同个环境的分域依据,同一个域的终端才能实现互通,AppKey 由 Juphoon 视频平台提供。

TIP

请扫描下方二维码联系 Juphoon 市场售前工程师获取 AppKey。

image-20210315095937896
  • 集成 SDK(iOS)。

    TIP

    如需集成指导,请扫描上方二维码联系 Juphoon 市场售前工程师获取相关咨询。

# 2. 快速跑通 Sample

  1. 在 Juphoon RTC SDK 文档中心**,iOS 平台**下载体验 JCCSample 示例项目。

访问下载地址 (opens new window),示例如下:

img

  1. 下载完成后,安装 Juphoon_Rtc_Sample_for_iOS_xxxx_CallCenter 目录下的 JCCSample.ipa

img

  1. 打开应用程序后,设置正确的 appKey ,环境地址以及账号。

    1. 首先点击初始化按钮,成功后,登入按钮变为可点击;
    2. 确认账号输入无误之后,点击登入按钮,按钮字样变为登出,即登录成功;
    3. 点击右上角 进入 按钮,选择多方即可体验多方相关的功能。
    4. 进入多方页面后,输入房间号,如果有密码输入密码。点击加入,即可进入房间。

img img

img

# 3. 功能实现

@startuml

autonumber

actor "用户1" as User1
participant "JRTCSDK" as JRTCSDK
participant "Server" as Server
participant "JRTCSDK" as JRTCSDK1
actor "用户2" as User2

activate User1
activate User2
User1 -> JRTCSDK: 初始化JRTCSDK(JRCCClient,JRTCMediaDevice,JRTCRoom)
User1 -> JRTCSDK: 登录login
JRTCSDK -> Server: 登录
Server -> JRTCSDK: 登录结果
User2 -> JRTCSDK1: 初始化JRTCSDK(JRCCClient,JRTCMediaDevice,JRTCRoom)
User2 -> JRTCSDK1: 登录login
JRTCSDK1 -> Server: 登录
Server -> JRTCSDK1: 登录结果

group 登录成功
JRTCSDK -> User1: onLogin(true, reason)
JRTCSDK1 -> User2: onLogin(true, reason)
User1 -> JRTCSDK: 加入房间join("roomId", JRTCRoomJoinParam)
JRTCSDK -> User1: 房间状态改变onRoomStateChanged(STATE_JOINING, STATE_IDLE, JRTCRoom)
JRTCSDK -> Server: 加入房间
Server -> JRTCSDK: 加入房间结果
User2 -> JRTCSDK1: 加入房间join("roomId", JRTCRoomJoinParam)
JRTCSDK1 -> User2: 房间状态改变onRoomStateChanged(STATE_JOINING, STATE_IDLE, JRTCRoom)
JRTCSDK1 -> Server: 加入房间
Server -> JRTCSDK1: 加入房间结果
group 加入房间成功
JRTCSDK -> User1: 房间状态改变onRoomStateChanged(STATE_JOINED, STATE_JOINING, JRTCRoom)
JRTCSDK -> User1: 加入房间结果onJoin(true, reason, "roomId", JRTCRoom)
JRTCSDK1 -> User2: 房间状态改变onRoomStateChanged(STATE_JOINED, STATE_JOINING, JRTCRoom)
JRTCSDK1 -> User2: 加入房间结果onJoin(true, reason, "roomId", JRTCRoom)
JRTCSDK -> User1: 成员加入房间onParticipantJoin(participant, JRTCRoom)
alt 业务操作
User1 <-> User2: 业务操作房间属性变化onRoomPropertyChanged(propChangeParam, JRTCRoom)
User1 <-> User2: onParticipantUpdate(participant, changeParam, JRTCRoom)
end
group 离开房间
User2 -> JRTCSDK1: 离开房间leave
JRTCSDK1 -> Server: 离开房间
Server -> JRTCSDK1: 离开房间结果
Server -> JRTCSDK: 成员离开房间
JRTCSDK -> User1: onParticipantLeft(participant, reason, JRTCRoom)
JRTCSDK1 -> User2: 离开房间onLeave(reason, roomId, JRTCRoom)
end
end
group 加入房间失败
JRTCSDK -> User1: 房间状态改变onRoomStateChanged(STATE_IDLE, STATE_JOINING, JRTCRoom)
JRTCSDK -> User1: 加入房间结果onJoin(false, reason, null, JRTCRoom)
JRTCSDK -> User1: 房间状态改变onRoomStateChanged(STATE_IDLE, STATE_JOINING, JRTCRoom)
end
end

group 登录失败
JRTCSDK -> User1: onLogin(false, reason)
JRTCSDK1 -> User2: onLogin(false, reason)
end
@enduml

# 初始化 SDK

注:我们所有的方法都建议在主线程调用,否则可能会出现异常无法正常使用,回调接口也都在主线程上报。 在使用业务接口前,需对 Juphoon SDK 进行初始化操作;

模块 描述
JRTCClient (opens new window) 登录模块 负责视频平台的登录登出,只有登录到视频平台才可以使用视频相关的业务
JRTCMediaDevice (opens new window) 媒体模块 负责本地的媒体设备操作,视频画面渲染等功能
JRTCRoom (opens new window) 多方通话模块 类似音视频房间的概念,可以通过房间号加入房间,从而进行音视频通话。

初始化参数详见 JRTCClientInitParam (opens new window)

示例代码:

@interface JCManager () <JRTCClientCallback, JRTCMediaDeviceCallback, JRTCRoomCallback>

- (void)initSDK {
	// 创建初始化参数
    JRTCClientInitParam *param = [[JRTCClientInitParam alloc] init];
    // 设置appkey
    param.appKey = @"AppKey"; 
    // 设置接入服务器地址
    param.server = @"Server"; 
    // 设置应用名
    param.appName = @"AppName";
    // 创建 client 对象
    _client = [JRTCClient create:self initParam:param];
    // 创建 mediaDevice 对象
    _mediaDevice = [JRTCMediaDevice create:_client callback:self];
    // 创建 room 对象
    _room = [JRTCRoom create:_client mediaDevice:_mediaDevice callback:self]; 
}

@end

然后根据需求实现 Callback 的接口即可。

# 登录

初始化之后,即可进行登录的集成。登录接口调用流程如下所示:

img

调用 login (opens new window) 接口登录到 Juphoon 视频平台

/**
 * 登录 Juphoon RTC 平台,只有登录成功后才能进行平台上的各种业务
 * 登录结果通过 {@link JRTCClientCallback.onLogin:reason: onLogin} 回调通知
 *
 * @param userId 用户ID
 * @param password 密码,不能为空
 * @return 接口调用结果
 * - true: 接口调用成功
 * - false: 接口调用异常
 * @warning 目前只支持免鉴权模式,服务器不校验账号密码,免鉴权模式下当账号不存在时会自动去创建该账号
 * @warning 用户名为英文数字和'+' '-' '_' '.',长度不要超过64字符,'-' '_' '.'不能作为第一个字符
 */
- (bool)login:(NSString* _Nonnull)userId password:(NSString* _Nonnull)password;

/**
 * 登录 Juphoon RTC 平台,只有登录成功后才能进行平台上的各种业务
 * 登录结果通过 {@link JRTCClientCallback.onLogin:reason: onLogin} 回调通知
 *
 * @param userId 用户ID
 * @param password 密码,不能为空
 * @param loginParam      登录参数,一般不需要设置,如需设置请询问客服,传 nil 则按默认值,详见 @ref JRTCClientLoginParam
 * @return 接口调用结果
 * - true: 接口调用成功
 * - false: 接口调用异常
 * @warning 目前只支持免鉴权模式,服务器不校验账号密码,免鉴权模式下当账号不存在时会自动去创建该账号
 * @warning 用户名为英文数字和'+' '-' '_' '.',长度不要超过64字符,'-' '_' '.'不能作为第一个字符
 */
- (bool)login:(NSString* _Nonnull)userId password:(NSString* _Nonnull)password loginParam:(JRTCClientLoginParam* _Nullable)loginParam;

/**
 * 重登录,该接口在如果有其他同类型终端登录着则会登录失败,一般用于记住了账号后重启自动登录逻辑
 * @param password 密码,不能为空
 * @return 接口调用结果
 * - true: 接口调用成功
 * - false: 接口调用异常
 */
- (bool)relogin:(NSString* _Nonnull)userId password:(NSString* _Nonnull)password;

JRTCClientLoginParam (opens new window) 参数介绍

terminalType 终端登录类型,支持多终端登录,默认所有终端相同会导致互踢
autoCreateAccount 是否自动创建账号(免鉴权使用),默认 true
deviceId 设备 ID
token token
tokenType token 校验类型
tokenExtraParam token 校验拓展参数,json 字符串,token 为空不生效
certificate S3 国密密钥
accountEntry 帐户分录, 如果支持国密 S3 则需要设置 certificate,否则不设置
logFilter 日志过滤标签(用于日志管理平台过滤终端日志使用)
accelerateKey 加速云 KEY
accelerateKeySecret 加速云 KEY 密钥

登录的结果将会通过 JRTCClientCallback (opens new window) 中的 onLogin (opens new window) 接口上报

/**
 * 登录结果回调
 * @param result true 表示登录成功,false 表示登录失败
 * @param reason 当 result 为 false 时该值有效
 */
- (void)onLogin:(bool)result reason:(ReasonCode)reason;

示例代码:

// 创建登录配置参数
JRTCClientLoginParam *param = [[JRTCClientLoginParam alloc] init];
// 登录
[_client login:@"2333" password:@"123456" loginParam:param];

// 登录结果回调
- (void)onLogin:(bool)result reason:(ReasonCode)reason {
 	if (result == true) {
     	// 登录成功   
    }
    else {
    	// 登录失败,具体原因查询 reason 错误码
    }
}

# 加入房间

通过 JRTCRoomJoinParam (opens new window) 可在加入房间前设置房间最大人数,房间密码,最大分辨率等。

/**
 * 加入房间
 *
 * 该方法让用户加入通话房间,在同一个房间内的用户可以互相通话。<br>
 * 如果用户已在房间中,必须退出当前房间,即处于空闲状态,才能进入其他房间,否则将直接返回 false,且不会收到回调通知。
 * @param roomId    房间号
 * @param joinParam     JRTCRoomJoinParam 对象,传 nil 则使用默认配置
 * @return 接口调用结果
 * - true: 接口调用成功,会收到 {@link JRTCRoomCallback.onJoin:reason:roomId:room: onJoin} 回调
 * - false: 接口调用异常
 */
- (bool)join:(NSString* __nonnull)roomId joinParam:(JRTCRoomJoinParam* __nullable)joinParam;

加入房间结果通过 onJoin (opens new window) 回调。

/**
 * 加入房间结果回调
 *
 * 调用 {@link JRTCRoom.join:joinParam: join} 接口成功后,会收到此回调。
 * @param result 加入房间是否成功
 * - true: 成功
 * - false: 失败
 * @param reason    加入失败原因,当 result 为 false 时该值有效。失败原因参见:@ref ReasonCode "错误码"
 * @param roomId     房间标识
 * @param room     当前 JRTCRoom 对象
 */
- (void)onJoin:(bool)result reason:(ReasonCode)reason roomId:(NSString *)roomId room:(JRTCRoom *)room;

当加入房间后可通过 JRTCRoom.participants (opens new window) 获取已经在房间中的成员,然后渲染当前所有成员的视频画面。 示例代码:

// 创建入会配置参数
JRTCRoomJoinParam *param = [[JRTCRoomJoinParam alloc] init];
// 是否上传本地音频流
param.isUploadLocalAudio = true; 
// 是否上传本地视频流
param.isUploadLocalVideo = true; 
// 加入房间
[_room join:roomId joinParam:param];

// 加入结果回调
- (void)onJoin:(bool)result reason:(ReasonCode)reason roomId:(NSString *)roomId room:(JRTCRoom *)room {
    if (result) {
        // 加入房间成功
        // 获取当前房间中所有成员
        NSArray *participants = _room.participants;
    } 
    else {
        // 加入房间失败
    }
}

# 自身在房间中的状态变化

当自身在房间中的状态发生变化时,会收到 onRoomStateChanged (opens new window) 回调,例如加入房间、加入房间成功、离开回调等。 房间状态详见 RoomState (opens new window)

/**
 * 自身在房间中的状态变化回调
 *
 * 当自身在房间中的状态发生变化时,会收到此回调,例如加入房间、加入房间成功、离开回调等。
 *
 * 状态:
 * - @ref StateIdle : 空闲状态
 * - @ref StateJoining : 加入中
 * - @ref StateJoined : 已加入
 * - @ref StateLeaving : 离开中
 *
 * @param state    当前状态
 * @param oldState 变化前状态
 * @param room 当前 JRTCRoom 对象
 */
- (void)onRoomStateChanged:(RoomState)state oldState:(RoomState)oldState room:(JRTCRoom *)room;

示例代码:

- (void)onRoomStateChanged:(RoomState)state oldState:(RoomState)oldState room:(JRTCRoom *)room {
    if (state == StateIdle) {
        // 空闲状态
    } else if (state == StateJoining) {
     	// 加入中   
    } else if (state == StateJoined) {
     	// 已加入   
    } else if (state == StateLeaving) {
     	// 离开中   
    }
}

# 创建本地视频画面

初始化成功后,可以创建本地的视频画面,创建本地视频画面的时机没有具体要求,在加入房间前后调用皆可。

  1. 通过 startCameraVideo (opens new window) 方法,获取 JRTCMediaDeviceVideoCanvas (opens new window)本地的视频对象。
  2. 在界面画布上渲染本地视频对象画面。
/**
 * 开始本端视频渲染
 *
 * 获取本端视频预览对象 JRTCMediaDeviceVideoCanvas ,通过此对象能获得视图用于UI显示
 * @note
 * 调用此方法时需要保证默认摄像头不为空,即 @ref defaultCamera 不为空,否则将直接返回 nil
 * @param renderType 渲染模式:
 * - @ref JRTCMediaDeviceRenderFullScreen : 铺满窗口,会有裁剪
 * - @ref JRTCMediaDeviceRenderFullContent : 全图像显示,会有黑边
 * - @ref JRTCMediaDeviceRenderFullAuto : 自适应
 * @return
 * - JRTCMediaDeviceVideoCanvas 对象: 开始自身视频渲染成功
 * - nil: 开始自身视频渲染失败
 */
- (JRTCMediaDeviceVideoCanvas* __nullable)startCameraVideo:(JRTCMediaDeviceRender)renderType;

/**
 * 开始自身视频渲染
 *
 * 获取本端视频预览对象 JRTCMediaDeviceVideoCanvas ,通过此对象能获得视图用于UI显示
 * @note
 * 调用此方法时需要保证默认摄像头不为空,即 @ref defaultCamera 不为空,否则将直接返回 nil
 * @param type 渲染模式:
 * - @ref JRTCMediaDeviceRenderFullScreen : 铺满窗口,会有裁剪
 * - @ref JRTCMediaDeviceRenderFullContent : 全图像显示,会有黑边
 * - @ref JRTCMediaDeviceRenderFullAuto : 自适应
 * @param view 渲染视图控件
 * @return
 * - JRTCMediaDeviceVideoCanvas 对象: 开始自身视频渲染成功
 * - nil: 开始自身视频渲染失败
 */
- (JRTCMediaDeviceVideoCanvas* __nullable)startCameraVideo:(JRTCMediaDeviceRender)type view:(JCView* __nonnull)view;

JRTCMediaDeviceRender (opens new window) 决定了视频的渲染模式:

  • FullScreen 为填充模式:即将画面内容居中等比缩放以充满整个显示区域,超出显示区域的部分将会被裁剪掉,此模式下画面可能不完整;
  • FullContent 为适应模式:即按画面长边进行缩放以适应显示区域,短边部分会被填充为黑色,此模式下图像完整但可能留有黑边。

img

示例代码:

// 创建本端视图渲染对象
JRTCMediaDeviceVideoCanvas *canvas = [_mediaDevice startCameraVideo:JRTCMediaDeviceRenderFullContent];
// 设置视图位置与尺寸
canvas.videoView.frame = CGRectMake(0, 0, 100, 100);
// 将渲染视图添加到界面上
[self.view addSubview:canvas.videoView];

# 新成员加入

当新成员加入房间后,其他成员会收到 onParticipantJoin (opens new window) 成员加入的回调。

/**
 * 新成员加入回调
 *
 * 当有用户调用 {@link JRTCRoom.join:joinParam: join} 接口加入房间成功时,已在房间中的成员会收到此回调。
 * @param participant JRTCRoomParticipant 成员对象
 * @param room 当前 JRTCRoom 对象
 */
- (void)onParticipantJoin:(JRTCRoomParticipant*)participant room:(JRTCRoom *)room;

此时可以通过回调获取到成员对象进行远端视图渲染并订阅远端成员的视频流。

示例代码:

// 新成员加入房间
- (void)onParticipantJoin:(JRTCRoomParticipant*)participant room:(JRTCRoom *)room {
    // 订阅该成员视频流
    [_room requestVideo:participant videoSize:videoSize];
    // 渲染该成员视频画面
    JRTCMediaDeviceVideoCanvas *canvas = [_mediaDevice startVideo:participant.streamId renderType:JRTCMediaDeviceRenderFullContent]; 
    // 设置视图位置与尺寸
	canvas.videoView.frame = CGRectMake(100, 0, 100, 100);
    // 将渲染视图添加到界面上
    [self.view addSubview:canvas.videoView];
}

# 成员更新

当房间内成员状态发生改变时,其他成员能收到该成员状态变化通知 onParticipantUpdate (opens new window),具体成员变化属性参考 JRTCRoomParticipantChangeParam (opens new window),包含成员音量、网络状态、音视频上传状态、成员类型、视频订阅尺寸变化等。

/**
 * 成员属性更新回调
 *
 * 当房间中有成员的属性发生变化时,房间中的其他成员会收到此回调,例如音频上传状态、视频上传状态、网络状态等发生变化。
 * @param participant JRTCRoomParticipant 成员对象
 * @param changeParam JRTCRoomParticipantChangeParam 更新标识类对象
 * @param room 当前 JRTCRoom 对象
 */
- (void)onParticipantUpdate:(JRTCRoomParticipant*)participant changeParam:(JRTCRoomParticipantChangeParam *)changeParam room:(JRTCRoom *)room;

示例代码:

- (void)onParticipantUpdate:(JRTCRoomParticipant*)participant changeParam:(JRTCRoomParticipantChangeParam *)changeParam room:(JRTCRoom *)room {
 	if (changeParam.volume) {
        //成员音量大小变化
    } else if (changeParam.volumeStatus) {
        //成员音量状态变化
    } else if (changeParam.netStatus) {
        //成员网络状态变化
    } else if (changeParam.netStatus) {
        //成员网络状态变化
    } else if (changeParam.audio) {
        //成员音频上传状态变化
    } else if (changeParam.video) {
        //成员视频上传状态变化
    } else if (changeParam.videoSize) {
        //订阅该成员视频尺寸变化
    } else if (changeParam.type) {
        //该成员类型变化
    }
}

# 创建远端视频画面

当加入房间后,除了本地的视频画面,还有房间内其他成员的视频画面,如果房间内其他成员有视频流上传,本端可以获取到其他成员的的视频流并进行渲染,详细见 4.3.6 章节;

当成员视频状态变化,比如该成员开始上传视频,此时可以去渲染该成员视频,该成员结束上传视频,则可以去停止渲染该成员视频。

# 订阅/取消订阅视频

在渲染成员视频前,需要先通过调用 requestVideo (opens new window) 方法订阅该视频,当成员离开需要调用 unRequestVideo (opens new window) 及时取消订阅该视频流。

/**
 * 订阅房间中其他用户的视频流
 *
 * @param participant      JRTCRoomParticipant 成员对象
 * @param videoSize    视频请求的尺寸,详见 @ref JRTCVideoSize
 * @return 接口调用结果
 * - true: 接口调用成功,会收到 {@link JRTCRoomCallback.onParticipantUpdate:changeParam:room: onParticipantUpdate} 回调
 * - false: 接口调用异常
 */
- (bool)requestVideo:(JRTCRoomParticipant* __nonnull)participant videoSize:(JRTCVideoSize *__nonnull)videoSize;

/**
 * 取消订阅房间中其他用户的视频流
 *
 * @param participant      JRTCRoomParticipant 房间中其他成员对象
 * @return 调用是否正常
 * - true: 正常执行调用流程,会收到 {@link JRTCRoomCallback.onParticipantUpdate:participantChangeParam:room: onParticipantUpdate} 回调
 * - false: 调用失败,不会收到回调通知
 */
- (bool)unRequestVideo:(JRTCRoomParticipant* __nonnull)participant;

# 渲染/停止渲染视频

远端视频渲染可以通过调用 startVideo (opens new window) 来实现,停止渲染通过调用 stopVideo (opens new window) 来实现。

/**
 * 开始其他端的视频渲染
 *
 * 获取其他端的视频预览对象 JRTCMediaDeviceVideoCanvas ,通过此对象能获得视图用于UI显示
 *
 * @param streamId 视频流ID
 * @param type  渲染模式:
 * - @ref JRTCMediaDeviceRenderFullScreen : 铺满窗口,会有裁剪
 * - @ref JRTCMediaDeviceRenderFullContent : 全图像显示,会有黑边
 * - @ref JRTCMediaDeviceRenderFullAuto : 自适应
 * @return
 * - JRTCMediaDeviceVideoCanvas 对象: 开始其他端视频渲染成功
 * - nil: 开始其他端视频渲染失败
 */
- (JRTCMediaDeviceVideoCanvas* __nullable)startVideo:(NSString* __nonnull)streamId renderType:(JRTCMediaDeviceRender)type;

/**
 * 开始其他端的视频渲染
 *
 * 获取其他端的视频预览对象 JRTCMediaDeviceVideoCanvas ,通过此对象能获得视图用于UI显示
 *
 * @param streamId 视频流ID
 * @param type  渲染模式:
 * - @ref JRTCMediaDeviceRenderFullScreen : 铺满窗口,会有裁剪
 * - @ref JRTCMediaDeviceRenderFullContent : 全图像显示,会有黑边
 * - @ref JRTCMediaDeviceRenderFullAuto : 自适应
 * @param view 渲染视图控件
 * @return
 * - JRTCMediaDeviceVideoCanvas 对象: 开始其他端视频渲染成功
 * - nil: 开始其他端视频渲染失败
 */
- (JRTCMediaDeviceVideoCanvas* __nullable)startVideo:(NSString* __nonnull)streamId renderType:(JRTCMediaDeviceRender)type view:(JCView* __nonnull)view;

/**
 * 停止视频渲染
 * @param canvas JRTCMediaDeviceVideoCanvas 对象,由 {@link startVideo:renderType: startVideo} 或 {@link startCameraVideo: startCameraVideo} 接口返回
 */
- (void)stopVideo:(JRTCMediaDeviceVideoCanvas* __nonnull)canvas;

示例代码:

- (void)onParticipantUpdate:(JRTCRoomParticipant*)participant changeParam:(JRTCRoomParticipantChangeParam *)changeParam room:(JRTCRoom *)room {
    if (changeParam.video) {
        if (participant.video) {
            //根据需要的视频尺寸订阅该成员视频
            [_room requestVideo:participant videoSize:[[JRTCVideoSize alloc] initWithSize:1280 height:720]];
            JRTCMediaDeviceVideoCanvas *canvas = [_mediaDevice startVideo:participant.streamId renderType:JRTCMediaDeviceRenderFullContent];
            canvas.videoView.frame = CGRectMake(0, 0, 100, 100);
            [self.view addSubview:canvas.videoView];
        } else {
            //取消订阅该成员视频
            [_room unRequestVideo:participant];
            //停止渲染该成员视频
            [_mediaDevice stopVideo:canvas];
        }
    }
}

# 成员离开

当成员离开房间后,其他成员会收到成员离开的回调 onParticipantLeft (opens new window) 回调通知,此时可以调用 stopVideo (opens new window) 取消订阅该成员视频流以及停止渲染该成员视频。

/**
 * 成员离开回调
 *
 * 当房间中有成员调用 {@link JRTCRoom.leave leave} 接口离开房间后,房间中的其他成员会收到此回调。
 * @param participant JRTCRoomParticipant 成员对象
 * @param reason 离开原因
 * @param room 当前 JRTCRoom 对象
 */
- (void)onParticipantLeft:(JRTCRoomParticipant*)participant reason:(ReasonCode)reason room:(JRTCRoom *)room;

示例代码:

- (void)onParticipantLeft:(JRTCRoomParticipant*)participant reason:(ReasonCode)reason room:(JRTCRoom *)room {
    //其中remoteCanvas对象是通过 startVideo 返回
    [_mediaDevice stopVideo:remoteCanvas];
}

# 离开房间

如果想离开房间,可以调用下面的接口 leave (opens new window) ,此时自己会收到 onLeave (opens new window) 回调,房间内其他成员会收到该成员离开的回调 onParticipantLeft (opens new window)

/**
 * 离开房间
 * @return 接口调用结果
 * - true: 接口调用成功,非空闲状态下,会收到 {@link JRTCRoomCallback.onLeave:roomId:room: onLeave} 回调
 * - false: 接口调用异常
 */
- (bool)leave;
/**
 * 离开房间结果回调
 *
 * 调用 {@link JRTCRoom.leave leave} 接口成功后,会收到此回调。
 * @param reason    离开原因,参见:@ref ReasonCode "离开原因"
 * @param roomId 房间标识
 * @param room 当前 JRTCRoom 对象
 */
- (void)onLeave:(ReasonCode)reason roomId:(NSString *)roomId room:(JRTCRoom *)room;

示例代码:

// 离开房间
_room.leave();

// 离开房间回调
- (void)onLeave:(ReasonCode)reason roomId:(NSString *)roomId room:(JRTCRoom *)room {
    // 可以停止渲染其他成员视频以及本地视频
    
    //其中localCanvas对象是通过startCameraVideo 返回
    [localCanvas.videoView removeFromSuperview];
    [_mediaDevice stopVideo:localCanvas];
    localCanvas = nil;

    //其中remoteCanvas对象是通过 startVideo 返回
    [remoteCanvas.videoView removeFromSuperview];
    [_mediaDevice stopVideo:remoteCanvas];
    remoteCanvas = nil;
}

# 销毁本地和远端视频画面

当不再需要查看视频画面,包括房间成员离开,或者离开房间,需要调用 stopVideo (opens new window) 接口来停止渲染的资源,该方法需传入要释放的 JRTCMediaDeviceVideoCanvas (opens new window) 对象,或者调用 stopAllVideos (opens new window) 接口来时停止所有正在渲染的视频,必须进行这步操作,不然会造成渲染内存不释放。

/**
* 停止视频渲染
* @param canvas JRTCMediaDeviceVideoCanvas 对象,由 {@link startVideo:renderType: startVideo} 或 {@link startCameraVideo: startCameraVideo} 接口返回
*/
- (void)stopVideo:(JRTCMediaDeviceVideoCanvas* __nonnull)canvas;
/**
 * 停止所有视频渲染
 */
- (void)stopAllVideos;

示例代码:

// 离开房间回调
- (void)onLeave:(ReasonCode)reason roomId:(NSString *)roomId room:(JRTCRoom *)room {
    // 停止本端视频
    [_mediaDevice stopVideo:localCanvas]; 
    // 停止远端成员视频
    [_mediaDevice stopVideo:remoteCanvas]; 
    // 停止所有正在渲染的视频
    [_mediaDevice stopAllVideos]; 
}

- (void)onParticipantLeft:(JRTCRoomParticipant*)participant reason:(ReasonCode)reason room:(JRTCRoom *)room {
    //其中remoteCanvas对象是通过 startVideo 返回
    [_mediaDevice stopVideo:remoteCanvas];
}

# 登出

离开房间后,可以做登出操作,登出接口调用流程如下所示:

img

成员可以通过调用 logout (opens new window)方法登出视频平台,与平台断开一切连接。

/**
 * 登出 Juphoon RTC 平台,登出后不能进行平台上的各种业务
 *
 * 登出结果通过 {@link JRTCClientCallback.onLogout: onLogout} 回调通知
 * @return 接口调用结果
 * - true: 接口调用成功
 * - false: 接口调用异常
 */
- (bool)logout;

登出结果通过 JRTCClientCallback (opens new window) 中的 onLogout (opens new window) 接口进行上报。

/**
 * 登出回调
 * @param reason 登出原因
 */
- (void)onLogout:(ReasonCode)reason;

示例代码:

// 调用登出接口
[_client logout];

// 监听登出结果回调
- (void)onLogout:(ReasonCode)reason {
    // 登出完成   
}

# 登录登出状态改变通知

登录状态通过 JRTCClientCallback (opens new window)onClientStateChanged (opens new window) 接口上报

/**
 * 登录状态变化通知
 * @param state 当前状态值
 * @param oldState 之前状态值
 */
- (void)onClientStateChanged:(JRTCClientState)state oldState:(JRTCClientState)oldState;

登录状态详见 JRTCClientState (opens new window)

示例代码:

- (void)onClientStateChanged:(JRTCClientState)state oldState:(JRTCClientState)oldState {
    //state 当前状态
    //oldState 之前状态
}

# 销毁 SDK

每个模块都有对应的销毁接口。如不需再使用 SDK 的相关功能,可以强制释放 SDK 的资源。 注:该方法为同步调用,调用此方法后,你将无法再使用该模块的其它方法和回调。 我们不建议在 JRTCSDK 的所有回调方法中调用此方法销毁对象,否则可能出现崩溃现象。

+ (void)destroy;

示例代码:

- (void)destroySDK {
    [JRTCClient destroy]; // client模块销毁
    [JRTCMediaDevice destroy]; // 设备模块销毁
    [JRTCRoom destroy]; // room模块销毁
}