进阶集成指引
在集成 1v1 私密房方案过程中,你可以参考本文对 API 的调用时机、逻辑、参数设置等进行调优。
使用已初始化过的 rtmClient
声网 1v1 私密房的 CallAPI
中已经实现了对所需 RTM 服务的封装。如果在集成 1v1 私密房之前,你的项目中已经有 RTM 实例 rtmClient
了,则可以直接使用初始化过的 RTM 实例,然后调用相关功能。
如果你使用自己创建的 rtmClient
实例,则可以自行维持 RTM 的登录状态;你也可以通过我们提供的 CallRtmManager
中的 login
和 logout
方法管理登录和登出。
let rtmClient:AgoraRtmClientKit? = _createRtmClient()
rtmClient?.login(token) {[weak self] resp, error in
if let error = error {return}
// 登录成功即可初始化 CallRtmManager、CallRtmSignalClient、CallApi
切换被叫的发布和订阅时机以节省费用
在收到呼叫后,被叫的发布和订阅时机有两种:
- 收到呼叫后自动发布音视频流和订阅视频流,这是默认行为。
- 收到呼叫后,需要被叫接受后再发布音视频流、订阅视频流。
你可以通过 CallApiListenerProtocol
中的可选回调 canJoinRtcOnCalling
来设置发布和订阅时机:
- 如果返回
true
,或不实现该回调方法,则使用默认的推流策略,即收到呼叫就发布音视频流和订阅视频流 - 如果返回
false
,则使用接受呼叫后再发布音视频流、订阅视频流的策略
/// 当收到呼叫时判断是否可以加入 RTC
/// @param eventInfo: 收到呼叫时的扩展信息
/// @return
/// - true:可以加入
/// - false:不可以加入
@objc optional func canJoinRtcOnCalling(eventInfo: [String: Any]) -> Bool
手动开启和关闭音视频流发布
由于 CallAPI
内部会在通话时开启、结束通话时关闭采集音视频,因此如果在结束通话后外部需要手动开启音视频采集,例如当 onCallStateChanged
返回 (state: prepared)
时,可以开启采集。
rtcEngine.enableLocalAudio(true)
rtcEngine.enableLocalVideo(true)
消息中携带自定义数据结构
通过在 PrepareConfig
的 userExtension
属性中设置参数,您可以在发送消息给对端时(例如呼叫/取消呼叫/同意/拒绝等)附加额外的用户扩展信息。对端可以通过回调消息接收到这个userExtension
,以便在处理消息时获取相关的附加信息。
public func onCallStateChanged(with state: CallStateType,
stateReason: CallStateReason,
eventReason: String,
eventInfo: [String : Any]) {
let userExtension = eventInfo[kFromUserExtension] as? [String: Any]
...
}
通话异常定位
在双端连接过程中(state
为 calling
/connecting
/connected
时),可以通过 getCallId
方法获取当次通话双端的呼叫 ID。
你还可以通过 CallAPI
内部的日志上报,在声网后台查询到当次通话的各个节点耗时。如果需要使用,可以联系 sales@shengwang.cn 申请开通声网自定义数据上报和分析服务。
监听通话频道的 RTC 回调
为了更好地了解当前通话频道的状态和事件,你还可以监听 RTC 频道的回调。由于 CallAPI
里使用的 joinChannelEx
方式加入 RTC 频道,因此不可以使用 rtcEngine.addDelegate
方式,需要通过 rtcEngine.addDelegateEx
并指定对应的频道来添加 delegate
:
// 可以在收到呼叫状态时保存呼叫的频道 ID
func onCallStateChanged(with state: CallStateType,
stateReason: CallStateReason,
eventReason: String,
eventInfo: [String : Any]) {
switch state {
case .calling:
roomId = eventInfo[kFromRoomId] as? String ?? ""
default:
break
}
}
// 在收到 joinRTCStart 事件后通过频道 ID 来设置监听
@objc func onCallEventChanged(with event: CallEvent, eventReason: String?) {
switch event {
case .joinRTCStart:
/// @param roomId 当前 RTC 通话频道 ID
/// @param currentUid 当前用户 ID
let connection = AgoraRtcConnection(channelId: roomId, localUid: Int(currentUid))
rtcEngine.addDelegateEx(self, connection: connection)
default:
break
}
}
其中,当前 RTC 通话频道的 ID(roomId
参数)可以通过 onCallStateChanged
为 calling
时从 evenInfo
里解析获取。
需要保证加入时已经触发过了 joinRTCStart
事件,在此事件之前调用 rtcEngine.addDelegateEx
会无效。
更新过期 Token
你可以通过如下方式,更新信令和 RTC 的过期 Token。
信令 Token
-
监听 RTM Token 是否过期。通过添加并监听 CallRtmManager 状态回调 监听
ICallRtmManagerListener
的onTokenPrivilegeWillExpire
。Swiftextension Pure1v1RoomViewController: ICallRtmManagerListener {
func onTokenPrivilegeWillExpire(channelName: String) {
// Token 过期,需要重新获取 Token
}
} -
更新 Token。
Swift// 更新 RTC Token
self.api.renewToken(with: rtcToken)
// 更新 RTM Token
self.rtmManager?.renewToken(rtmToken: rtmToken)
// 为确保 RTM 和 RTC Token 同时有效,建议同时更新这两个 Token
RTC Token
-
监听 RTC Token 是否过期。
-
监听进行通话时过期的 Token。
Swiftextension Pure1v1RoomViewController:CallApiListenerProtocol {
func tokenPrivilegeWillExpire() {
// Token过期,需要重新获取 Token
}
} -
监听进行通话之前过期的 Token。
Swiftextension Pure1v1RoomViewController:CallApiListenerProtocol {
@objc func onCallError(with errorEvent: CallErrorEvent,
errorType: CallErrorCodeType,
errorCode: Int,
message: String?) {
if errorEvent == .rtcOccurError, errorType == .rtc, errorCode == AgoraErrorCode.tokenExpired.rawValue {
// RTC 加入频道失败,需要取消呼叫,并重新获取 Token
self.api.cancelCall { err in
}
}
}
}
-
-
更新 Token。
Swift// 更新 RTC Token
self.api.renewToken(with: rtcToken)
// 更新 RTM Token
self.rtmManager?.renewToken(rtmToken: rtmToken)
// 为确保 RTM 和 RTC Token 同时有效,建议同时更新这两个 Token
建议给 RTC 和 RTM 配置相同的 Token 过期时间,然后通过信令 Token 方式,借助 RTM 来检测过期并同时更新。