# 实现视频通话
本文档为您展示通过 SDK 实现视频通话(座席侧集成)的相关步骤,帮助您在远程银行和视频客服的场景下实现智能排队、座席转接、全景录像、座席管理的相关能力。
# 1. 前提条件
请确认您已完成以下操作:
- 已获取 App Key。
AppKey 作为同个环境的分域依据,同一个域的终端才能实现互通,AppKey 由 Juphoon 视频平台提供。
- 集成 SDK(iOS)。
TIP
请扫描下方二维码联系 Juphoon 市场售前工程师获取 AppKey。
集成 SDK(iOS)。
TIP
如需集成指导,请扫描上方二维码联系 Juphoon 市场售前工程师获取相关咨询。
# 2. 快速跑通Sample
- 在 Juphoon RTC SDK 文档中心**,iOS 平台**下载体验 JCCSample 示例项目。
访问下载地址 (opens new window),示例如下:
- 下载完成后,安装 Juphoon_Rtc_Sample_for_iOS_R22C03_CallCenter 目录下的 JCCSample.ipa。
打开应用程序后,设置合适的 Appkey,即可体验 Sample 的功能。
操作步骤:
a. 确认 AppKey 的正确性,输入账号,密码,服务器地址等信息;
b. 点击 登录 按钮,待 登录 按钮变为 "登出" 时表示已经成功登录;
c. 点击座席的右上角 进入 按钮,选择座席即可体验座席相关的功能。
d. 进入座席页面,首先座席签入到排队机,签入按钮变为签出时表示签入成功,签入成功时自动设置为示闲状态;当有访客呼入时,座席即可接听或挂断当前通话,进行视频客服座席的基本业务流程。
# 3. 实现视频通话
# 初始化
注:我们所有的方法都建议在主线程调用,否则可能会出现异常无法正常使用,回调接口也都在主线程上报。
初始化JRTCSDK需要创建 JRTCClient (opens new window),JRTCMediaDevice (opens new window),JRTCAgent (opens new window)的实例。
JRTCClient (opens new window) | 登录模块 | 负责视频平台的登录登出,只有登录到视频平台才可以使用视频相关的业务 | |
---|---|---|---|
JRTCMediaDevice (opens new window) | 媒体模块 | 负责本地的媒体设备操作,视频画面渲染等功能 | |
JRTCAgent (opens new window) | 座席模块 | 负责座席的视频业务的处理,比如接听来电,控制音视频流等 |
AppKey 作为同个环境的分域依据,同一个域的终端才能实现互通,AppKey 由 Juphoon 视频平台提供。 在使用业务接口前,需对 Juphoon SDK 进行初始化操作。 注:Guest 访客模块和 Agent 座席模块只支持初始化一个,否则会出现接收不到呼叫,接收不到邀请等现象影响正常的业务流程。
初始化参数详见 JRTCClientInitParam (opens new window) 。
示例代码:
@interface JCManager () <JRTCClientCallback, JRTCMediaDeviceCallback, JRTCAgentCallback>
- (void)initSDK {
// 创建初始化参数
JRTCClientInitParam *param = [[JRTCClientInitParam alloc] init];
// 设置appkey
param.appKey = @"AppKey";
// 设置接入服务器地址
param.server = @"Server";
// 设置应用名
param.appName = @"AppName";
// 创建 JRTCClient 对象
_client = [JRTCClient create:self initParam:param];
// 创建 JRTCMediaDevice 对象
_mediaDevice = [JRTCMediaDevice create:_client callback:self];
// 创建 JRTCAgent 对象
_agent = [JRTCAgent create:_client mediaDevice:_mediaDevice callback:self];
}
@end@interface JCManager () <JRTCClientCallback, JRTCMediaDeviceCallback, JRTCAgentCallback>
- (void)initSDK {
// 创建初始化参数
JRTCClientInitParam *param = [[JRTCClientInitParam alloc] init];
// 设置appkey
param.appKey = @"AppKey";
// 设置接入服务器地址
param.server = @"Server";
// 设置应用名
param.appName = @"AppName";
// 创建 JRTCClient 对象
_client = [JRTCClient create:self initParam:param];
// 创建 JRTCMediaDevice 对象
_mediaDevice = [JRTCMediaDevice create:_client callback:self];
// 创建 JRTCAgent 对象
_agent = [JRTCAgent create:_client mediaDevice:_mediaDevice callback:self];
}
@end
然后根据需求实现 Callback 的接口即可。
# 登录
SDK 初始化之后,即可进行登录的集成。登录接口调用流程如下所示: 调用 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;/**
* 登录 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;
登录的结果将会通过 JRTCClientCallback (opens new window) 中的 onLogin (opens new window) 接口上报。
/**
* 登录结果回调
* @param result true 表示登录成功,false 表示登录失败
* @param reason 当 result 为 false 时该值有效
*/
- (void)onLogin:(bool)result reason:(ReasonCode)reason;/**
* 登录结果回调
* @param result true 表示登录成功,false 表示登录失败
* @param reason 当 result 为 false 时该值有效
*/
- (void)onLogin:(bool)result reason:(ReasonCode)reason;
示例代码:
// 创建登录配置参数
JRTCClientLoginParam *param = [[JRTCClientLoginParam alloc] init];
// 登录
[_client login:@"agent1" password:@"123456" loginParam:param];
// 登录结果回调
- (void)onLogin:(bool)result reason:(ReasonCode)reason {
if (result == true) {
// 登录成功
}
else {
// 登录失败,具体原因查询 reason 错误码
}
}// 创建登录配置参数
JRTCClientLoginParam *param = [[JRTCClientLoginParam alloc] init];
// 登录
[_client login:@"agent1" password:@"123456" loginParam:param];
// 登录结果回调
- (void)onLogin:(bool)result reason:(ReasonCode)reason {
if (result == true) {
// 登录成功
}
else {
// 登录失败,具体原因查询 reason 错误码
}
}
# 获取业务号列表
通过调用 queryAllGroups (opens new window) 接口获取当前业务号列表。
/**
* 获取业务号列表
*
* @return 接口调用结果
* - true: 接口调用成功
* - false: 接口调用异常
*/
- (bool)queryAllGroups;/**
* 获取业务号列表
*
* @return 接口调用结果
* - true: 接口调用成功
* - false: 接口调用异常
*/
- (bool)queryAllGroups;
业务组信息通过实现 JRTCAgentCallback (opens new window) 中的 onGetAllGroups (opens new window) 接口上报。
/**
* 获取业务号列表结果回调
* @param groups 坐席业务实体对象列表,获取失败时为 nil
* @param result 获取结果
* - true: 获取成功
* - false: 获取失败
*/
- (void)onGetAllGroups:(NSArray <JRTCCallCenterGroupItem *> *)groups result:(bool)result;/**
* 获取业务号列表结果回调
* @param groups 坐席业务实体对象列表,获取失败时为 nil
* @param result 获取结果
* - true: 获取成功
* - false: 获取失败
*/
- (void)onGetAllGroups:(NSArray <JRTCCallCenterGroupItem *> *)groups result:(bool)result;
示例代码:
// 获取业务号列表
[_agent queryAllGroups];
// 获取业务号列表结果回调
- (void)onGetAllGroups:(NSArray <JRTCCallCenterGroupItem *> *)groups result:(bool)result {
if (result == true) {
// 查询成功
}
else {
// 查询失败
}
}// 获取业务号列表
[_agent queryAllGroups];
// 获取业务号列表结果回调
- (void)onGetAllGroups:(NSArray <JRTCCallCenterGroupItem *> *)groups result:(bool)result {
if (result == true) {
// 查询成功
}
else {
// 查询失败
}
}
# 查询指定组号的空闲座席
调用 queryAvailableAgentList (opens new window) 接口查询指定组号的空闲座席。
/**
* 查询指定组号的空闲座席
*
* 查询结果通过 {@link JRTCAgentCallback.onQueryAvailableAgentList:result:userIds: onQueryAvailableAgentList} 回调上报
* @param businessNumber 业务号,例如 10087
* @return 操作id,与 {@link JRTCAgentCallback.onQueryAvailableAgentList:result:userIds: onQueryAvailableAgentList} 的 operationId 参数对应
*/
- (int)queryAvailableAgentList:(NSString *)businessNumber;/**
* 查询指定组号的空闲座席
*
* 查询结果通过 {@link JRTCAgentCallback.onQueryAvailableAgentList:result:userIds: onQueryAvailableAgentList} 回调上报
* @param businessNumber 业务号,例如 10087
* @return 操作id,与 {@link JRTCAgentCallback.onQueryAvailableAgentList:result:userIds: onQueryAvailableAgentList} 的 operationId 参数对应
*/
- (int)queryAvailableAgentList:(NSString *)businessNumber;
指定组号的空闲座席查询结果通过实现 JRTCAgentCallback (opens new window) 中的 onQueryAvailableAgentList (opens new window) 接口上报。
/**
* 查询空闲座席回调
*
* 座席调用 {@link JRTCAgent.queryAvailableAgentList: queryAvailableAgentList} 接口查询空闲座席成功时,会收到此回调。
* @param operationId 操作ID,对应 {@link JRTCAgent.queryAvailableAgentList: queryAvailableAgentList} 接口的返回值
* @param result 查询结果
* - true: 查询成功
* - false: 查询失败
* @param userIds 查询到的空闲座席列表
*/
- (void)onQueryAvailableAgentList:(int)operationId result:(bool)result userIds:(NSArray <NSString *> *)userIds;
/**
* 查询空闲座席回调
*
* 座席调用 {@link JRTCAgent.queryAvailableAgentList: queryAvailableAgentList} 接口查询空闲座席成功时,会收到此回调。
* @param operationId 操作ID,对应 {@link JRTCAgent.queryAvailableAgentList: queryAvailableAgentList} 接口的返回值
* @param result 查询结果
* - true: 查询成功
* - false: 查询失败
* @param userIds 查询到的空闲座席列表
*/
- (void)onQueryAvailableAgentList:(int)operationId result:(bool)result userIds:(NSArray <NSString *> *)userIds;
示例代码:
// 查询指定组号的空闲座席
[_agent queryAvailableAgentList:@"10087"];
// 查询空闲座席回调
- (void)onQueryAvailableAgentList:(int)operationId result:(bool)result userIds:(NSArray <NSString *> *)userIds {
if (result == true) {
// 查询成功,具体查看 userIds
} else {
// 查询失败
}
}// 查询指定组号的空闲座席
[_agent queryAvailableAgentList:@"10087"];
// 查询空闲座席回调
- (void)onQueryAvailableAgentList:(int)operationId result:(bool)result userIds:(NSArray <NSString *> *)userIds {
if (result == true) {
// 查询成功,具体查看 userIds
} else {
// 查询失败
}
}
# 座席签入
登录视频能力平台成功后,需要签入到排队机才能由排队机进行路由分配。 座席可调用的 checkIn (opens new window) 接口签入到排队机。
/**
* 签入
*
* 签入到排队机,签入后默认示闲状态 <br>
* 示闲状态下正常呼叫进线 <br>
* 调用接口前确定 JRTCClient 登录成功 <br>
* 调用该接口前需先确定 @ref operatorState 来获取到当前的签入状态
* @param userId 座席用户ID,需与业务管理平台上配置的座席staffId对应
* @param role 座席角色类型,目前该参数已有服务端控制,不再通过终端设置,可忽略
* @return 接口调用结果
* - true: 接口调用成功,签入结果会触发 {@link JRTCAgentCallback.onCheckinResult: onCheckinResult} 回调上报
* - false: 接口调用异常
*/
- (bool)checkIn:(NSString *)userId role:(AgentRoleType)role;
/**
* 签入
*
* 签入到排队机,签入后默认示闲状态 <br>
* 示闲状态下正常呼叫进线 <br>
* 调用接口前确定 JRTCClient 登录成功 <br>
* 调用该接口前需先确定 @ref operatorState 来获取到当前的签入状态 <br>
* 该方法座席用户ID默认为 {@link JRTCClient.userId userId} ,与业务管理平台上配置的座席staffId对应
* @param role 座席角色类型,目前该参数已有服务端控制,不再通过终端设置,可忽略
* @return 接口调用结果
* - true: 接口调用成功,签入结果会触发 {@link JRTCAgentCallback.onCheckinResult: onCheckinResult} 回调上报
* - false: 接口调用异常
*/
- (bool)checkIn:(AgentRoleType)role;
/**
* 签入
*
* 签入到排队机,签入后示忙/示闲状态由 busy 参数决定 <br>
* 示闲状态下正常呼叫进线 <br>
* 调用接口前确定 JRTCClient 登录成功 <br>
* 调用该接口前需先确定 @ref operatorState 来获取到当前的签入状态
* @param userId 座席用户ID,需与业务管理平台上配置的座席staffId对应
* @param role 座席角色类型,目前该参数已有服务端控制,不再通过终端设置,可忽略
* @param busy 签入后示忙/示闲状态
* - true: 示忙
* - false: 示闲
* @return 接口调用结果
* - true: 接口调用成功,签入结果会触发 {@link JRTCAgentCallback.onCheckinResult: onCheckinResult} 回调上报
* - false: 接口调用异常
*/
- (bool)checkIn:(NSString *)userId role:(AgentRoleType)role busy:(bool)busy;/**
* 签入
*
* 签入到排队机,签入后默认示闲状态 <br>
* 示闲状态下正常呼叫进线 <br>
* 调用接口前确定 JRTCClient 登录成功 <br>
* 调用该接口前需先确定 @ref operatorState 来获取到当前的签入状态
* @param userId 座席用户ID,需与业务管理平台上配置的座席staffId对应
* @param role 座席角色类型,目前该参数已有服务端控制,不再通过终端设置,可忽略
* @return 接口调用结果
* - true: 接口调用成功,签入结果会触发 {@link JRTCAgentCallback.onCheckinResult: onCheckinResult} 回调上报
* - false: 接口调用异常
*/
- (bool)checkIn:(NSString *)userId role:(AgentRoleType)role;
/**
* 签入
*
* 签入到排队机,签入后默认示闲状态 <br>
* 示闲状态下正常呼叫进线 <br>
* 调用接口前确定 JRTCClient 登录成功 <br>
* 调用该接口前需先确定 @ref operatorState 来获取到当前的签入状态 <br>
* 该方法座席用户ID默认为 {@link JRTCClient.userId userId} ,与业务管理平台上配置的座席staffId对应
* @param role 座席角色类型,目前该参数已有服务端控制,不再通过终端设置,可忽略
* @return 接口调用结果
* - true: 接口调用成功,签入结果会触发 {@link JRTCAgentCallback.onCheckinResult: onCheckinResult} 回调上报
* - false: 接口调用异常
*/
- (bool)checkIn:(AgentRoleType)role;
/**
* 签入
*
* 签入到排队机,签入后示忙/示闲状态由 busy 参数决定 <br>
* 示闲状态下正常呼叫进线 <br>
* 调用接口前确定 JRTCClient 登录成功 <br>
* 调用该接口前需先确定 @ref operatorState 来获取到当前的签入状态
* @param userId 座席用户ID,需与业务管理平台上配置的座席staffId对应
* @param role 座席角色类型,目前该参数已有服务端控制,不再通过终端设置,可忽略
* @param busy 签入后示忙/示闲状态
* - true: 示忙
* - false: 示闲
* @return 接口调用结果
* - true: 接口调用成功,签入结果会触发 {@link JRTCAgentCallback.onCheckinResult: onCheckinResult} 回调上报
* - false: 接口调用异常
*/
- (bool)checkIn:(NSString *)userId role:(AgentRoleType)role busy:(bool)busy;
checkIn (opens new window) 接口包含几个重载,用来适应各种可配置的参数,比如签入后默认为示闲还是示忙。这些接口的使用结合具体的需求来使用。
签入的结果将会通过实现 JRTCAgentCallback (opens new window) 中的 onCheckIn (opens new window) 接口上报。
/**
* 签入回调
*
* 座席调用 {@link JRTCAgent.checkIn:role:busy: checkIn} 接口成功,会收到此回调。
* @param result 签入结果
* - true: 签入成功
* - false: 签入失败
* @param pause 签入后的示闲/示忙状态
* - true: 签入后示忙
* - false: 签入后示闲
* @param onlineTime 座席累计在线时长
* @param breakTime 座席累计示忙时长
* @param callTimes 通话次数
* @param reason 签入失败原因
*/
- (void)onCheckIn:(bool)result pause:(bool)pause onlineTime:(long)onlineTime breakTime:(long)breakTime callTimes:(long)callTimes reason:(int)reason;/**
* 签入回调
*
* 座席调用 {@link JRTCAgent.checkIn:role:busy: checkIn} 接口成功,会收到此回调。
* @param result 签入结果
* - true: 签入成功
* - false: 签入失败
* @param pause 签入后的示闲/示忙状态
* - true: 签入后示忙
* - false: 签入后示闲
* @param onlineTime 座席累计在线时长
* @param breakTime 座席累计示忙时长
* @param callTimes 通话次数
* @param reason 签入失败原因
*/
- (void)onCheckIn:(bool)result pause:(bool)pause onlineTime:(long)onlineTime breakTime:(long)breakTime callTimes:(long)callTimes reason:(int)reason;
示例代码:
// 签入,签入后为示闲状态
[_agent checkIn:_client.userId role:0 busy:false];
// 签入结果回调
- (void)onCheckIn:(bool)result pause:(bool)pause onlineTime:(long)onlineTime breakTime:(long)breakTime callTimes:(long)callTimes reason:(int)reason {
if (result == true) {
NSLog(@"签入成功,签入后状态为 %@", pause == true ? @"示忙" : @"示闲");
} else {
NSLog(@"签入失败,失败原因为 %d", reason);
}
}// 签入,签入后为示闲状态
[_agent checkIn:_client.userId role:0 busy:false];
// 签入结果回调
- (void)onCheckIn:(bool)result pause:(bool)pause onlineTime:(long)onlineTime breakTime:(long)breakTime callTimes:(long)callTimes reason:(int)reason {
if (result == true) {
NSLog(@"签入成功,签入后状态为 %@", pause == true ? @"示忙" : @"示闲");
} else {
NSLog(@"签入失败,失败原因为 %d", reason);
}
}
# 座席签出
当所有业务处理完毕,座席可以使用 Agent 对象中的 checkout (opens new window) 签出后排队机将不会分发访客到这个座席终端,业务管理平台上该座席的状态将变为离线。
/**
* 签出
*
* 签出后将不会收到排队机的呼叫分配 <br>
* 签出排队机不影响 JRTCClient 的登录状态 <br>
* 调用 @ref operatorState 可获取当前签入状态
* @return 接口调用结果
* - true: 接口调用成功,签出结果通过 {@link JRTCAgentCallback.onCheckoutResult:reason: onCheckoutResult} 回调上报
* - false: 接口调用异常
*/
- (bool)checkout;/**
* 签出
*
* 签出后将不会收到排队机的呼叫分配 <br>
* 签出排队机不影响 JRTCClient 的登录状态 <br>
* 调用 @ref operatorState 可获取当前签入状态
* @return 接口调用结果
* - true: 接口调用成功,签出结果通过 {@link JRTCAgentCallback.onCheckoutResult:reason: onCheckoutResult} 回调上报
* - false: 接口调用异常
*/
- (bool)checkout;
签出结果通过 JRTCAgentCallback (opens new window) 的 onCheckout (opens new window) 上报。
/**
* 签出回调
*
* 座席调用 {@link JRTCAgent.checkout checkout} 接口签出排队机,会收到此回调。
* @param result 签出结果
* - true: 签出成功
* - false: 签出失败
* @param reason 签出原因
*/
- (void)onCheckout:(bool)result reason:(AgentCheckoutReason)reason;/**
* 签出回调
*
* 座席调用 {@link JRTCAgent.checkout checkout} 接口签出排队机,会收到此回调。
* @param result 签出结果
* - true: 签出成功
* - false: 签出失败
* @param reason 签出原因
*/
- (void)onCheckout:(bool)result reason:(AgentCheckoutReason)reason;
座席签出原因详见 AgentCheckoutReason (opens new window) 。
示例代码:
// 签出
[_agent checkout];
// 签出结果回调
- (void)onCheckout:(bool)result reason:(AgentCheckoutReason)reason {
if (result == true) {
// 签出成功,签出原因查看 reason
} else {
// 签出失败
}
}// 签出
[_agent checkout];
// 签出结果回调
- (void)onCheckout:(bool)result reason:(AgentCheckoutReason)reason {
if (result == true) {
// 签出成功,签出原因查看 reason
} else {
// 签出失败
}
}
# 座席签入签出状态改变
座席签入状态发生变化通过 JRTCAgentCallback (opens new window) 的 onCheckStateChanged (opens new window) 接口上报。
/**
* 签入/签出状态改变
*
* 座席签入/签出状态发生改变时,会收到此回调,例如,调用签入/签出接口。
* @param currentState 当前座席状态
* @param oldState 旧的座席状态
*/
- (void)onCheckStateChanged:(AgentOperatorState)currentState oldState:(AgentOperatorState)oldState;/**
* 签入/签出状态改变
*
* 座席签入/签出状态发生改变时,会收到此回调,例如,调用签入/签出接口。
* @param currentState 当前座席状态
* @param oldState 旧的座席状态
*/
- (void)onCheckStateChanged:(AgentOperatorState)currentState oldState:(AgentOperatorState)oldState;
座席状态详见 AgentOperatorState (opens new window) 。
- (void)onCheckStateChanged:(AgentOperatorState)currentState oldState:(AgentOperatorState)oldState {
if (currentState == AgentOperatorStateCheckining) {
//正在签入中
} else if (currentState == AgentOperatorStateCheckinOK) {
//已签入
} else if (currentState == AgentOperatorStateCheckouting) {
//签出中
} else if (currentState == AgentOperatorStateCheckinIdle) {
//签入失败
}
}
- (void)onCheckStateChanged:(AgentOperatorState)currentState oldState:(AgentOperatorState)oldState {
if (currentState == AgentOperatorStateCheckining) {
//正在签入中
} else if (currentState == AgentOperatorStateCheckinOK) {
//已签入
} else if (currentState == AgentOperatorStateCheckouting) {
//签出中
} else if (currentState == AgentOperatorStateCheckinIdle) {
//签入失败
}
}
# 获取座席签入状态
通过 operatorState (opens new window) 获取座席签入状态。
/**
* 座席签入状态
*/
@property (nonatomic, readonly, assign) AgentOperatorState operatorState;/**
* 座席签入状态
*/
@property (nonatomic, readonly, assign) AgentOperatorState operatorState;
# 示忙示闲
通过调用 JRTCAgent 对象的 applyStatePause (opens new window) 方法来切换该状态。
- 示忙:座席暂停服务,访客无法呼到该座席
- 示闲:座席保持服务,访客可以呼到该座席
/**
* 示忙/示闲
*
* 示忙状态下不会收到呼叫来电,示闲状态下正常呼叫进线 <br>
* 通话过程中调用该接口不会影响当前通话,从下个通话开始状态生效 <br>
* 示忙/示闲的结果通过 {@link JRTCAgentCallback.onApplyResult:result: onApplyResult} 回调上报
* @param pause 示忙或是示闲
* - true: 示忙
* - false: 示闲
* @return 接口调用结果
* - > 0: 操作id,对应 {@link JRTCAgentCallback.onApplyResult:result: onApplyResult} 回调的 operationId 参数
* - -1:接口调用异常
*/
- (int)applyStatePause:(bool)pause;/**
* 示忙/示闲
*
* 示忙状态下不会收到呼叫来电,示闲状态下正常呼叫进线 <br>
* 通话过程中调用该接口不会影响当前通话,从下个通话开始状态生效 <br>
* 示忙/示闲的结果通过 {@link JRTCAgentCallback.onApplyResult:result: onApplyResult} 回调上报
* @param pause 示忙或是示闲
* - true: 示忙
* - false: 示闲
* @return 接口调用结果
* - > 0: 操作id,对应 {@link JRTCAgentCallback.onApplyResult:result: onApplyResult} 回调的 operationId 参数
* - -1:接口调用异常
*/
- (int)applyStatePause:(bool)pause;
示忙示闲结果通过实现 JRTCAgentCallback (opens new window) 中的 onApplyResult (opens new window) 接口上报。
/**
* 示忙/示闲回调
*
* 座席示忙/示闲状态发生改变时,会收到此回调,例如调用 {@link JRTCAgent.applyStatePause: applyStatePause} 接口修改忙闲状态。 <br>
* 可以通过 {@link JRTCAgent.pause pause} 获取当前的忙闲状态。
* @param operationId 对应 {@link JRTCAgent.applyStatePause: applyStatePause} 接口的返回值
* @param result 示忙/示闲操作结果
* - true: 示忙/示闲成功
* - false: 示忙/示闲失败
*/
- (void)onApplyResult:(int)operationId result:(bool)result;/**
* 示忙/示闲回调
*
* 座席示忙/示闲状态发生改变时,会收到此回调,例如调用 {@link JRTCAgent.applyStatePause: applyStatePause} 接口修改忙闲状态。 <br>
* 可以通过 {@link JRTCAgent.pause pause} 获取当前的忙闲状态。
* @param operationId 对应 {@link JRTCAgent.applyStatePause: applyStatePause} 接口的返回值
* @param result 示忙/示闲操作结果
* - true: 示忙/示闲成功
* - false: 示忙/示闲失败
*/
- (void)onApplyResult:(int)operationId result:(bool)result;
可通过 termState (opens new window) 属性设置通话结束后设置示闲示忙。
/**
* 结束通话后的示闲/示忙状态,默认为示闲状态
*
* 结束通话后,默认为示闲状态,可由上层设置
*/
@property (nonatomic, assign) AgentTermState termState;/**
* 结束通话后的示闲/示忙状态,默认为示闲状态
*
* 结束通话后,默认为示闲状态,可由上层设置
*/
@property (nonatomic, assign) AgentTermState termState;
可通过 pause (opens new window) 查询示闲示忙的状态。
/**
* 示忙/示闲状态
*/
@property (nonatomic, readonly, assign) bool pause;/**
* 示忙/示闲状态
*/
@property (nonatomic, readonly, assign) bool pause;
示例代码:
// 示忙
[_agent applyStatePause:true];
// 示闲
[_agent applyStatePause:false];
// 示闲/示忙结果回调
- (void)onApplyResult:(int)operationId result:(bool)result {
if (result == true) {
NSLog(@"示忙/示闲操作成功");
} else {
NSLog(@"示忙/示闲操作失败");
}
}
// 设置签出后示忙/示闲状态
_agent.termState = AgentTermStateBusy;
// 获取当前示闲/示忙状态
bool pause = _agent.pause;
if (pause == true) {
NSLog(@"当前为示忙状态");
} else {
NSLog(@"当前为示闲状态");
}// 示忙
[_agent applyStatePause:true];
// 示闲
[_agent applyStatePause:false];
// 示闲/示忙结果回调
- (void)onApplyResult:(int)operationId result:(bool)result {
if (result == true) {
NSLog(@"示忙/示闲操作成功");
} else {
NSLog(@"示忙/示闲操作失败");
}
}
// 设置签出后示忙/示闲状态
_agent.termState = AgentTermStateBusy;
// 获取当前示闲/示忙状态
bool pause = _agent.pause;
if (pause == true) {
NSLog(@"当前为示忙状态");
} else {
NSLog(@"当前为示闲状态");
}
# 座席回呼
座席可以通过调用 recall (opens new window) 接口回呼访客。
/**
* 座席回呼
*
* @param userId 访客用户ID
* @param callParam 呼叫参数设置,此参数可传 nil 则使用默认配置,详见 {@link JRTCallCenterCallParam}
* @return 接口调用结果
* - true: 接口调用成功,通话状态会通过 {@link JRTCAgentCallback#onCallStateChanged onCallStateChanged} 回调上报
* - false: 接口调用异常
*/
- (bool)recall:(NSString *)userId callParam:(JRTCCallCenterCallParam *)param;/**
* 座席回呼
*
* @param userId 访客用户ID
* @param callParam 呼叫参数设置,此参数可传 nil 则使用默认配置,详见 {@link JRTCallCenterCallParam}
* @return 接口调用结果
* - true: 接口调用成功,通话状态会通过 {@link JRTCAgentCallback#onCallStateChanged onCallStateChanged} 回调上报
* - false: 接口调用异常
*/
- (bool)recall:(NSString *)userId callParam:(JRTCCallCenterCallParam *)param;
示例代码:
JRTCCallCenterCallParam *callParam = [JRTCCallCenterCallParam new];
// callParam参数设置
...
[agent recall:userId callParam:callParam];JRTCCallCenterCallParam *callParam = [JRTCCallCenterCallParam new];
// callParam参数设置
...
[agent recall:userId callParam:callParam];
# 接听来电
在座席收到来电的通知后,可以通过调用 answer (opens new window) 接口来接起访客的呼叫。
来电类型详见 CallIncomingType (opens new window)
CallIncomingTypeCall (opens new window):普通来电,访客调用 call (opens new window) 接口呼叫;
CallIncomingTypeInvite (opens new window):三方邀请来电,座席调用 inviteThirdAgent (opens new window) 接口邀请三方座席;
CallIncomingTypeForward (opens new window):转接来电,座席调用 transferCall (opens new window) 接口转接当前通话;
CallIncomingTypeDirectCall (opens new window):直呼来电,访客调用 oneToOneCall (opens new window) 接口进行直呼座席;
/**
* 接听通话
*
* 主座席、第三方座席或是被转接的座席,都调用此接口接听通话
* @return 接口调用结果
* - true: 接口调用成功,会收到 {@link JRTCAgentCallback.onCallStateChanged:incomingType:inviter:reason: onCallStateChanged} 回调
* - false: 接口调用异常
*/
- (bool)answer;/**
* 接听通话
*
* 主座席、第三方座席或是被转接的座席,都调用此接口接听通话
* @return 接口调用结果
* - true: 接口调用成功,会收到 {@link JRTCAgentCallback.onCallStateChanged:incomingType:inviter:reason: onCallStateChanged} 回调
* - false: 接口调用异常
*/
- (bool)answer;
示例代码:
- (void)onCallStateChanged:(AgentCallStateChangeType)type incomingType:(CallIncomingType)incomingType inviter:(nullable JRTCInviter *)inviter reason:(CallTermReason)reason {
if (type == AgentCallStateChangeTypeIncoming) {
if (incomingType == CallIncomingTypeCall) {
// 普通呼叫来电
} else if (incomingType == CallIncomingTypeInvite) {
// 三方邀请来电
} else if (incomingType == CallIncomingTypeInvite) {
// 转接来电
} else if (incomingType == CallIncomingTypeInvite) {
// 直呼来电
}
// 接听
[_agent answer];
}
}- (void)onCallStateChanged:(AgentCallStateChangeType)type incomingType:(CallIncomingType)incomingType inviter:(nullable JRTCInviter *)inviter reason:(CallTermReason)reason {
if (type == AgentCallStateChangeTypeIncoming) {
if (incomingType == CallIncomingTypeCall) {
// 普通呼叫来电
} else if (incomingType == CallIncomingTypeInvite) {
// 三方邀请来电
} else if (incomingType == CallIncomingTypeInvite) {
// 转接来电
} else if (incomingType == CallIncomingTypeInvite) {
// 直呼来电
}
// 接听
[_agent answer];
}
}
接听的结果同样通过 JRTCAgentCallback (opens new window) 的 onCallStateChanged (opens new window) 接口上报。
# 通话状态改变通知
座席签入成功后即为一个等待通话接入的状态,具体的通话由排队机进分配。
- 访客呼叫场景:
- 座席收到来电,通话状态就改变为 AgentCallStateChangeTypeIncoming (opens new window) ;
- 座席接听,成功进入通话,通话状态改变为 AgentCallStateChangeTypeTalking (opens new window) ;
- 座席挂断或者其他成员挂断导致通话结束,通话状态改变为 AgentCallStateChangeTypeTermed (opens new window) ;
回呼场景
- 座席回呼访客,通话状态就改变为 AgentCallStateChangeTypeCalling (opens new window) ;
- 访客接听,成功进入通话,通话状态改变为 AgentCallStateChangeTypeTalking (opens new window) ;
- 座席挂断或者其他成员挂断导致通话结束,通话状态改变为 AgentCallStateChangeTypeTermed (opens new window) ;
均通过实现 JRTCAgentCallback (opens new window) 中的 onCallStateChanged (opens new window) 的接口上报。
/**
* 通话状态改变回调
* @param type 通话状态改变类型,即以下情况会收到此回调:
* - @ref AgentCallStateChangeTypeIncoming 收到来电(访客呼叫、座席邀请、转接)
* - @ref AgentCallStateChangeTypeTalking 通话接通
* - @ref AgentCallStateChangeTypeTermed 通话挂断或被挂断
* @param incomingType 来电类型,当 type == {@link AgentCallStateChangeTypeIncoming} 时有效
* @param inviter 邀请成员对象,当 type == {@link AgentCallStateChangeTypeIncoming} 时有效
* @param reason 挂断原因,只在 type 为 @ref AgentCallStateChangeTypeTermed 时需要关注,详见 @ref CallTermReason
*/
- (void)onCallStateChanged:(AgentCallStateChangeType)type incomingType:(CallIncomingType)incomingType inviter:(nullable JRTCInviter *)inviter reason:(CallTermReason)reason;/**
* 通话状态改变回调
* @param type 通话状态改变类型,即以下情况会收到此回调:
* - @ref AgentCallStateChangeTypeIncoming 收到来电(访客呼叫、座席邀请、转接)
* - @ref AgentCallStateChangeTypeTalking 通话接通
* - @ref AgentCallStateChangeTypeTermed 通话挂断或被挂断
* @param incomingType 来电类型,当 type == {@link AgentCallStateChangeTypeIncoming} 时有效
* @param inviter 邀请成员对象,当 type == {@link AgentCallStateChangeTypeIncoming} 时有效
* @param reason 挂断原因,只在 type 为 @ref AgentCallStateChangeTypeTermed 时需要关注,详见 @ref CallTermReason
*/
- (void)onCallStateChanged:(AgentCallStateChangeType)type incomingType:(CallIncomingType)incomingType inviter:(nullable JRTCInviter *)inviter reason:(CallTermReason)reason;
通话状态详见 AgentCallStateChangeType (opens new window) 。 通话结束原因详见 CallTermReason (opens new window) 。
示例代码:
- (void)onCallStateChanged:(AgentCallStateChangeType)type incomingType:(CallIncomingType)incomingType inviter:(nullable JRTCInviter *)inviter reason:(CallTermReason)reason {
if (type == AgentCallStateChangeTypeIncoming) {
// 收到来电
} else if (type == AgentCallStateChangeTypeTalking) {
// 通话建立
} else if (type == AgentCallStateChangeTypeTermed) {
// 通话挂断
} else if (type == AgentCallStateChangeTypeCalling) {
// 呼叫(坐席回呼)
}
}- (void)onCallStateChanged:(AgentCallStateChangeType)type incomingType:(CallIncomingType)incomingType inviter:(nullable JRTCInviter *)inviter reason:(CallTermReason)reason {
if (type == AgentCallStateChangeTypeIncoming) {
// 收到来电
} else if (type == AgentCallStateChangeTypeTalking) {
// 通话建立
} else if (type == AgentCallStateChangeTypeTermed) {
// 通话挂断
} else if (type == AgentCallStateChangeTypeCalling) {
// 呼叫(坐席回呼)
}
}
# 获取通话状态
可通过调用 callState (opens new window) 方法获取当前通话状态,通话状态改变详见 CallState (opens new window) 。
/**
* 当前通话状态
*/
@property (nonatomic, readonly, assign) CallState callState;/**
* 当前通话状态
*/
@property (nonatomic, readonly, assign) CallState callState;
示例代码:
CallState callState = _agent.callState;
if (callState == CallStateIdle) {
// 空闲
} else if (callState == CallStateCalling) {
// 呼叫中(回呼场景)
} else if (callState == CallStateIncoming) {
// 来电
} else if (callState == CallStateTalking) {
// 通话中
}CallState callState = _agent.callState;
if (callState == CallStateIdle) {
// 空闲
} else if (callState == CallStateCalling) {
// 呼叫中(回呼场景)
} else if (callState == CallStateIncoming) {
// 来电
} else if (callState == CallStateTalking) {
// 通话中
}
# 创建本地视频画面
初始化成功后,可以创建本地的视频画面,创建本地视频画面的时机没有具体要求,在通话前通话中皆可。
- 通过 startCameraVideo (opens new window)方法,获取 JRTCMediaDeviceVideoCanvas (opens new window)本地的视频对象。
- 在界面画布上渲染本地视频对象画面。
/**
* 开始自身视频渲染
*
* 获取本端视频预览对象 JRTCMediaDeviceVideoCanvas ,通过此对象能获得视图用于UI显示
* @note
* 调用此方法时需要保证默认摄像头不为空,即 @ref defaultCamera 不为空,否则将直接返回 nil
* @param type 渲染模式:
* - @ref JRTCMediaDeviceRenderFullScreen : 铺满窗口,会有裁剪
* - @ref JRTCMediaDeviceRenderFullContent : 全图像显示,会有黑边
* - @ref JRTCMediaDeviceRenderFullAuto : 自适应
* @return
* - JRTCMediaDeviceVideoCanvas 对象: 开始自身视频渲染成功
* - nil: 开始自身视频渲染失败
*/
- (JRTCMediaDeviceVideoCanvas* __nullable)startCameraVideo:(JRTCMediaDeviceRender)type;
/**
* 开始自身视频渲染
*
* 获取本端视频预览对象 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;/**
* 开始自身视频渲染
*
* 获取本端视频预览对象 JRTCMediaDeviceVideoCanvas ,通过此对象能获得视图用于UI显示
* @note
* 调用此方法时需要保证默认摄像头不为空,即 @ref defaultCamera 不为空,否则将直接返回 nil
* @param type 渲染模式:
* - @ref JRTCMediaDeviceRenderFullScreen : 铺满窗口,会有裁剪
* - @ref JRTCMediaDeviceRenderFullContent : 全图像显示,会有黑边
* - @ref JRTCMediaDeviceRenderFullAuto : 自适应
* @return
* - JRTCMediaDeviceVideoCanvas 对象: 开始自身视频渲染成功
* - nil: 开始自身视频渲染失败
*/
- (JRTCMediaDeviceVideoCanvas* __nullable)startCameraVideo:(JRTCMediaDeviceRender)type;
/**
* 开始自身视频渲染
*
* 获取本端视频预览对象 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 为适应模式:即按画面长边进行缩放以适应显示区域,短边部分会被填充为黑色,此模式下图像完整但可能留有黑边。
示例代码:
// 创建本端视图渲染对象
JRTCMediaDeviceVideoCanvas *canvas = [_mediaDevice startCameraVideo:JRTCMediaDeviceRenderFullContent];
// 设置视图位置与尺寸
canvas.videoView.frame = CGRectMake(0, 0, 100, 100);
// 将渲染视图添加到界面上
[self.view addSubview:canvas.videoView];// 创建本端视图渲染对象
JRTCMediaDeviceVideoCanvas *canvas = [_mediaDevice startCameraVideo:JRTCMediaDeviceRenderFullContent];
// 设置视图位置与尺寸
canvas.videoView.frame = CGRectMake(0, 0, 100, 100);
// 将渲染视图添加到界面上
[self.view addSubview:canvas.videoView];
# 创建远端视频画面
当通话建立后,除了本地的视频画面,还有通话成员的远端视频画面,如果通话成员有视频流的上传,座席端可以获取到其他成员的视频流并进行渲染。 座席可在收到以下回调时进行界面处理:
- 收到 onCallStateChanged (opens new window) 回调且通话状态改为 Talking 时,表示座席加入了通话。
- 收到 onMemberJoin (opens new window) 回调时,表示有其他成员加入通话。
- 收到 onMemberUpdate (opens new window) 回调时,表示通话中用户的通话状态变化。例如,可通过 changeParam.video (opens new window) 属性判断用户视频流状态是否发送改变;当 JRTCRoomParticipant.video (opens new window) 的值为 true ,表示远端用户已上传视频流,本端通过订阅远端视频流,获取远端视图渲染对象。
调用 startVideo (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;/**
* 开始其他端的视频渲染
*
* 获取其他端的视频预览对象 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;
渲染其他用户视图画面的方法法与渲染摄像头画面的用法基本一致,需关注 JRTCMediaDeviceRender (opens new window) 渲染模式。
示例代码:
// 创建其他端视图渲染对象
JRTCMediaDeviceVideoCanvas *canvas = [_mediaDevice startVideo:@"视频流ID" renderType:JRTCMediaDeviceRenderFullContent];
// 设置视图位置与尺寸
canvas.videoView.frame = CGRectMake(0, 0, 100, 100);
// 将渲染视图添加到界面上
[self.view addSubview:canvas.videoView];// 创建其他端视图渲染对象
JRTCMediaDeviceVideoCanvas *canvas = [_mediaDevice startVideo:@"视频流ID" renderType:JRTCMediaDeviceRenderFullContent];
// 设置视图位置与尺寸
canvas.videoView.frame = CGRectMake(0, 0, 100, 100);
// 将渲染视图添加到界面上
[self.view addSubview:canvas.videoView];
# 结束通话
当业务办理结束,访客可以主动结束通话,座席也可以通过 term (opens new window) 方法来主动结束通话。
/**
* 结束通话
*
* 来电过程中调用此接口拒绝接听,访客分配到其他座席继续呼叫等待不会挂断。<br>
* 主座席调用此接口会结束通话,通话中所有成员都会离开,此通通话销毁,所有成员会收到 {@link JRTCAgentCallback.onCallStateChanged:incomingType:inviter:reason: onCallStateChanged} 或 {@link JRTCGuestCallback.onCallStateChanged:incomingType:inviter:termReason: onCallStateChanged} 通话结束回调。<br>
* 第三方座席调用此接口仅自身离开通话,通话中其他成员会收到该成员离开的回调 {@link JRTCGuestCallback.onMemberLeave: onMemberLeave} 或 {@link JRTCAgentCallback.onMemberLeave: onMemberLeave} 回调,通话继续进行。
* @return 接口调用结果
* - true: 接口调用成功,会收到 {@link JRTCAgentCallback.onCallStateChanged:incomingType:inviter:reason: onCallStateChanged} 回调
* - false: 接口调用异常
*/
- (bool)term;/**
* 结束通话
*
* 来电过程中调用此接口拒绝接听,访客分配到其他座席继续呼叫等待不会挂断。<br>
* 主座席调用此接口会结束通话,通话中所有成员都会离开,此通通话销毁,所有成员会收到 {@link JRTCAgentCallback.onCallStateChanged:incomingType:inviter:reason: onCallStateChanged} 或 {@link JRTCGuestCallback.onCallStateChanged:incomingType:inviter:termReason: onCallStateChanged} 通话结束回调。<br>
* 第三方座席调用此接口仅自身离开通话,通话中其他成员会收到该成员离开的回调 {@link JRTCGuestCallback.onMemberLeave: onMemberLeave} 或 {@link JRTCAgentCallback.onMemberLeave: onMemberLeave} 回调,通话继续进行。
* @return 接口调用结果
* - true: 接口调用成功,会收到 {@link JRTCAgentCallback.onCallStateChanged:incomingType:inviter:reason: onCallStateChanged} 回调
* - false: 接口调用异常
*/
- (bool)term;
主动和被动的挂断事件与来电、接通一样,都通过 JRTCAgentCallback (opens new window) 的 onCallStateChanged (opens new window) 接口上报。 其中 CallTermReason (opens new window) 可以用来判断挂断原因,如:主动挂断、对端挂断等。
示例代码:
// 坐席主动结束通话
[_agent term];
// 通话状态改变回调
- (void)onCallStateChanged:(AgentCallStateChangeType)type incomingType:(CallIncomingType)incomingType inviter:(nullable JRTCInviter *)inviter reason:(CallTermReason)reason {
if (type == AgentCallStateChangeTypeTermed) {
// 通话结束,结束原因查看 reason
}
}// 坐席主动结束通话
[_agent term];
// 通话状态改变回调
- (void)onCallStateChanged:(AgentCallStateChangeType)type incomingType:(CallIncomingType)incomingType inviter:(nullable JRTCInviter *)inviter reason:(CallTermReason)reason {
if (type == AgentCallStateChangeTypeTermed) {
// 通话结束,结束原因查看 reason
}
}
# 销毁本地和远端视频画面
当不再需要查看视频画面,或者通话结束,需要 JRTCMediaDevice (opens new window) 对象的 stopVideo (opens new window) 方法来释放渲染资源。 该方法需传入要释放的 JRTCMediaDeviceVideoCanvas (opens new window) 对象。必须进行这步操作,不然会造成渲染内存不释放。
/**
* 停止视频渲染
* @param canvas JRTCMediaDeviceVideoCanvas 对象,由 {@link startVideo:renderType: startVideo} 或 {@link startCameraVideo: startCameraVideo} 接口返回
*/
- (void)stopVideo:(JRTCMediaDeviceVideoCanvas* __nonnull)canvas;/**
* 停止视频渲染
* @param canvas JRTCMediaDeviceVideoCanvas 对象,由 {@link startVideo:renderType: startVideo} 或 {@link startCameraVideo: startCameraVideo} 接口返回
*/
- (void)stopVideo:(JRTCMediaDeviceVideoCanvas* __nonnull)canvas;
示例代码:
// 通话结束
- (void)onCallStateChanged:(AgentCallStateChangeType)type incomingType:(CallIncomingType)incomingType inviter:(nullable JRTCInviter *)inviter reason:(CallTermReason)reason {
if (type == AgentCallStateChangeTypeTermed) {
[_mediaDevice stopVideo:_localCanvas];
[_mediaDevice stopVideo:_remoteCanvas];
}
}
// 成员离开
- (void)onMemberLeave:(JRTCRoomParticipant *)part {
// 停止远端坐席的画面渲染
[_mediaDevice StopVideo:_remoteCanvas];
}// 通话结束
- (void)onCallStateChanged:(AgentCallStateChangeType)type incomingType:(CallIncomingType)incomingType inviter:(nullable JRTCInviter *)inviter reason:(CallTermReason)reason {
if (type == AgentCallStateChangeTypeTermed) {
[_mediaDevice stopVideo:_localCanvas];
[_mediaDevice stopVideo:_remoteCanvas];
}
}
// 成员离开
- (void)onMemberLeave:(JRTCRoomParticipant *)part {
// 停止远端坐席的画面渲染
[_mediaDevice StopVideo:_remoteCanvas];
}
# 登出
结束通话后,可以做登出操作,与平台断开一切连接。 登出接口调用流程如下所示:
调用 logout (opens new window)接口登出 Juphoon RTC 平台。
/**
* 登出 Juphoon RTC 平台,登出后不能进行平台上的各种业务
*
* 登出结果通过 {@link JRTCClientCallback.onLogout: onLogout} 回调通知
* @return 接口调用结果
* - true: 接口调用成功
* - false: 接口调用异常
*/
- (bool)logout;/**
* 登出 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;/**
* 登出回调
* @param reason 登出原因
*/
- (void)onLogout:(ReasonCode)reason;
示例代码:
// 调用登出接口
[_client logout];
// 监听登出结果回调
- (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;/**
* 登录状态变化通知
* @param state 当前状态值
* @param oldState 之前状态值
*/
- (void)onClientStateChanged:(JRTCClientState)state oldState:(JRTCClientState)oldState;
登录状态详见 JRTCClientState (opens new window) :
示例代码:
//登录状态改变通知
- (void)onClientStateChanged:(JRTCClientState)state oldState:(JRTCClientState)oldState {
//state 当前状态
//oldState 之前状态
}//登录状态改变通知
- (void)onClientStateChanged:(JRTCClientState)state oldState:(JRTCClientState)oldState {
//state 当前状态
//oldState 之前状态
}
# 销毁 SDK
每个模块都有对应的销毁接口。如不需再使用 SDK 的相关功能,可以强制释放 SDK 的资源。 注:该方法为同步调用,调用此方法后,你将无法再使用该模块的其它方法和回调。 我们不建议在 JRTCSDK 的所有回调方法中调用此方法销毁对象,否则可能出现崩溃现象。
+ (void)destroy;+ (void)destroy;
示例代码:
- (void)destroySDK {
[JRTCAgent destroy];
[JRTCMediaDevice destroy];
[JRTCClient destroy];
}- (void)destroySDK {
[JRTCAgent destroy];
[JRTCMediaDevice destroy];
[JRTCClient destroy];
}