iOS

# 通话操作

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

# 1. 通话属性变化

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

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

示例代码:

public void onCallPropertyChanged(JRTCRoom.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) 接口上报

/**
 * 通话中成员属性更新回调
 * <p>
 * 常用的有 {@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 文档。

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

示例代码:

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

# 4. 获取访客成员

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

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

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

示例代码:

// 获取主访客对象
JRTCRoomParticipant mainAgent = agent.getMainGuestParticipant();

// 获取访客成员列表
List<JRTCRoomParticipant> guests = 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) 通话被保持的回调。

/**
 * 收到通话保持或取回的回调
 * <p>
 * 通话中座席可调用 {@link JRTCAgent#setHoldState setHoldState} 接口保持通话或取回通话,通话中所有成员都会收到此回调。
 *
 * @param hold true 表示通话被保持,false 表示通话取回
 */
void onHoldStateChanged(boolean hold);

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

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

示例代码:

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

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

# 8. 音视频切换

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

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

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

/**
 * 音视频通话切换
 * <p>
 * 可以通过 {@link #getCallType} 接口获取当前的通话类型 <br>
 * 根据通话业务类型
 * 1. 默认视频客服通话:
 * 通话中所有成员都将收到{@link JRTCGuestCallback#onCallTypeChanged onCallTypeChanged} 或 {@link JRTCAgentCallback#onCallTypeChanged onCallTypeChanged} 回调
 * 2. SIP通话:
 * 对端会收到 {@link JRTCAgentCallback#onCallTypeRequestConfirm(String, int) onCallTypeRequestConfirm}属性设置通知 <br>
 * SIP通话中,首先是音频通话,升级需要同意,降级默认同意。不会存在一端视频一端音频的情况。
 *
 * @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) 接口获取当前通话类型。

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

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

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

示例代码:

// 切换到语音通话
agent.turnCallType(JRTCCallCenter.CALL_TYPE_AUDIO);

// 切换到视频通话
agent.turnCallType(JRTCCallCenter.CALL_TYPE_VIDEO);

public void onCallTypeChanged(@JRTCAgent.CallType int callType) {
    if (callType == JRTCCallCenter.CALL_TYPE_AUDIO) {
        // 切换为语音通话
    } else if (callType == JRTCCallCenter.CALL_TYPE_VIDEO) {
        // 切换为视频通话
    }
}

# 9. 指定SIP音视频切换

SIP通话中座席可指定SIP成员切换音视频turnCallTypeForSip (opens new window)(目前仅支持SIP情况下,请求切换某一个SIP成员为视频)

/**
 * 音视频通话切换(目前仅支持SIP情况下,请求切换某一个SIP成员为视频)
 * @param callType 通话类型
 * 当前通话类型
 * - {@link JRTCCallCenter#CALL_TYPE_AUDIO CALL_TYPE_AUDIO}:语音通话
 * - {@link JRTCCallCenter#CALL_TYPE_VIDEO CALL_TYPE_VIDEO}:视频通话(目前仅支持此类型)
 * @param userId 用户id
 * @param extraInfo 随路参数
 * @return 接口调用是否成功
 * - true 操作成功
 * - false 操作失败
 */
public abstract boolean turnCallTypeForSip(@CallType int callType, String userId, String extraInfo);

调用之后,切换的结果通过通知上报onTurnCallTypeForSipResult (opens new window)

/**
 * 请求音视频通话切换结果回调
 * @note 目前仅支持Sip通话情况下,请求Sip成员开启视频
 *
 * @param result 请求音视频通话切换结果
 * - true:  请求成功
 * - false: 请求失败
 * @param reason 失败原因
 */
void onTurnCallTypeForSipResult(boolean result, String reason);

示例代码:

// 切换到语音通话
agent.turnCallTypeForSip(JRTCCallCenter.CALL_TYPE_AUDIO, userId, "");

// 切换到视频通话
agent.turnCallTypeForSip(JRTCCallCenter.CALL_TYPE_VIDEO, userId, "");

public void onTurnCallTypeForSipResult(boolean result, String reason) {

}

# 10. 通话转接

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

  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. 当新座席加入通话后,通话继续。
/**
 * 通话转接
 *
 * @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: 接口调用异常
 * @note 直呼场景接通后,不支持通话转接
 * 支持转接到具体座席和转接到某个业务组 <br>
 * 转接结果通过 {@link JRTCAgentCallback#onTransferCallResult onTransferCallResult} 回调上报 <br>
 * 座席调用转接接口成功时,访客会收到 {@link JRTCGuestCallback#onCallForwarding onCallForwarding} 回调
 */
public abstract int transferCall(@TransferType int type, String id);
/**
 * 通话转接回调
 * <p>
 * 调用 {@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() {
    //正在被转接,此时可以做一些界面提示
}

# 11. 单向视频

单向视频发起流程:

/**
 * 请求单向视频
 * <p>
 * 座席调用此接口后,会向全体访客发送单向视频请求,访客会收到 {@link JRTCGuestCallback#onOnewayVideoChanged onOnewayVideoChanged} 回调 <br>
 * 应用需要自行实现单向视频功能,例如访客用图片遮挡该座席画面,SDK不会对画面进行单向处理
 *
 * @param turnOn 打开或关闭单向视频
 *               - true: 打开单向视频
 *               - false: 关闭单向录制
 */
public abstract void requestOnewayVideo(boolean turnOn);

示例代码:

//座席请求打开单向视频
agent.requestOnewayVideo(true);
//座席请求关闭单向视频
agent.requestOnewayVideo(false);

// 访客接受不了单向视频请求回调
void onOnewayVideoChanged(boolean result) {
  if (result) {
    //单向视频开启
  } else {
    //单向视频关闭
  }  
}

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

/**
 * 获取单向视频状态
 * <p>
 * 座席可调用 {@link AAAAAJRTCAgent#requestOnewayVideo} 接口修改当前通话的单向视频状态。
 *
 * @return 单向视频状态
 * - true: 当前通话开启了单项视频
 * - false: 当前通话未开启单项视频
 */
public abstract boolean isOnewayVideo();

# 12. 获取随路参数

访客呼叫时携带的额外信息,可以在座席收到来电通知 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();
    }
    
}