iOS

# 通话操作

本文将介绍座席可基于 Juphoon RTC SDK 提供的通话操作能力实现的功能。

# 1. 通话属性变化

通话属性变化通过实现 JRTCAgentCallback (opens new window) 中的 onCallPropertyChanged (opens new window) 接口上报

/**
 * 通话属性改变回调
 * @note
 * 重点关注屏幕共享,即当{@link PropChangeParam#screenShare screenShare} 属性为 true 时,去处理屏幕共享相关事件。<br>
 * 可根据 {@link JRTCGuest#getShareStreamId shareRenderId} 和 {@link JRTCGuest#getShareUserId shareUserId} 属性进行屏幕共享画面的渲染和停止渲染。
 * @param propChangeParam 通话改变的属性
 */
void onCallPropertyChanged(PropChangeParam propChangeParam);

示例代码:

public void onCallPropertyChanged(PropChangeParam propChangeParam) {
    if(propChangeParam.uploadAudio) {
        //上传声音状态是否变化
    } else if(propChangeParam.uploadVideo) {
        //上传视频状态是否变化
    } else if(propChangeParam.audioOut) {
        //输出声音状态是否变化
    } else if(propChangeParam.cdnState) {
        //CDN推流状态是否变化
    } else if(propChangeParam.remoteRecordState) {
        //远程录制状态是否变化
    } else if(propChangeParam.screenShare) {
        //屏幕共享状态是否变化
    } else if(propChangeParam.audioRouteType) {
        //音频输出类型是否变化
    }
}

通话属性变化详见 PropChangeParam (opens new window)

其中对应通话属性的 boolean 值,有变化的为 true,没有变化为 false

# 2. 成员属性变化

成员属性变化通过实现 JRTCAgentCallback (opens new window) 中的 onMemberUpdate (opens new window) 接口上报

/**
 * 通话中成员属性更新回调
 *
 * 常用的有 {@link JRTCRoomParticipant.ChangeParam#volume 音量值}、{@link JRTCRoomParticipant.ChangeParam#audio 音频上传状态}、{@link JRTCRoomParticipant.ChangeParam#video 视频上传状态}等。<br>
 * 例如当通话中有成员关闭视频传输,通话中所有成员都会收到此回调。
 * @param part 属性更新的成员对象
 * @param changeParam 更新的属性对象
 */
void onMemberUpdate(JRTCRoomParticipant part, JRTCRoomParticipant.ChangeParam changeParam);

示例代码:

void onMemberUpdate(JRTCRoomParticipant part, JRTCRoomParticipant.ChangeParam changeParam){
    if (changeParam.video) {
        if (part.video) {
        	// 视频流打开
        } else {
        	// 视频流关闭
        }
    }
    if (changeParam.audio) {
        if (part.audio) {
        	// 音频流打开
        } else {
        	// 音频流关闭
        }
    }
}

成员属性变化详见 ChangeParam (opens new window)

其中对应通话属性的 boolean 值,有变化的为 true,没有变化为 false

# 3. 获取所有通话成员

通过 getParticipants (opens new window) 获取通话中所有成员列表,JRTCRoomParticipant (opens new window) 类见 API 文档。

/**
 * 获取所有成员 (包含自己、访客和其他坐席)
 *
 * @return
 */
public abstract List<JRTCRoomParticipant> getParticipants();

示例代码:

//获取通话中所有成员
List<JRTCRoomParticipant> participants = guest.getParticipants();

# 4. 获取访客成员

SDK 支持邀请三方座席(座席端功能)进入通话,可以通过以下接口获取所有访客成员列表,以及获取主访客成员。

/**
 * 获取主访客成员
 *
 * @return
 * - 通话中返回访客成员对象
 * - 不在通话中返回 null
 */
public abstract JRTCRoomParticipant getMainGuestParticipant();

/**
 * 获取访客成员列表
 *
 * @return
 * - 只有在通话中且通话中才能获得含有访客成员对象的数组,否则为空数组
 * - 当通话中不存在第三方访客时,获得一个仅含有主访客成员对象的数组
 * - 当通话中存在第三方访客时,获得一个含有主访客和第三方访客成员对象的数组
 */
public abstract List<JRTCRoomParticipant> getGuestParticipants();

示例代码:

// 获取主访客成员
agent.getMainGuestParticipant();

// 获取访客成员列表
agent.getGuestParticipants();

# 5. 获取自己的对象

/**
 * 获取自己对象
 *
 * @return 自己对象
 */
public abstract JRTCRoomParticipant getSelfParticipant();

示例代码:

//获取自己
JRTCRoomParticipant self = agent.getSelfParticipant();

# 6. 是否主座席

SDK 支持邀请三方座席进入通话,可通过以下接口判断自己是否主座席

/**
 * 是否主座席
 *
 * @return - true 主座席
 * - false 其他三方座席
 */
public abstract boolean isMainAgent();

示例代码:

// 是否主座席
agent.isMainAgent();

# 7. 通话保持/取回

通话中座席可发起保持通话的操作,保持通话之后座席和访客皆停发音视频数据,双方将互相听不到声音看不到视频画面。

发起通话保持之后,通话中的所有成员都将收到 onHoldStateChanged (opens new window) 通话被保持的回调。

/**
 * 获取当前通话保持状态
 *
 * 坐席可调用 {@link #setHoldState} 接口修改当前通话的保持状态。
 * @return 当前通话是否保持
 * - true:当前通话状态为保持
 * - false:当前通话状态为正常
 */
public abstract boolean setHoldState(boolean hold);

还可以通过调用 getHoldState (opens new window) 方法主动获取通话保持状态

/**
 * 获取当前通话保持状态
 *
 * 坐席可调用 {@link JRCAgent#setHoldState} 接口修改当前通话的保持状态。
 * @return 当前通话是否保持
 * - true:当前通话状态为保持
 * - false:当前通话状态为正常
 */
public abstract boolean getHoldState();

示例代码:

// 保持
agent.setHoldState(true);
// 取回
agent.setHoldState(false);

// 主动获取通话保持状态
bool hold = guest.getHoldState();
if (hold == true) {
    // 通话保持
} else {
    // 通话取回
}

public void onHoldStateChanged(boolean held) {
    if (held) {
        // 通话保持
    } else {
        // 通话取回
    }
}

# 8. 音视频通话切换

通话中座席与访客皆可发起音视频通话切换的操作。

视频通话状态下座席访客互相可听到对方声音看到视频画面,语音通话状态下座席访客只能听到对方声音,看不到对方视频画面。

座席可以调用 turnCallType (opens new window) 接口进行音视频通话切换。

/**
 * 音视频通话切换
 *
 * 可以通过 {@link #getCallType} 接口获取当前的通话类型 <br>
 * 通话中所有成员都将收到{@link JRTCGuestCallback#onCallTypeChanged onCallTypeChanged} 或 {@link JRTCAgentCallback#onCallTypeChanged onCallTypeChanged} 回调
 * @param callType 通话类型
 * @return 当前通话类型
 * - {@link JRTCCallCenter#CALL_TYPE_AUDIO CALL_TYPE_AUDIO}:语音通话
 * - {@link JRTCCallCenter#CALL_TYPE_VIDEO CALL_TYPE_VIDEO}:视频通话
 */
public abstract void turnCallType(@CallType int callType);

可以调用 getCallType (opens new window) 接口获取当前通话类型。

/**
 * 获取当前通话类型
 *
 * 可通过 {@link #turnCallType} 接口修改当前通话类型。
 * @return 当前通话类型
 * - {@link JRTCCallCenter#CALL_TYPE_AUDIO CALL_TYPE_AUDIO}:语音通话
 * - {@link JRTCCallCenter#CALL_TYPE_VIDEO CALL_TYPE_VIDEO}:视频通话
 */
public abstract @CallType int getCallType();

通话类型切换之后,参加通话的所有成员都将收到 onCallTypeChanged (opens new window) 通话类型切换的通知。

/**
 * 音视频通话切换回调
 *
 * 通话中的访客和座席可分别调用 {@link JRTCGuest#turnCallType turnCallType} 和 {@link JRTCAgent#turnCallType turnCallType} 方法切换音视频通话模式,通话中所有成员都会收到此回调。
 * @param callType 通话模式
 * - {@link JRTCGuest#CALL_TYPE_AUDIO CALL_TYPE_AUDIO} 语音通话模式
 * - {@link JRTCGuest#CALL_TYPE_VIDEO CALL_TYPE_VIDEO} 视频通话模式
 */
void onCallTypeChanged(@CallType int callType);

示例代码:

// 切换到语音通话
agent.turnCallType(JRTCCallCenter.CALL_TYPE_AUDIO);
// 切换到视频通话
agent.turnCallType(JRTCCallCenter.CALL_TYPE_VIDEO);
// 获取当前通话类型
int callType = guest.getCallType();
if (callType == JRTCGuest.CALL_TYPE_AUDIO) {
    // 当前为语音通话
} else if (callType == JRTCGuest.CALL_TYPE_VIDEO) {
    // 当前为视频通话
}
public void onCallTypeChanged(@CallType int callType) {
    if (callType == JRTCCallCenter.CALL_TYPE_AUDIO) {
        // 切换为语音通话
    } else if (callType == JRTCCallCenter.CALL_TYPE_VIDEO) {
        // 切换为视频通话
    }
}

# 9. 通话转接

座席可在通话过程中将通话转给其他座席;座席可以指定座席或指定业务组,如指定业务组将会选择业务组中一个空闲座席进行转接。转接流程:

  1. 座席通过调用 transferCall (opens new window) 发起通话转接;
  2. 座席转接结果通过实现 JRTCAgentCallback (opens new window)onTransferCallResult (opens new window) 接口获取;
  3. 访客会通过实现 JRTCGuestCallback (opens new window)onCallForwarding (opens new window) 接口接收被转接通知;
  4. 原座席离开通话;
  5. 当新座席加入通话后,通话继续。
/**
 * 通话转接
 *
 * 支持转接到具体座席和转接到某个业务组 <br>
 * 转接结果通过 {@link JRTCAgentCallback#onTransferCallResult onTransferCallResult} 回调上报 <br>
 * 座席调用转接接口成功时,访客会收到 {@link JRTCGuestCallback#onCallForwarding onCallForwarding} 回调
 * @param type 转接类型,转接到具体座席或是转接到业务组
 * - {@link JRTCCallCenter#TRANSFER_GROUP TRANSFER_GROUP} 转接到业务组
 * - {@link JRTCCallCenter#TRANSFER_STUFF TRANSFER_STUFF} 转接到具体座席
 * @param id
 * - 当转接类型为 {@link JRTCCallCenter#TRANSFER_GROUP TRANSFER_GROUP} 时,id 需传入业务组号
 * - 当转接类型为 {@link JRTCCallCenter#TRANSFER_STUFF TRANSFER_STUFF} 时,id 需传入座席用户ID
 * @return 接口调用结果
 * - > 0: 操作id,对应 {@link JRTCAgentCallback#onTransferCallResult onTransferCallResult} 回调的 operationId 参数
 * - -1: 接口调用异常
 */
public abstract int transferCall(@TransferType int type, String id);
/**
 * 通话转接回调
 *
 * 调用 {@link JRTCAgent#transferCall transferCall} 接口将通话转接给其他座席或业务组时,会收到此回调。
 * @param operationId 操作id,对应 {@link JRTCAgent#transferCall transferCall} 接口的返回值
 * @param result 通话转接结果
 * - true: 转接成功
 * - false: 转接失败
 */
void onTransferCallResult(int operationId, boolean result);

示例代码:

// 转接到业务组号
agent.transferCall(TRANSFER_GROUP, "10086");
// 转接到指定坐席
agent.transferCall(TRANSFER_STUFF, "agent2");
// 通话转接事件回调
public void onTransferCallResult(int operationId, boolean result) {
    if(result) {
        //转接成功
    } else {
        //转接失败
    }
}

// 访客收到转接被通知
void onCallForwarding() {
    //正在被转接,此时可以做一些界面提示
}

# 10. 单向视频

座席可通过调用接口请求单向视频。访客在收到对应的回调时,需应用层自行实现单项视频的功能,比如将对应的座席的视频画面进行遮挡,使访客无法看到座席画面。

单向视频发起流程:

  1. 座席可通过调用 requestOnewayVideo (opens new window) 接口打开/关闭单向视频;
  2. 访客通过实现 JRTCGuestCallback (opens new window)onOnewayVideoChanged (opens new window) 接口接受单向视频请求通知;
  3. 访客端应用层自行实现单向视频的功能,比如将对应的座席的视频画面进行遮挡,使访客无法看到座席画面;
/**
 * 请求单向视频
 *
 * 座席调用此接口后,会向全体访客发送单向视频请求,访客会收到 {@link JRTCGuestCallback#onOnewayVideoChanged onOnewayVideoChanged} 回调 <br>
 * 应用需要自行实现单向视频功能,例如访客用图片遮挡该座席画面,SDK不会对画面进行单向处理
 * @param turnOn 打开或关闭单向视频
 * - true: 打开单向视频
 * - false: 关闭单向录制
 */
public abstract void requestOnewayVideo(boolean turnOn);

示例代码:

// 请求单向视频
agent.requestOnewayVideo(true);
// 取消单向视频
agent.requestOnewayVideo(false);
//请求单向视频事件回调
public void onOnewayVideoChanged(boolean result) {
    if(result) {
    //成功
} else {
    //失败
}
}

也可以主动通过isOnewayVideo (opens new window) 获取当前单向视频状态

/**
 * 获取单向视频状态
 *
 * 座席可调用 {@link JRTCAgent#requestOnewayVideo: requestOnewayVideo} 接口修改当前通话的单向视频状态。
 * @return 单向视频状态
 * - true: 处于单向视频
 * - false: 不处于单向视频
 */
public abstract boolean isOnewayVideo();

# 11. 获取随路参数

访客呼叫时携带的额外信息,可以在座席收到来电通知 onCallStateChanged (opens new window) 回调中的 inviter 参数对象获取。

/**
 * 通话状态改变回调
 *
 * @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);

示例代码:

@Override
public void onCallStateChanged(@JRTCAgent.AgentCallStateChangeType int type, @JRTCAgent.CallIncomingType int incomingType, JRTCInviter inviter, @JRTCAgent.CallTermReason int reason){
    if (type == AGENT_CHANGE_TYPE_INCOMING) {
        //收到来电
        inviter.getExtraInfo();
    }
    
}

# 12. 切换自己在通话中角色

/**
 * 切换自己在通话中角色
 *
 * @note 需要先进入通话,目前只支持从观察者座席角色切换到主座席角色
 *
 * @param partRole            通话成员角色,目前只支持
 * @see #PART_ROLE_MAIN_AGENT 主座席
 * @see #PART_ROLE_AGENT      次座席
 * @return 接口调用结果
 * - > 0: 操作id,对应 {@link JRTCAgentCallback#onSwitchPartRoleResult(int, boolean, String) onSwitchPartRoleResult} 回调的 operationId 参数
 * - -1: 接口调用异常
 */
public abstract int switchPartRole(@PartRole int partRole);

# 13. 踢出通话成员

/**
 * 踢出通话成员
 * @note 只有主座席角色可以使用该功能
 *
 * @param userId 成员用户ID
 * @return 接口调用结果
 * - > 0:  操作id,对应 {@link JRTCAgentCallback#onKickParticipantResult(int, boolean, String) onKickParticipantResult} 回调的 operationId 参数
 * - -1:   接口调用异常
 */
public abstract int kickParticipant(String userId);