# 实现视频通话
本文档为您展示通过 SDK 实现视频通话(坐席侧)的相关步骤,帮助您在远程银行和视频客服的场景下实现智能排队、坐席转接、全景录像、坐席管理的相关能力。
# 1. 前提条件
请确认您已完成以下操作:
- 已获取 App Key。
AppKey 作为同个环境的分域依据,同一个域的终端才能实现互通,AppKey 由 Juphoon 视频平台提供。
TIP
请扫描下方二维码联系 Juphoon 市场售前工程师获取 AppKey。

集成 SDK(Windows Java)。
TIP
如需集成指导,请扫描上方二维码联系 Juphoon 市场售前工程师获取相关咨询。
# 2. 快速跑通 Sample
- 在Juphoon RTC SDK 文档中心,选择视频客服-座席选择项,在 SDK 下载页面下载体验 Sample 示例项目。访问下载地址 (opens new window),示例如下:
- 下载完成后,打开安装包,解压 JCCSample:
- Windows
双击安装 JCCSampleSetup-java.exe
- UOS-X86 和 UOS-ARM
需要依赖 jre 运行环境(请提前安装),然后
a. 在终端 cd 到 Program 目录下;
b. chmod 777 ./start.sh,修改程序运行权限;
c. ./start.sh,运行程序,出现 Sample 主界面;
打开应用程序后,设置正确的 appkey,环境地址以及账号。
a. 首先点击初始化按钮,成功后,登录按钮变为可点击;
b. 确认账号输入无误之后,点击登录按钮,按钮字样变为登出,即登录成功;
c. 点击座席按钮,即可进入对应座席页面;
- 进入座席页面后,点击签入即可回呼访客及等待访客来电
# 3. 实现视频通话(视频客服)
# 初始化 SDK
注:我们所有的方法都建议在 UI 线程调用,否则可能会出现异常无法正常使用,回调接口也都在 UI 线程上报。
在使用业务接口前,需对 Juphoon SDK 进行初始化操作。
JRTCClient (opens new window) | 基础模块 | 负责视频平台的登录登出,只有登录到视频平台才可以使用视频相关的业务,AppKey 作为同个环境的分域依据,同一个域的终端才能实现互通。 |
---|---|---|
JRTCMediaDevice (opens new window) | 媒体模块 | 负责本地的媒体设备操作,视频画面渲染等功能。 |
JRTCAgent (opens new window) | 座席模块 | 负责座席的视频业务的处理,比如接听来电,控制音视频流等 这些模块初始化的时候需要有 callback 作为入参来监听各模块的事件 |
JRTCRecord (opens new window) | 录制模块 | 负责分片录制与上传 |
注:Agent 座席模块和 Guest 访客模块只支持初始化一个,否则会出现接收不到呼叫,接收不到邀请等现象影响正常的业务流程。
初始化参数详见 JRTCClientInitParam (opens new window)。
示例代码:
class JRTCManager implements JRTCClientCallback, JRTCGuestCallback,
JRTCMediaDeviceCallback {
public void init() {
JRTCClientInitParam param = new JRTCClientInitParam();
/**
* 设置应用名称,比如:菊风访客
*/
param.setAppName("appName");
/**
* 设置SDK信息存储目录,该目录下的log目录为日志目录
*/
param.setSdkInfoDir("sdkInfoDir");
/**
* 设置SDK dll库的放置目录
*/
param.setSdkInfoDir("sdkLibPath")
/**
* 设置AppKey
* 用户从 Juphoon RTC 平台上申请的 AppKey 字符串
*/
param.setAppKey("appKey");
/**
* 设置接入服务器地址
*/
param.setServer("server");
/**
* 设置是否需要自动加载so库,默认true
*/
param.setLoadLibrary(true);
/**
* 设置是否控制台日志输出, 默认true
*/
param.setLogConsole(true);
/**
* 获取是否是否本地文件日志输出, 默认true
*/
param.setLogLocalFile(true);
/**
* 设置是否开启 RPC 抗信令丢包控制(70%的上下行信令丢包), 默认false
*/
param.setLooseTimeoutControl(true);
/**
* 是否使用hik,如果使用将会在初始化时初始化海康资源
*
* @param useHik 是否使用海康
* - tue 使用,并初始化
* - false 不使用,不初始化
*/
param.setUseHik(true);
/**
* 是否使用dahua,如果使用将会在初始化时初始化大华资源
*
* @param useDahua 是否使用海康
* - tue 使用,并初始化
* - false 不使用,不初始化
*/
param.setUseDahua(true);
client = JRTCClient.create(context, this, param);
mediaDevice = JRTCMediaDevice.create(client, this, null);
record = JRTCRecord.create(client, mediaDevice, mRecordCallback);
agent = JRTCAgent.create(client, mediaDevice, this);
//设置基本参数
client.setServer("server");
client.setAppKey("appKey");
client.setDisplayName("displayName");
client.setAppName("appName");
}
}
然后根据 idea 提示将 interface 的接口实现补全即可。
# 登录
SDK 初始化之后,即可进行登录的集成,登录接口调用流程如下所示:
登录到 Juphoon 视频平台主要调用的是 JRTCClient 的登录接口 login (opens new window)。
/**
* 登录 Juphoon RTC 平台,只有登录成功后才能进行平台上的各种业务<br>
* 登录结果通过 JRTCClientCallback 通知<br>
*
* @param userId 用户名
* @param password 密码,不能为空
* @return 返回 true 表示正常执行调用流程,false 表示调用异常,异常错误通过 JRTCClientCallback 通知
* @note 目前只支持免鉴权模式,服务器不校验账号密码,免鉴权模式下当账号不存在时会自动去创建该账号
* @note 注意:用户名为英文数字和'+' '-' '_' '.',长度不要超过64字符,'-' '.' '_'字符不能处于第一位<br>
*/
public abstract boolean login(String userId, String password);
/**
* 登录 Juphoon RTC 平台,只有登录成功后才能进行平台上的各种业务<br>
* 登录结果通过 JRTCClientCallback 通知<br>
*
* @param userId 用户名
* @param password 密码,不能为空
* @param clientLoginParam 登录校验参数,传 null 则按默认值。一般不需要设置,如需设置请询问客服
* @return 返回 true 表示正常执行调用流程,false 表示调用异常,异常错误通过 JRTCClientCallback 通知
* @note 目前只支持免鉴权模式,服务器不校验账号密码,免鉴权模式下当账号不存在时会自动去创建该账号
* @note 注意:用户名为英文数字和'+' '-' '_' '.',长度不要超过64字符,'-' '.' '_'字符不能处于第一位<br>
*/
public abstract boolean login(String userId, String password, JRTCClientLoginParam clientLoginParam);
/**
* 重登录,该接口在如果有其他同类型终端登录着则会登录失败,一般用于记住了账号后重启自动登录逻辑
*
* @param userId 用户名
* @param password 密码,不能为空
* @return 返回 true 表示正常执行调用流程,false 表示调用异常,异常错误通过 JRTCClientCallback 通知
*/
public abstract boolean reLogin(String userId, String password);
JRTCClientLoginParam (opens new window) 属性介绍
属性 | 描述 |
---|---|
setAccountEntry | 设置账户分录参数,如果支持国密S3则需要设置 certificate 参数,否则可以不设置 certificate 参数 |
setCertificate | 设置 S3 国密证书 Base64 编码内容 |
setAcceptExpiredCertificate | 设置是否允许过期证书校验通过 |
setToken | 设置token |
setTokenType | 设置 token 校验类型 |
setDeviceId | 设置设备id |
setLogFilter | 设置日志过滤标签(用于日志管理平台过滤终端日志使用) |
setTerminalType | 设置终端登录类型,支持多终端登录,默认所有终端相同会导致互踢 |
setAutoCreateAccount | 是否自动创建账号(免鉴权使用),默认true |
setAccelerateKey | 设置加速云KEY |
setAccelerateKeySecret | 设置加速云KEY密钥 |
登录的结果将会通过 JRTCClientCallback (opens new window) 的接口上报:
/**
* 登录结果回调
*
* @param result true 表示登录成功,false 表示登录失败
* @param reason 当 result 为 false 时该值有效
*/
void onLogin(boolean result, @JRTCEnum.ReasonCode int reason);
示例代码:
// 创建登录配置参数
JRTCClientLoginParam loginParam = new JRTCClientLoginParam();
// 登录
client.login("juphoon", "123456", loginParam);
public void onLogin(boolean result, @ReasonCode int reason) {
if(result) {
// 登录成功
} else {
// 登录失败,具体原因查询 reason 错误码
}
}
# 获取业务号列表
调用 queryAllGroups (opens new window) 可以获取业务号列表。
/**
* 获取业务号列表
*
* @return 接口调用结果
* - true: 接口调用成功,返回结果通过 {@link JRTCAgentCallback#onGetAllGroups onGetAllGroups} 回调上报
* - false: 接口调用异常
*/
public abstract boolean queryAllGroups();
获取业务号信息通过实现 JRTCAgentCallback (opens new window) 中的 onGetAllGroups (opens new window) 接口上报。
/**
* 获取业务号列表结果回调
* <p>
* 座席调用 {@link JRTCAgent#queryAllGroups queryAllGroups} 接口获取业务号列表,会收到此回调。
*
* @param groups 座席业务实体对象列表,获取失败时为 null
* @param result 获取结果
* - true: 获取成功
* - false: 获取失败
*/
void onGetAllGroups(boolean result, List<JRTCCallCenterGroupItem> groups);
示例代码:
//获取业务号列表
agent.queryAllGroups();
public void onGetAllGroups(boolean result, List<JRTCCallCenterGroupItem> groups) {
if(result) {
//获取成功
} else {
//获取失败
}
}
# 查询指定业务号的空闲座席
通过业务号查询空闲的座席,详见 queryAvailableAgentList (opens new window)
/**
* 查询指定业务号的空闲座席
* <p>
* 查询结果通过 {@link JRTCAgentCallback#onQueryAvailableAgentList onQueryAvailableAgentList} 回调上报
*
* @param businessNumber 业务号,例如 10087
* @return 操作id,与 {@link JRTCAgentCallback#onQueryAvailableAgentList onQueryAvailableAgentList} 的 operationId 参数对应
*/
public abstract int queryAvailableAgentList(String businessNumber);
查询指定业务号的空闲座席查询结果通过实现 onQueryAvailableAgentList (opens new window) 接口上报:
/**
* 查询空闲座席结果回调
* <p>
* 座席调用 {@link JRTCAgent#queryAvailableAgentList queryAvailableAgentList} 接口查询空闲座席成功时,会收到此回调。
*
* @param operationId 操作id,对应 {@link JRTCAgent#queryAvailableAgentList queryAvailableAgentList} 接口的返回值
* @param result 查询结果
* - true: 查询成功
* - false: 查询失败
* @param userIds 查询到的空闲座席列表
*/
void onQueryAvailableAgentList(int operationId, boolean result, List<String> userIds);
示例代码:
//查询业务号为10086的空闲座席列表
agent.queryAvailableAgentList("10086");
void onQueryAvailableAgentList(int operationId, boolean result, List<String> userIds) {
if (result) {
// 查询成功,具体查看 userIds
} else {
// 查询失败
}
}
# 座席签入
登录视频能力平台成功后,需要签入到排队机才能进行业务(回呼访客和接收访客呼叫)。
/**
* 签入
* <p>
* 签入到排队机,签入后示忙/示闲状态由 busy 参数决定 <br>
* 示闲状态下正常呼叫进线 <br>
* 调用接口前确定 JRTCClient 登录成功 <br>
* 调用该接口前需先确定 {@link #getOperatorState operatorState} 来获取到当前的签入状态
*
* @param userId 座席用户ID,需与业务管理平台上配置的座席staffId对应,如果传空,则默认用当前登录用户ID签入
* @param busy 签入后示忙/示闲状态
* - true: 示忙
* - false: 示闲
* @oaram checkinParam 签入其他参数
* @return 接口调用结果
* - true: 接口调用成功,签入结果会触发 {@link JRTCAgentCallback#onCheckin onCheckin} 回调上报
* - false: 接口调用异常
*/
public abstract boolean checkin(String userId, boolean busy, JRTCAgentCheckinParam checkinParam);
/**
* 签入
* <p>
* 签入到排队机,签入后示忙/示闲状态由 busy 参数决定 <br>
* 示闲状态下正常呼叫进线 <br>
* 调用接口前确定 JRTCClient 登录成功 <br>
* 调用该接口前需先确定 {@link #getOperatorState operatorState} 来获取到当前的签入状态
*
* @param userId 座席用户ID,需与业务管理平台上配置的座席staffId对应
* @param role 座席角色类型,目前该参数已有服务端控制,不再通过终端设置,可忽略
* @param busy 签入后示忙/示闲状态
* - true: 示忙
* - false: 示闲
* @return 接口调用结果
* - true: 接口调用成功,签入结果会触发 {@link JRTCAgentCallback#onCheckIn onCheckIn} 回调上报
* - false: 接口调用异常
* @deprecated 请使用 {@link #checkin(String, boolean, JRTCAgentCheckinParam) checkin} 代替
*/
@Deprecated
public abstract boolean checkIn(String userId, @AgentRoleType int role, boolean busy);
/**
* 签入
* <p>
* 签入到排队机,签入后默认示闲状态 <br>
* 示闲状态下正常呼叫进线 <br>
* 调用接口前确定 JRTCClient 登录成功 <br>
* 调用该接口前需先确定 {@link #getOperatorState operatorState} 来获取到当前的签入状态
*
* @param userId 座席用户ID,需与业务管理平台上配置的座席staffId对应
* @param role 座席角色类型,目前该参数已有服务端控制,不再通过终端设置,可忽略
* @return 接口调用结果
* - true: 接口调用成功,签入结果会触发 {@link JRTCAgentCallback#onCheckIn onCheckIn} 回调上报
* - false: 接口调用异常
* @deprecated 请使用 {@link #checkin(String, boolean, JRTCAgentCheckinParam) checkin} 代替
*/
@Deprecated
public abstract boolean checkIn(String userId, @AgentRoleType int role);
/**
* 签入
* <p>
* 签入到排队机,签入后默认示闲状态 <br>
* 示闲状态下正常呼叫进线 <br>
* 调用接口前确定 JRTCClient 登录成功 <br>
* 调用该接口前需先确定 {@link #getOperatorState operatorState} 来获取到当前的签入状态 <br>
* 该方法座席用户ID默认为 {@link JRTCClient#getUserId userId} ,与业务管理平台上配置的座席staffId对应
*
* @param role 座席角色类型,目前该参数已有服务端控制,不再通过终端设置,可忽略
* @return 接口调用结果
* - true: 接口调用成功,签入结果会触发 {@link JRTCAgentCallback#onCheckIn onCheckIn} 回调上报
* - false: 接口调用异常
* @deprecated 请使用 {@link #checkin(String, boolean, JRTCAgentCheckinParam) checkin} 代替
*/
@Deprecated
public abstract boolean checkIn(@AgentRoleType int role);
签入方法包含几个重载,用来适应各种可配置的参数,比如签入后默认为示闲还是示忙、比如座席的角色。这些方法的需结合具体的需求来使用。
签入结果通过 JRTCAgentCallback (opens new window) 的 onCheckIn (opens new window) 接口上报。
/**
* 签入回调
* <p>
* 座席调用 {@link JRTCAgent#checkIn checkIn} 接口成功,会收到此回调。
*
* @param result 签入结果
* - true: 签入成功
* - false: 签入失败
* @param pause 签入后的示闲/示忙状态
* - true: 签入后示忙
* - false: 签入后示闲
* @param onlineTime 座席累计在线时长
* @param breakTime 座席累计示忙时长
* @param callTimes 通话次数
* @param reason 签入失败原因
* @deprecated 该回调方法即将废弃,请使用 {@link #onCheckin(boolean, boolean, String)} onCheckin} 代替
*/
@Deprecated
void onCheckIn(boolean result, boolean pause, long onlineTime, long breakTime, long callTimes, int reason);
/**
* 签入回调
* <p>
* 座席调用 {@link JRTCAgent#checkin checkin} 接口成功,会收到此回调。
*
* @param result 签入结果
* - true: 签入成功
* - false: 签入失败
* @param pause 签入后的示闲/示忙状态
* - true: 签入后示忙
* - false: 签入后示闲
* @param reason 失败原因
*/
void onCheckin(boolean result, boolean pause, String reason);
示例代码:
// 签入,签入后为示闲状态
agent.checkIn(client.getUserId(), JRTCCallCenter.AGENT_ROLE_ADMINISTRATOR, false);
// 签入结果回调
void onCheckIn(boolean result, boolean pause, long onlineTime, long breakTime, long callTimes, long callTime, int reason) {
if (result) {
// 签入成功
} else {
// 签入失败
}
}
# 座席签出
当所有业务处理完毕,座席可以调用 JRTCAgent (opens new window) 对象中的 checkout (opens new window) 方法签出排队机,将不会再收到终端业务,业务管理平台上该座席的状态将变为离线。
/**
* 签出
* <p>
* 签出后将不会收到排队机的呼叫分配 <br>
* 签出排队机不影响 JRTCClient 的登录状态 <br>
* 调用 {@link #getOperatorState operatorState} 可获取当前签入状态
*
* @return 接口调用结果
* - true: 接口调用成功,签出结果通过 {@link JRTCAgentCallback#onCheckout onCheckout} 回调上报
* - false: 接口调用异常
*/
public abstract boolean checkout();
结果通过 JRTCAgentCallback (opens new window) 的 onCheckout (opens new window) 接口上报:
/**
* 签出回调
* <p>
* 座席调用 {@link JRTCAgent#checkout checkout} 接口签出排队机,会收到此回调。
*
* @param result 签出结果
* - true: 签出成功
* - false: 签出失败
* @param reason 签出原因
*/
void onCheckout(boolean result, @JRTCAgent.AgentCheckoutReason int reason);
座席签出原因详见 AgentCheckoutReason (opens new window) 。
示例代码:
//座席签出
agent.checkout();
void onCheckout(boolean result, @JRTCAgent.AgentCheckoutReason int reason) {
if(result) {
// 签出成功
} else {
// 签出失败
}
}
# 座席签入签出状态改变
座席签入状态发生变化就会通过 JRTCAgentCallback (opens new window) 的 onCheckStateChanged (opens new window) 接口上报。
/**
* 签出状态改变
*
* @param currState 当前座席状态
* @param oldState 旧的座席状态
*/
void onCheckStateChanged(@JRTCAgent.AgentOperatorState int currState, @JRTCAgent.AgentOperatorState int oldState);
座席状态详见 AgentOperatorState (opens new window)。
示例代码:
public void onCheckStateChanged(@JRTCAgent.AgentOperatorState int currState, @JRTCAgent.AgentOperatorState int oldState) {
if (currState == AGENT_OPERATOR_CHECKING_IN) {
//正在签入中
} else if (currState == AGENT_OPERATOR_CHECKED_IN) {
//已签入
} else if (currState == AGENT_OPERATOR_CHECKING_OUT) {
//已签出
} else if (currState == AGENT_OPERATOR_IDLE) {
//签入失败
}
}
# 获取座席签入状态
通过 getOperatorState (opens new window) 获取座席签入状态。
/**
* 获取座席签入状态
*
* @return 座席签入状态
*/
@AgentOperatorState
public abstract int getOperatorState();
# 示忙示闲
通过调用 JRTCAgent (opens new window) 对象的 applyStatePause (opens new window) 方法来切换该状态。
- 示忙:座席暂停服务,访客无法呼到该座席
- 示闲:座席保持服务,访客可以呼到该座席
/**
* 示忙/示闲
* <p>
* 示忙状态下不会收到呼叫来电,示闲状态下正常呼叫进线 <br>
* 通话过程中调用该接口不会影响当前通话,从下个通话开始状态生效 <br>
* 示忙/示闲的结果通过 {@link JRTCAgentCallback#onApplyResult onApplyResult} 回调上报
*
* @param pause 示忙或是示闲
* - true: 示忙
* - false: 示闲
* @return 接口调用结果
* - > 0: 操作id,对应 {@link JRTCAgentCallback#onApplyResult onApplyResult} 回调的 operationId 参数
* - -1: 接口调用异常
*/
public abstract int applyStatePause(boolean pause);
/**
* 示忙/示闲
* <p>
* 示忙状态下不会收到呼叫来电,示闲状态下正常呼叫进线 <br>
* 通话过程中调用该接口不会影响当前通话,从下个通话开始状态生效 <br>
* 示忙/示闲的结果通过 {@link JRTCAgentCallback#onApplyResult onApplyResult} 回调上报
*
* @param pause 示忙或是示闲
* - true: 示忙
* - false: 示闲
* @param subState 子状态,报表数据统计需要,取值[0, 9]
* - 0: 默认子状态
* - 1~9: 自定义子状态
* @return 接口调用结果
* - > 0: 操作id,对应 {@link JRTCAgentCallback#onApplyResult onApplyResult} 回调的 operationId 参数
* - -1:接口调用异常
*/
public abstract int applyStatePause(boolean pause, int subState);
如果需要在通话结束后设置默认示闲示忙,可以通过调用调用 JRTCAgent (opens new window) 对象的 setTermState (opens new window) 方法实现
/**
* 获取结束通话后的示闲/示忙状态,默认为示闲状态
*
* @return 通话结束后状态
*/
@AgentTermState
public abstract int getTermState();
/**
* 设置通话结束后示闲/示忙状态,默认为示闲状态
*
* @param state 示闲/示忙状态
*/
public abstract void setTermState(@AgentTermState int state);
示忙示闲结果通过 JRTCAgentCallback (opens new window) 的 onApplyResult (opens new window) 接口上报:
/**
* 示忙/示闲回调
* <p>
* 座席示忙/示闲状态发生改变时,会收到此回调,例如调用 {@link JRTCAgent#applyStatePause applyStatePause} 接口修改忙闲状态。 <br>
* 可以通过 {@link JRTCAgent#isPause pause} 获取当前的忙闲状态。
*
* @param operationId 对应 {@link JRTCAgent#applyStatePause applyStatePause} 接口的返回值
* @param result 示忙/示闲结果
* - true: 示忙/示闲成功
* - false: 示忙/示闲失败
*/
void onApplyResult(int operationId, boolean result);
还可以调用 isPause (opens new window) 查询当前示闲示忙的状态:
/**
* 示忙/示闲回调
* <p>
* 座席示忙/示闲状态发生改变时,会收到此回调,例如调用 {@link JRTCAgent#applyStatePause applyStatePause} 接口修改忙闲状态。 <br>
* 可以通过 {@link JRTCAgent#isPause pause} 获取当前的忙闲状态。
*
* @param operationId 对应 {@link JRTCAgent#applyStatePause applyStatePause} 接口的返回值
* @param result 示忙/示闲结果
* - true: 示忙/示闲成功
* - false: 示忙/示闲失败
* @param subState 当前子状态,当 result 为 true 时有效
*/
void onApplyResult(int operationId, boolean result, int subState);
示例代码:
//座席示忙
agent.applyStatePause(true);
//座席示忙示闲结果
public void onApplyResult(int operationId, boolean result) {
if (result) {
// 示忙示闲的操作成功
}
// 获取当前的忙闲状态
agent.isPause();
}
# 座席回呼
座席可以通过调用 recall (opens new window) 接口回呼访客。
/**
* 座席回呼
*
* @param userId 访客用户ID
* @param callParam 呼叫参数设置,此参数可传 null 则使用默认配置,详见 {@link JRTCCallCenterCallParam}
* @return 接口调用结果
* - true: 接口调用成功,通话状态会通过 {@link JRTCAgentCallback#onCallStateChanged onCallStateChanged} 回调上报
* - false: 接口调用异常
*/
public abstract boolean recall(String userId, JRTCCallCenterCallParam callParam);
示例代码:
// 座席回呼
JRTCCallCenterCallParam callParam = new JRTCCallCenterCallParam();
callParam.setExtraInfo("测试");
//callParam 其他参数设置
agent.recall("guestUserId", callParam);
# 接听来电
在座席收到来电的通知后,可以通过调用 answer (opens new window) 接口来接起访客的呼叫;
来电类型详见 CallIncomingType (opens new window)
CALL_INCOMING_TYPE_CALL (opens new window):普通来电,访客调用 call (opens new window) 接口呼叫;
CALL_INCOMING_TYPE_INVITE (opens new window):三方邀请来电,座席调用 inviteThirdAgent (opens new window) 接口邀请三方座席;
CALL_INCOMING_TYPE_FORWARD (opens new window):转接来电,座席调用 transferCall (opens new window) 接口转接当前通话;
CALL_INCOMING_TYPE_DIRECT_CALL (opens new window):直呼来电,访客调用 oneToOneCall (opens new window) 接口进行直呼座席;
/**
* 接听
* <p>
* 主座席、第三方座席或是被转接的座席,都调用此接口接听通话 <br>
*
* @return 接口调用结果
* - true: 接口调用成功,会收到 {@link JRTCAgentCallback#onCallStateChanged onCallStateChanged} 回调
* - false: 接口调用异常
*/
public abstract boolean answer();
示例代码:
public void onCallStateChanged(@JRTCAgent.AgentCallStateChangeType int type, @JRTCAgent.CallIncomingType int incomingType, JRTCInviter inviter, @JRTCAgent.CallTermReason int reason) {
if (type == AGENT_CHANGE_TYPE_INCOMING) {
if (incomingType == CALL_INCOMING_TYPE_CALL) {
// 普通呼叫来电
} else if (incomingType == CALL_INCOMING_TYPE_INVITE) {
// 三方邀请来电
} else if (incomingType == CALL_INCOMING_TYPE_FORWARD) {
// 转接来电
} else if (incomingType == CALL_INCOMING_TYPE_DIRECT_CALL) {
// 直呼来电
}
// 接听
agent.answer();
}
}
接听的结果同样通过 JRTCAgentCallback (opens new window) 的 onCallStateChanged (opens new window) 接口上报通话状态改变。
# 通话状态改变通知
座席签入成功后即为一个等待通话接入的状态,具体的通话由排队机进行分配,
- 访客呼叫场景:
- 座席收到来电,通话状态就改变为 AGENT_CHANGE_TYPE_INCOMING (opens new window);
- 座席接听,成功进入通话,通话状态改变为 AGENT_CHANGE_TYPE_TALKING (opens new window);
- 座席挂断或者其他成员挂断导致通话结束,通话状态改变为 AGENT_CHANGE_TYPE_TERMED (opens new window);
回呼场景
- 座席回呼访客,通话状态就改变为 AGENT_CHANGE_TYPE_CALLING (opens new window)
- 访客接听,成功进入通话,通话状态改变为 AGENT_CHANGE_TYPE_TALKING (opens new window);
- 座席挂断或者其他成员挂断导致通话结束,通话状态改变为 AGENT_CHANGE_TYPE_TERMED (opens new window)
通过 JRTCAgentCallback (opens new window) 的 onCallStateChanged (opens new window) 的接口上报:
/**
* 通话状态改变回调
*
* @param type 通话状态改变类型,即以下情况会收到此回调:
* - {@link JRTCAgent#AGENT_CHANGE_TYPE_INCOMING AGENT_CHANGE_TYPE_INCOMING} 收到来电(访客呼叫、座席邀请、转接)
* - {@link JRTCAgent#AGENT_CHANGE_TYPE_TALKING AGENT_CHANGE_TYPE_TALKING} 通话接通
* - {@link JRTCAgent#AGENT_CHANGE_TYPE_TERMED AGENT_CHANGE_TYPE_TERMED} 通话挂断或被挂断
* @param incomingType 来电类型,当 type == {@link JRTCAgent#AGENT_CHANGE_TYPE_INCOMING AGENT_CHANGE_TYPE_INCOMING} 时有效
* @param inviter 邀请成员对象,当 type == {@link JRTCAgent#AGENT_CHANGE_TYPE_INCOMING AGENT_CHANGE_TYPE_INCOMING} 时有效
* @param reason 挂断原因,只在 type 为 {@link JRTCCallCenter#AGENT_CHANGE_TYPE_TERMED AGENT_CHANGE_TYPE_TERMED} 时需要关注,详见 {@link JRTCAgent.CallTermReason CallTermReason}
*/
void onCallStateChanged(@JRTCAgent.AgentCallStateChangeType int type, @JRTCAgent.CallIncomingType int incomingType, JRTCInviter inviter, @JRTCAgent.CallTermReason int reason);
通话状态改变详见 AgentCallStateChangeType (opens new window) 。
通话结束原因详见 CallTermReason (opens new window)。
示例代码:
public void onCallStateChanged(@JRTCAgent.AgentCallStateChangeType int type, @JRTCAgent.CallIncomingType int incomingType, JRTCInviter inviter, @JRTCAgent.CallTermReason int reason) {
if (type == AGENT_CHANGE_TYPE_INCOMING) {
// 来电
} else if (type == AGENT_CHANGE_TYPE_TALKING) {
// 通话建立
} else if (type == AGENT_CHANGE_TYPE_TERMED) {
// 通话结束
} else if (type == AGENT_CHANGE_TYPE_CALLING) {
// 正在呼叫(座席回呼)
}
}
# 获取通话状态
可通过调用 getCallState (opens new window) 方法获取当前通话状态,通话状态改变详见 CallState (opens new window)
/**
* 获取当前通话状态
*
* @return 当前通话状态
*/
@CallState
public abstract int getCallState();
示例代码:
@CallState int callState = agent.getCallState();
if (callState == CALL_STATE_IDLE) {
// 空闲状态
} else if (callState == CALL_STATE_INCOMING) {
// 收到来电
} else if (callState == CALL_STATE_TALKING) {
// 通话中
} else if (callState == CALL_STATE_CALLING) {
// 呼叫中(回呼场景)
}
# 创建本地视频画面
初始化成功后,可以创建本地的视频画面,创建本地视频画面的时机没有具体要求,在通话前通话中皆可。
- 通过调用 JRTCMediaDevice (opens new window) 里的 startCameraVideo (opens new window) 方法获取本地的视频对象。
- 通过 startCameraVideo (opens new window) 方法里传入渲染的画布的句柄进行视频画面渲染;
/**
* 开始本端视频渲染
* @note 该接口默认在 native 层使用硬件渲染,部分机型可能不支持
* <p>
* 获取本端视频预览对象 JRTCMediaDeviceVideoCanvas,通过此对象能获得视图用于UI显示
*
* @param view 视频窗口句柄
* @param camera 摄像头对象
* @param renderType 渲染模式:
* - {@link #RENDER_FULL_SCREEN RENDER_FULL_SCREEN} : 铺满窗口,会有裁剪
* - {@link #RENDER_FULL_CONTENT RENDER_FULL_CONTENT} : 全图像显示,会有黑边
* - {@link #RENDER_FULL_AUTO RENDER_FULL_AUTO} : 自适应
* @return - JRTCMediaDeviceVideoCanvas 对象: 开始自身视频渲染成功
* - null: 开始自身视频渲染失败
*/
public abstract JRTCMediaDeviceVideoCanvas startCameraVideo(int view, JRTCMediaDeviceCamera camera, @RenderType int renderType);
/**
* 开始本端视频渲染
* @note 该接口默认在 java 层进行渲染,兼容性较好
* <p>
* 获取本端视频预览对象 JRTCMediaDeviceVideoCanvas,通过此对象能获得视图用于UI显示
*
* @param camera 摄像头对象
* @param renderType 渲染模式:
* - {@link #RENDER_FULL_SCREEN RENDER_FULL_SCREEN} : 铺满窗口,会有裁剪
* - {@link #RENDER_FULL_CONTENT RENDER_FULL_CONTENT} : 全图像显示,会有黑边
* @return - JRTCMediaDeviceVideoCanvas 对象: 开始自身视频渲染成功
* - null: 开始自身视频渲染失败
*/
public abstract JRTCMediaDeviceVideoCanvas startCameraVideo(JRTCMediaDeviceCamera camera, @RenderType int renderType);
RenderType (opens new window) 决定了视频的渲染模式:
- RENDER_FULL_SCREEN (opens new window) 为填充模式:即将画面内容居中等比缩放以充满整个显示区域,超出显示区域的部分将会被裁剪掉,此模式下画面可能不完整;
- RENDER_FULL_CONTENT (opens new window) 为适应模式:即按画面长边进行缩放以适应显示区域,短边部分会被填充为黑色,此模式下图像完整但可能留有黑边。
示例代码:
这里用 JavaSwing 的使用为例,JavaSwing 是 Java 桌面的 UI 库,Java 编写桌面程序的重要资源。JavaSwing 中常用的界面对象 JFrame,自定义类继承 JFrame 就可以进一步实现窗口。
//获取第一个摄像头对象
JRTCMediaDeviceCamera camera = mediaDevice.getCameras().get(0);
//打开指定摄像图,并开始渲染画面,其实viewPointer是渲染窗口句柄
JRTCMediaDeviceVideoCanvas localCanvas = mediaDevice.startCameraVideo(viewPointer, camera, JRTCMediaDevice.RENDER_FULL_SCREEN);
// 以下提供两种获取窗口句柄的方法,使用其中一个即可。如果出现黑屏应该先检查句柄是否获取正确。
//Windows窗口句柄可以通过如下方式获取,swing只支持JFrame窗口控件渲染视频,awt支持Pannel等
public static long getComponentPointer(Component component) {
long peerValue = -1;
Pointer componentPointer = Native.getComponentPointer(component);
Class a = componentPointer.getClass();
try {
Field peer = a.getDeclaredField("peer");
peer.setAccessible(true);
try {
peerValue = (long) peer.get(componentPointer);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
return peerValue;
}
//UOS&Kylin窗口句柄可以通过如下方式获取,swing只支持JFrame窗口控件渲染视频,awt支持Pannel等
public static long getComponentPointer(Component component) {
if (component == null) {
return -1;
}
if (!component.isDisplayable()) {
return -1;
}
XBaseWindow xBaseWindow = (XBaseWindow) component.getPeer();
return xBaseWindow.getContentWindow();
}
}
# 创建远端视频画面
当通话建立后,除了本地的视频画面,还有通话成员的远端视频画面,如果通话成员有视频流的上传,座席端可以获取到访客的视频流并进行渲染。
座席可在收到以下回调时进行界面处理:
- 收到 onCallStateChanged (opens new window) 回调且通话状态改为 AGENT_CHANGE_TYPE_TALKING (opens new window) 时,表示访客加入了通话。
- 收到 onMemberJoin (opens new window) 回调时,表示有其他成员加入通话。
- 收到 onMemberUpdate (opens new window) 回调时,表示通话中用户的通话状态变化。例如,可通过 changeParam.video (opens new window) 属性判断用户视频流状态是否发送改变;当 JRTCRoomParticipant.isVideo() (opens new window) 的值为 true ,表示远端用户已上传视频流,本端通过订阅远端视频流,获取远端视图渲染对象。
调用 startVideo (opens new window) 方法里传入渲染的画布的句柄进行视频画面渲染。
/**
* 开始其他端的视频渲染
* @note 该接口默认在 native 层使用硬件渲染,部分机型可能不支持
* <p>
* 获取其他端的视频预览对象 JRTCMediaDeviceVideoCanvas,通过此对象能获得视图用于UI显示
*
* @param view 视频窗口句柄
* @param streamId 视频流ID
* @param renderType 渲染模式:
* - {@link #RENDER_FULL_SCREEN RENDER_FULL_SCREEN} : 铺满窗口,会有裁剪
* - {@link #RENDER_FULL_CONTENT RENDER_FULL_CONTENT} : 全图像显示,会有黑边
* - {@link #RENDER_FULL_AUTO RENDER_FULL_AUTO} : 自适应
* @return
* - JRTCMediaDeviceVideoCanvas 对象: 开始其他端视频渲染成功
* - null: 开始其他端视频渲染失败
*/
public abstract JRTCMediaDeviceVideoCanvas startVideo(int view, String streamId, @RenderType int renderType);
/**
* 开始其他端的视频渲染
* @note 该接口默认在 java 层进行渲染,兼容性较好
* <p>
* 获取其他端的视频预览对象 JRTCMediaDeviceVideoCanvas,通过此对象能获得视图用于UI显示
*
* @param streamId 视频流ID
* @param renderType 渲染模式:
* - {@link #RENDER_FULL_SCREEN RENDER_FULL_SCREEN} : 铺满窗口,会有裁剪
* - {@link #RENDER_FULL_CONTENT RENDER_FULL_CONTENT} : 全图像显示,会有黑边
* @return
* - JRTCMediaDeviceVideoCanvas 对象: 开始其他端视频渲染成功
* - null: 开始其他端视频渲染失败
*/
public abstract JRTCMediaDeviceVideoCanvas startVideo(String streamId, @RenderType int renderType);
/**
* 停止视频渲染
*
* @param canvas JRTCMediaDeviceVideoCanvas 对象,由 {@link #startVideo startVideo} 或 {@link #startCameraVideo startCameraVideo} 接口返回
*/
public abstract void stopVideo(JRTCMediaDeviceVideoCanvas canvas);
渲染其他用户视图画面的方法法与渲染摄像头画面的用法基本一致,需关注 RenderType (opens new window) 渲染模式。
示例代码:
这里用 JavaSwing 的使用为例,JavaSwing 是 Java 桌面的 UI 库,Java 编写桌面程序的重要资源。JavaSwing中常用的界面对象 JFrame,自定义类继承 JFrame 就可以进一步实现窗口。
public class MyVideoFrame extends JFrame {
public MyVideoFrame() {
......
}
}
MyVideoFrame view = new MyVideoFrame();// 继承了JFrame的类,获取对象。在获取对象失败时应该检查类内部UI方法是否有误。
JRTCMediaDeviceVideoCanvas remoteCanvas = mediaDevice.startVideo(getComponentPointer(view), agent.getGuestParticipant().getRenderId(), RENDER_FULL_CONTENT);
// 以下提供两种获取窗口句柄的方法,使用其中一个即可。如果出现黑屏应该先检查句柄是否获取正确。
//Windows窗口句柄可以通过如下方式获取,swing只支持JFrame窗口控件渲染视频,awt支持Pannel等
public static long getComponentPointer(Component component) {
long peerValue = -1;
Pointer componentPointer = Native.getComponentPointer(component);
Class a = componentPointer.getClass();
try {
Field peer = a.getDeclaredField("peer");
peer.setAccessible(true);
try {
peerValue = (long) peer.get(componentPointer);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
return peerValue;
}
//UOS&Kylin窗口句柄可以通过如下方式获取,swing只支持JFrame窗口控件渲染视频,awt支持Pannel等
public static long getComponentPointer(Component component) {
if (component == null) {
return -1;
}
if (!component.isDisplayable()) {
return -1;
}
XBaseWindow xBaseWindow = (XBaseWindow) component.getPeer();
return xBaseWindow.getContentWindow();
}
}
# 结束通话
当业务办理结束,访客可以主动结束通话,座席也可以调用 term (opens new window) 接口主动结束通话。
/**
* 结束通话
* <p>
* 来电过程中调用此接口拒绝接听,访客分配到其他座席继续呼叫等待不会挂断。<br>
* 主座席调用此接口会结束通话,通话中所有成员都会离开,此通通话销毁,所有成员会收到 {@link JRTCAgentCallback#onCallStateChanged onCallStateChanged} 或 {@link JRTCGuestCallback#onCallStateChanged onCallStateChanged} 通话结束回调。<br>
* 第三方座席调用此接口仅自身离开通话,通话中其他成员会收到该成员离开的回调 {@link JRTCGuestCallback#onMemberLeave onMemberLeave} 或 {@link JRTCAgentCallback#onMemberLeave onMemberLeave} 回调,通话继续进行。
*
* @return 接口调用结果
* - true: 接口调用成功,会收到 {@link JRTCAgentCallback#onCallStateChanged onCallStateChanged} 回调
* - false: 接口调用异常
*/
public abstract boolean term();
主动和被动的挂断事件与来电、接通一样,都通过 onCallStateChanged (opens new window) 接口上报,其中 CallTermReason (opens new window) 可以用来判断挂断原因,如:主动挂断、对端挂断等,详细可参考接口文档或者 SDK 注释。
示例代码:
// 座席主动结束通话
agent.term();
// 通话状态改变回调
public void onCallStateChanged(@AgentCallStateChangeType int type, @CallIncomingType int incomingType, JRTCInviter inviter, @CallTermReason int reason) {
if (type == JRTCCallCenter.AGENT_CHANGE_TYPE_TERMED) {
// 通话结束,结束原因查看 reason
}
}
# 销毁本地和远端画面
当不再需要查看视频画面,包括会议成员离开,或者通话结束,需要调用 JRTCMediaDevice (opens new window) 中的 stopVideo (opens new window) 接口来释放渲染的资源;该方法需传入要释放的 JRTCMediaDeviceVideoCanvas (opens new window) 对象;必须进行这步操作,不然会造成渲染内存不释放。
/**
* 停止视频渲染
*
* @param canvas JRTCMediaDeviceVideoCanvas 对象,由 {@link #startVideo startVideo} 或 {@link #startCameraVideo startCameraVideo} 接口返回
*/
public abstract void stopVideo(JRTCMediaDeviceVideoCanvas canvas);
示例代码:
// 通话结束
public void onCallStateChanged(@AgentCallStateChangeType int type, @CallIncomingType int incomingType, JRTCInviter inviter, @CallTermReason int reason) {
if (type == JRTCCallCenter.AGENT_CHANGE_TYPE_TERMED) {
mediaDevice.stopVideo(localCanvas);
mediaDevice.stopVideo(remoteCanvas);
}
}
// 成员离开
public void onMemberLeave(JRTCRoomParticipant part) {
// 停止该成员画面渲染
mediaDevice.stopVideo(remoteCanvas);
}
# 登出
座席结束通话后,可以做登出操作;登出接口调用流程如下所示:
@startuml
autonumber
participant "用户" as User
participant "JRTCSDK" as JRTCSDK #orange
activate JRTCSDK
User -> JRTCSDK: client.logout()
group 登出成功
JRTCSDK -> User: onLogout(reason)
end
group 登出失败,强制登出
JRTCSDK -> User: onLogout(reason)
end
@enduml
座席可以登出视频平台,与平台断开一切连接。
/**
* 登出 Juphoon RTC 平台,登出后不能进行平台上的各种业务
* <p>
* 登出结果通过 {@link JRTCClientCallback#onLogout onLogout} 回调通知
*
* @return 接口调用结果
* - true: 接口调用成功
* - false: 接口调用异常
*/
public abstract boolean logout();
登出结果通过 JRTCClientCallback (opens new window) 中的 onLogout (opens new window) 接口上报:
/**
* 登出回调
*
* @param reason 登出原因
*/
void onLogout(@JRTCEnum.ReasonCode int reason);
示例代码:
// 调用登出接口
client.logout();
// 监听登出结果回调
public void onLogout(@ReasonCode int reason) {
// 登出完成
}
# 登录状态改变通知
登录状态通过 JRTCClientCallback (opens new window) 中的 onClientStateChanged (opens new window) 接口上报
/**
* 登录状态变化通知
* @param state 当前状态值
* @param oldState 之前状态值
*/
void onClientStateChanged(@JRTCClient.ClientState int state, @JRTCClient.ClientState int oldState);
登录状态详见 ClientState (opens new window):
示例代码:
//登录状态改变通知
public void onClientStateChanged(@ClientState int state, @ClientState int oldState) {
//state 当前状态
//oldState 之前状态
}
# 销毁SDK
每个模块都有对应的销毁接口。如不需再使用 SDK 的相关功能,可以强制释放 SDK 的资源。
注:该方法为同步调用,调用此方法后,你将无法再使用该模块的其它方法和回调。 我们不建议在 JRTC SDK 的所有回调方法中调用此方法销毁对象,否则可能出现崩溃现象。
/**
* 销毁 JRTCAgent 对象
*
* @note 该方法为同步调用,需要等待 JRTCAgent 实例资源释放后才能执行其他操作,调用此方法后,你将无法再使用 JRTCAgent 的其它方法和回调。<br>
* 我们 **不建议** 在 JRTCSDK 的回调中调用此方法销毁 JRTCAgent 对象,否则可能出现崩溃现象。<br>
* 如需在销毁后再次创建 JRTCAgent 实例,需要等待 destroy 方法执行结束后再创建实例。
*/
public static void destroy();
示例代码:
JRTCAgent.destroy();
JRTCMediaDevice.destroy();
JRTCClient.destroy();
# 4. 实现视频通话(房间)
# 加入房间
joinCall (opens new window)设置自己的角色直接通过房间号加入会议。需要先签入并且示闲,目前只支持以观察者座席PART_ROLE_MAIN_AGENT (opens new window)和次座席PART_ROLE_AGENT (opens new window)角色加入。同样可接收onCallStateChanged (opens new window)通知
int partRole = -1;
switch (mCBPartRole.getSelectedIndex()) {
case 1:
partRole = PART_ROLE_AGENT;
break;
case 2:
partRole = PART_ROLE_VIEWER_AGENT;
break;
default:
break;
}
if (partRole == -1) {
JOptionPane.showMessageDialog(null, "加入失败,目前只支持以观察者座席和次座席角色加入", "提示", JOptionPane.ERROR_MESSAGE);
} else {
if (!agent.joinCall(serialNumber, partRole)) {
JOptionPane.showMessageDialog(null, "加入失败", "提示", JOptionPane.ERROR_MESSAGE);
}
}
# 获取房间号
获取房间号 getRoomId (opens new window)
/**
* 获取房间号
*
* @return 房间号
*/
public abstract String getRoomId();
# 切换自己在通话中角色
switchPartRole (opens new window)切换自己在通话中角色,需要先进入通话,目前只支持从观察者座席角色切换到主座席角色。成员角色partRole (opens new window):PART_ROLE_MAIN_AGENT 主座席;PART_ROLE_AGENT 次座席。
if (agent.switchPartRole(partRole) == -1) {
JOptionPane.showMessageDialog(null, "切换角色失败", "提示", JOptionPane.ERROR_MESSAGE);
}
切换自己在通话中角色结果回调:onSwitchPartRoleResult (opens new window)
int operationId 操作id,对应 switchPartRole接口的返回值
boolean result 切换自己在通话中角色结果
- true: 操作成功
- false: 操作失败
String error 切换自己在通话中角色操作失败原因
示例代码;
@Override
public void onSwitchPartRoleResult(int operationId, boolean result, String error) {
super.onSwitchPartRoleResult(operationId, result, error);
BridgeNotify.NotifySwitchPartRoleResult switchPartRoleResult = new BridgeNotify.NotifySwitchPartRoleResult();
switchPartRoleResult.result = result;
switchPartRoleResult.error = error;
BaseSocketEngine.sendMessage(switchPartRoleResult);
BaseSocketEngine.sendMessage(switchPartRoleResult);
}
# 踢出通话成员
kickParticipant (opens new window)踢出通话成员,只有主座席角色可以使用该功能。
if (agent.kickParticipant(userId) == -1) {
JOptionPane.showMessageDialog(null, "踢出成员失败", "提示", JOptionPane.ERROR_MESSAGE);
}
踢出通话成员结果回调:onKickParticipantResult (opens new window)
int operationId 操作id,对应kickParticipant 接口的返回值
boolean result 踢出通话成员结果
- true: 操作成功
- false: 操作失败
String error 踢出通话成员操作失败原因
示例代码:
@Override
public void onKickParticipantResult(int operationId, boolean result, String error) {
super.onKickParticipantResult(operationId, result, error);
BridgeNotify.NotifyKickParticipantResult kickParticipantResult = new BridgeNotify.NotifyKickParticipantResult();
kickParticipantResult.result = result;
kickParticipantResult.error = error;
BaseSocketEngine.sendMessage(kickParticipantResult);
}
# 5. SIP通话
# 设置通话全局属性
setAcdProperty (opens new window)设置通话全局属性,目前用于有SIP成员通话中,改变SIP通话的属性。
(1)value 属性的value值;
(2)key 属性的key值AcdPropertyType (opens new window),除枚举提供得key之外也可以自定义;
/**
* 未知属性类别
*/
int ACD_PROPERTY_TYPE_UNKNOWN = -1;
/**
* SIP音视频属性
*/
int ACD_PROPERTY_TYPE_SIP_VIDEO = 0;
(3) publishType 发布类型AcdPropertyPublishType (opens new window)
/**
* 未知类型
*/
int ACD_PROPERTY_PUBLISH_TYPE_UNKNOWN = -1;
/**
* 广播全员
*/
int ACD_PROPERTY_PUBLISH_TYPE_BROADCAST = 0;
/**
* 指定发送
*/
int ACD_PROPERTY_PUBLISH_TYPE_DIRECT_SEND = 1;
/**
* 需要等待确定
*/
int ACD_PROPERTY_PUBLISH_TYPE_WAIT_RESPONSE = 2;
示例代码:
agent.setAcdProperty(ACD_PROPERTY_TYPE_SIP_VIDEO, String.valueOf(mCBACDCallType.getSelectedIndex()), ACD_PROPERTY_PUBLISH_TYPE_WAIT_RESPONSE);
# 收到通话全局属性变化通知
onAcdPropertyChange (opens new window)收到通话全局属性变化通知,通话中,修改通话全局属性属性其他成员将会收到该通知,根据消息发布类型进行响应。消息发布类型为ACD_PROPERTY_PUBLISH_TYPE_WAIT_RESPONSE (opens new window)时,需要本端确认是否同意切换。通过调用confirmAcdPropertyChange (opens new window) 来确认是否同意属性修改
@Override
public void onAcdPropertyChange(String userId, @JRTCCallCenter.AcdPropertyType int key, String value, boolean needConfirm) {
super.onAcdPropertyChange(userId, key, value, needConfirm);
// 响应别人的要求
// 用于sip通话中切换sip音视频,升级视频需要同意,降级音频不需要用户同意。目前适用于浙江移动和一站式外呼业务逻辑。
if (key == ACD_PROPERTY_TYPE_SIP_VIDEO) {
}
}
# 收到通话全局属性属性确认结果
onAcdPropertyResponse (opens new window)收到通话全局属性属性确认结果,通话中本端修改通话全局属性属性,消息发布类型如果为ACD_PROPERTY_PUBLISH_TYPE_WAIT_RESPONSE (opens new window),则其他成员响应后本端将会收到该通知。消息发布类型为其他类型,也会收到该通知,则结果为默认同意。
@Override
public void onAcdPropertyResponse(boolean accept, String userId, @JRTCCallCenter.AcdPropertyType int key, String value) {
super.onAcdPropertyResponse(accept, userId, key, value);
// 执行自己的要求
// 用于sip通话中切换sip音视频,升级视频需要同意,降级音频不需要用户同意。目前适用于浙江移动和一站式外呼业务逻辑。
if (key == ACD_PROPERTY_TYPE_SIP_VIDEO) {
}
}