跳到主要内容

实现音视频通话

CallLib 是在 RTCLib 基础上,额外封装了一套音视频呼叫功能 SDK,包含了单人、多人音视频呼叫的各种场景和功能,通过集成它,您可以自由的实现音视频呼叫场景的各种玩法。

注意

房间人数上限

考虑移动设备的带宽(主要是在多路视频情况下),建议单次通话或房间内,视频不超过 16 人,纯音频不超过 32 人。超过此上限可能影响通话效果。

步骤 1:服务开通

您在融云创建的应用默认不会启用音视频服务。在使用融云提供的任何音视频服务前,您需要前往控制台,为应用开通音视频服务。

具体步骤请参阅 开通音视频服务

注意

服务开通、关闭等设置完成后 15 分钟后生效。

步骤 2:SDK 导入

您需要导入融云音视频通话能力库 CallLib,和 RTC 业务所依赖的即时通讯能力库 IMLib。根据您的业务需求,可选择导入美颜扩展库。

具体步骤请参阅 导入 CallLib SDK

步骤 3:初始化

CallLib 是基于 IM 作为信令通道的,所以要先初始化 IM 。如果不换 AppKey,在整个应用生命周期中,初始化一次即可。建议调用位置放在应用启动位置处,或在音视频功能模块的加载位置处。 在 UIAbilityonCreate() 方法中,调用初始化方法,传入生产开发环境的 App Key。

TypeScript
// 在 UIAbility 中获取 context
let context = this.context

let initOption = new InitOption();
let appKey = "从融云后台获取的 appKey";
IMEngine.getInstance().init(context, appKey, initOption);

步骤 4:监听通话事件

SDK 提供针对来电、通话状态、通话记录的事件处理机制。

设置监听

以下示例代码,新建一个 CallListenerImpl 类实现 RCCallClientListener 接口。并将实例设置给 SDK 。

TypeScript
/**
* RCCallClient 单例
* export const CallClientInstance: RCCallClient = CallClientImpl.getInstance()
*/
// 创建 _callClient 成员变量,供后续示例代码使用
this._callClient = CallClientInstance
// 设置监听
this._callClient.callClientListener = new CallListenerImpl()

通话呼入

通过实现 RCCallClientListener 中的 didReceiveCall 来监听通话呼入。

TypeScript
export class CallListenerImpl implements RCCallClientListener {
/**
* 收到通话呼入的回调
*
* @param callSession 通话实例
*
* @remarks 代理
*/
didReceiveCall(callSession: RCCallSession): void {
console.log('didReceiveCall', callSession)
}
}

通话状态变化

通过实现 RCCallClientListener 的通话连接,断开连接,人员变动来监听通话状态的变化。

TypeScript
export class CallListenerImpl implements RCCallClientListener {
/**
* 挂断通话的回调
*
* @param callSession 通话实例
* @param callDisconnectReason 通话挂断原因
*
* @remarks 代理
*/
didCallDisconnected(callSession: RCCallSession, callDisconnectReason: RCCallDisconnectReason): void {

},
/**
* 挂断通话的回调
*
* @param callSession 通话实例
* @param callDisconnectReason 通话挂断原因
*
* @remarks 代理
*/
didCallDisconnected(callSession: RCCallSession, callDisconnectReason: RCCallDisconnectReason): void {

},
/**
* 远端用户加入通话的回调
*
* @param callSession 通话实例
* @param userId 用户 ID
* @param mediaType 媒体类型
*
* @remarks 代理
*/
didRemoteUserJoined(callSession: RCCallSession, userId: string, mediaType: RCCallMediaType): void {

},
/**
* 远端用户挂断通话的回调
*
* @param callSession 通话实例
* @param userId 用户 ID
* @param callDisconnectReason 通话挂断原因
*
* @remarks 代理
*/
didRemoteUserLeft(callSession: RCCallSession, userId: string, callDisconnectReason: RCCallDisconnectReason): void {

}
}

漏接电话

通过实现 RCCallClientListener 中的 didMissCall 来监听漏接的通话。

TypeScript
 /**
* 收到通话漏接的回调
*
* @param callSession 通话实例
*
* @remarks 代理
*/
didMissCall(callSession: RCCallSession): void {

}

通话计时

CallLib SDK 无法直接获取通话时长,您可以在通话建立成功、音频首帧回调、或视频首帧回调方法中,使用当前时间减去通话起始时间,获取通话时长。

TypeScript
/**
* 接通通话的回调
*
* @param callSession 通话实例
*
* @remarks 代理
*/
didCallConnected(callSession: RCCallSession): void {

},
/**
* 收到远端用户音频首帧的回调
*
* @param callSession 通话实例
* @param userId 用户 ID
*
* @remarks 代理
*/
didReceiveFirstRemoteAudio(callSession: RCCallSession, userId: string): void {

},
/**
* 收到远端用户视频首帧的回调
*
* @param callSession 通话实例
* @param userId 用户 ID
*
* @remarks 代理
*/
didReceiveFirstRemoteVideo(callSession: RCCallSession, userId: string): void {

}

提示

如需在应用程序的服务端进行通话计时,建议使用融云提供的服务端回调音视频房间状态同步。通过实时回调事件 event 11(成员加入音视频房间)和 event 12(成员加入音视频房间)记录计费的开始和结束时间。

步骤 5:连接 IM 服务

音视频用户之间的信令传输依赖于融云的即时通信(IM)服务,因此需要先调用 connect 与 IM 服务建立好 TCP 长连接。建议在功能模块的加载位置处调用,之后再进行音视频呼叫业务。当模块退出后调用 disconnect 断开该连接。

TypeScript
// 连接 IM
IMEngine.getInstance().connect(token, 20).then(result => {
if (EngineError.Success === result.code) {
// 连接成功
let userId = result.userId;
return
}
if (EngineError.ConnectTokenExpired === result.code) {
// Token 过期,从 APP 服务请求新 token,获取到新 token 后重新 connect()
} else if (EngineError.ConnectionTimeout === result.code) {
// 连接超时,弹出提示,可以引导用户等待网络正常的时候再次点击进行连接
} else {
//其它业务错误码,请根据相应的错误码作出对应处理。
}
});

步骤 6:发起呼叫

连接 IM 服务成功后,可调用 RCCallClient 中的 startCall 来方法发起通话。

发起单人呼叫

TypeScript
/// 定义两个成员变量
private _callClient: RCCallClient = CallClientInstance
privete _callSession: RCCallSession

/// 发起单人呼叫
let callType = RCCallType.SINGLE;
let targetId = 'userId'
let userIds: string[] = ['userId']
let mediaType = RCCallMediaType.AUDIO
let extra = 'extra'

this._callClient.startCall(callType, targetId, userIds, mediaType, extra)
.then((res) => {
if(res.isSuccess){
this._callSession = res.callSession
} else {
console.error("呼叫失败, Code=" + RCCallErrorCode[res.code])
}
})

发起多人呼叫

TypeScript
/// 发起多人呼叫
let callType = RCCallType.MULTI;
let targetId = 'userId'
let userIds: string[] = ['userId']
let mediaType = RCCallMediaType.AUDIO
let extra = 'extra'
this._callClient.startCall(callType, targetId, userIds, mediaType, extra)
.then((res) => {
if(res.isSuccess){
this._callSession = res.callSession
} else {
console.error("呼叫失败, Code=" + RCCallErrorCode[res.code])
}
})

步骤 7:呼叫接听

在收到 didReceiveCall 回调之后,调用如下方法接听通话。

TypeScript
didReceiveCall(callSession: RCCallSession): void {
this._callClient.accept()
}