跳到主要内容

一对一通话

本页介绍了一对一呼叫的主要功能,包括如何从您的应用程序拨打、接听、处理和结束呼叫。


关键类介绍

  • RCCallPlusClientRCCallPlusClient 单例对象是 CallPlus for HarmonyOS SDK 的核心类,用于管理客户端呼叫行为,例如发起、接听、挂断通话,操作音视频设备,管理通话记录等。
  • RCCallPlusSessionRCCallPlusSession 对象代表一则通话的所有信息,提供 getCallIdgetCallTypegetMediaTypegetUserList 等获取通话属性的方法。
  • IRCCallPlusCallRecordIRCCallPlusCallRecord 代表一则通话记录,其中包含了与 RCCallPlusSession 类似的通话信息,还提供了通话开始与结束的时间戳、通话时长、通话结束原因等信息。
  • ICallPlusEventListener:监听器 ICallPlusEventListener 提供了来电事件 onReceivedCall 、通话建立成功 onCallConnected 、收到通话记录 onReceivedCallPlusSummaryMessage 等事件相关回调。
  • IStatusReportListener:监听器 IStatusReportListener 提供通话中的通话质量数据回调。

初始化

TypeScript
/**
* CallPlusInstance 是 RCCallPlusClient 默认对外导出的实例
* _callPlusClient 为具体实现类声明的私有属性,后续示例代码都使用该变量。
*/
private _callPlusClient: RCCallPlusClient = CallPlusInstance

/**
* 初始化 CallPlus
* @param isPubTiny 配置是否发布视频小流,视频小流分辨率为 W176_H144,默认为 false
* 业务层有订阅视频小流的需求时,可配置 isPubTiny 为 true
*/
this._callPlusClient.init({isPubTiny: false})

设置监听器

注意

必须在 IMLib 连接之前设置监听。

CallPlus for HarmonyOS SDK 提供了两个监听器:

请在应用程序初始化或呼叫模块初始化时设置监听器:

  1. 调用 RCCallPlusClientsetCallPlusEventListener 方法设置 ICallPlusEventListener 监听器。

    TypeScript
    /**
    * 设置事件代理
    * @description 多次调用,后面设置会覆盖前面设置的通话事件监听
    * @param listener 类型为 ICallPlusEventListener,详细定义可参考 apiDoc
    */
    this._callPlusClient.setCallPlusEventListener({
    /**
    * 呼入通知
    * 收到呼入时,可选择接听或挂断通话
    * @param session 通话实例
    * @param extra 透传呼叫方发起呼叫时携带的附加信息
    */
    onReceivedCall: (session: RCCallPlusSession, extra?: string | undefined): void => {
    const callId = session.getCallId();
    const syncData = session.getSyncData();
    const isSecret = session.isSecret();
    console.log('呼入通知', callId, extra, syncData, isSecret);
    },
    /**
    * 通话已建立,sdk 内部会发布音视频资源
    */
    onCallConnected: (session: RCCallPlusSession): void => {
    const callId = session.getCallId();
    console.log('本端加入通话', callId);
    },
    /**
    * 通话结束(群组通话时,客户端挂断不代表通话结束)
    * @param session 通话实例
    * @param reason 通话结束原因
    */
    onCallEnded: (session: RCCallPlusSession, reason: RCCallPlusReason): void => {
    console.log('通话结束', session.getCallId(), reason);
    },
    /**
    * 收到通话结束的消息记录,可用于在 IM 聊天界面插入通话结束消息
    * 仅单聊可收到
    * 触发时机:
    * 1.单聊在线通话结束后
    * 2.离线时收到单聊呼叫,通话结束后,重新连接 IM 在线时
    * @param message 通话记录的消息体
    */
    onReceivedCallPlusSummaryMessage(message: Message) {
    console.log('收到 Call Plus summary message', JSON.stringify(message));
    },
    /**
    * 收到远端人员被邀请加入通话通知
    * @param inviteeUserList 被邀请人员列表
    * @param inviterUserId 邀请人员 ID
    * @param callId 通话 ID
    */
    onRemoteUserInvited: (inviteeUserList: string[], inviterUserId: string, callId: string): void => {
    console.log('收到远端人员被邀请加入通话通知', inviteeUserList, inviterUserId, callId);
    },
    /**
    * 远端用户的音视频首帧渲染
    * @param userId 远端用户 ID
    * @param mediaType 媒体类型
    */
    onFirstFrame: (userId: string, mediaType: RCCallPlusMediaType): void => {
    console.log(`${userId}${(mediaType === RCCallPlusMediaType.AUDIO) ? '音频' : '视频'}可渲染`);
    }
    })

连接融云服务器

要使用 CallPlus SDK 的通话能力,必须先通过 IMEngineconnect 方法连接融云服务器,传入用户身份令牌(Token),向融云服务器验证用户身份。连接成功后,使用 RCCallPlusClientinit() 方法初始化和配置 CallPlus SDK。

TypeScript
let token = "用户Token";
IMEngine.getInstance().connect(token, 20).then(result => {
if (EngineError.Success === result.code) {
// 连接成功
let userId = result.userId;
} else {
// 连接失败
}
});

处理本地与远端视频视图

在主叫方发起通话前,被叫方接听通话时需要使用 setVideoView 方法设置视频视图,删除已设置的用户视频视图请调用 removeVideoView 方法。若远端用户没有设置视频渲染视图,则不会产生该用户的视频流的下行流量。

在鸿蒙开发中的渲染通常需要结合 XComponent 组件,通过设置 viewId 来标识 RCCallPlusVideoViewXComponent 的唯一性。

本地预览

一般在发起通话前使用 setVideoView 方法,传入当前 userId 以及 RCCallPlusVideoView 实例,同时需要配合 startCamera 接口开启摄像头,就可以实现本地预览。当通话连接成功,本地预览的流才会发布到远端。

TypeScript
// 可以在 .ets 文件,aboutToAppear 方法里面设置本地预览

private viewId: string

aboutToAppear(): void {
// currentUserId 取当前的 userId
const currentUserId = 'current userId'
this.viewId = currentUserId
let videoView = new RCCallPlusVideoView(this.viewId, RCRTCVideoFillMode.ASPECT_FILL)
this._callPlusClient.setVideoView([{userId: currentUserId, videoElement: videoView, isTiny: isTiny}])
}
...

XComponent({
id: this.viewId,
type: XComponentType.SURFACE,
libraryname: 'nativerender'
})
.id(this.viewId)
.height('100%')
.width('70%')

远端视频视图

远端视频渲染和本地视图渲染一样使用 setVideoView 方法,支持在通话前或者通话连接成功后设置,需要指定远端用户的 userId 并且需要设置 viewId 来标识唯一性。接通前设置时,只有接通后 SDK 收到对应视频首帧了,才会开始渲染。

TypeScript
  // 定义 viewId 成员变量
private viewId: string

let remoteUserId = "remote UserId"
this.viewId = remoteUserId
let remoteVideoView = new RCCallPlusVideoView(this.viewId, RCRTCVideoFillMode.ASPECT_FILL)
this._callPlusClient.setVideoView([{userId: remoteUserId, videoElement: remoteVideoView, isTiny: true}])

...
// 使用 Stack 容器组件,可在 XComponent 叠加 Text 显示 userId
Stack({alignContent: Alignment.TopStart}) {
XComponent({
id: this.viewId,
type: XComponentType.SURFACE,
libraryname: 'nativerender'
})
Text(`${this.user.uid}`)
.backgroundColor('#6a000000')
.padding(5)
.fontColor(Color.White)
.fontSize(14)
}
.id(this.viewId)
.width('70%')

发起呼叫

CallPlus 定义了一对一通话类型 RCCallPlusType.SINGLE,您可以使用 startCallWithParams 方法来发起一对一通话。同时支持在发起呼叫时配置推送属性,达到自定义远程推送标题等属性的效果;支持携带自定义数据。如不需要配置推送属性,可选择不传。

TypeScript
/**
* 发起呼叫
* @param IRCCallPlusStartParams.callId 可选参数,非必要不传,如果需要指定 callId,必须保证生成的 callId 唯一性
* @param IRCCallPlusStartParams.userIds 被叫人员userId列表,单人呼叫仅需在数组中放置对方一人的 userId
* @param IRCCallPlusStartParams.callType 通话类型,单人呼叫或多人呼叫,单人呼叫时 userIds 长度只能为 1。
* @param IRCCallPlusStartParams.mediaType 通话媒体类型,音频或者音视频
* @param IRCCallPlusStartParams.pushConfig 可选参数,移动端推送信息
* @param IRCCallPlusStartParams.extra 可选参数,附加信息,会透传给被呼叫方
* @param IRCCallPlusStartParams.syncData 可选参数,定义通话同步数据,该数据与 `extra` 不同点,在于数据会被服务器存储,同时可通过 `session.getSyncData()` 获取数据不可超出 1024 Bytes
* @param IRCCallPlusStartParams.encryption 可选参数,加密配置,非必要不传,用于参与通话端之间的加密公钥交换
* @returns code 返回是否呼叫成功
* @returns callId 呼叫成功后,返回的通话 id
* @returns busyUsers 被呼叫方忙线时,返回忙线人员列表
*/
this._callPlusClient.startCallWithParams({
userIds: ['userId1'],
type: RCCallPlusType.SINGLE,
mediaType: RCCallPlusMediaType.AUDIO,
extra: 'extra',
syncData: 'syncData'
}).then((result) => {
if (result.code === RCCallPlusCode.SUCCESS) {
console.log('发起通话成功');
} else {
console.log('发起通话失败', result.code);
}
});

该方法调用后,SDK 内部会以异步方式执行。在主叫与被叫端触发以下回调:

通话建立成功后,主叫端已经设置的 setVideoView 中会自动渲染远端被叫用户的视图。


来电处理

被叫方的客户端应用程序中必须先注册 ICallPlusEventListener 监听器,才能通过 onReceivedCall 接收来电通知。onReceivedCall 方法中会返回 RCCallPlusSession 对象,通过 getCallId 可获取 callId,使用 getCallType 可获取通话类型。

调用以下方法选择是否接听来电:

  • 接听来电,使用 accept 方法,CallPlus SDK 将自动建立媒体会话。
  • 挂断来电,使用 hangup 方法,通话直接结束。

您可以在收到来电事件后打开摄像头采集,并完成本地视图设置。

TypeScript
/**
* 被叫用户/被邀请用户接收到通话呼叫通知
* @param session 通话实例
* @param extra 透传呼叫方发起呼叫时携带的附加信息
*/
onReceivedCall: (session: RCCallPlusSession, extra?: string): void => {
const callId = session.getCallId();
const syncData = session.getSyncData();
const isSecret = session.isSecret();
console.log('呼入通知', callId, extra, syncData, isSecret);
/// 接听
const res = await this._callPlusClient.accept(callId);
console.log(`接听通话结果, code: ${res.code}`);
}

同样在 onReceivedCall 监听到有新呼入的电话时,调用 hangup 方法直接挂断。

TypeScript
onReceivedCall: (session: RCCallPlusSession, extra?: string): void => {
const callId = session.getCallId();
const syncData = session.getSyncData();
const isSecret = session.isSecret();
console.log('呼入通知', callId, extra, syncData, isSecret);
/// 来电拒接
const res = await this._callPlusClient.hangup(callId);
console.log(`挂断通话结果, code: ${res.code}`);
}

通话设置

开关麦克风

在通话过程中,您可以使用 startMicrophone 方法来开启麦克风,stopMicrophone 方法来关闭麦克风。

TypeScript
// 开启麦克风,code 为当前接口的调用结果
const {code} = await this._callPlusClient.startMicrophone()

// 停止麦克风采集
const {code} = await this._callPlusClient.stopMicrophone()

当麦克风状态改变时,另一方将通过 ICallPlusEventListeneronRemoteMicrophoneStateChanged 回调方法接收事件回调。

TypeScript
/**
* 远端用户麦克风开关状态通知
* @param callId 通话 id
* @param userId 远端用户 id
* @param disabled 麦克风开关状态,true 为关闭状态,false 为打开状态
*/
onRemoteMicrophoneStateChanged(callId: string, userId: string, disabled: boolean): void {
console.log('收到远端麦克风状态通知', callId, userId, disabled)
}

开关摄像头

在通话过程中,您可以通过使用 startCamerastopCamera 方法来开启或关闭摄像头。

TypeScript
//开启摄像头数据采集
let result = await this._callPlusClient.startCamera()

//关闭摄像头数据采集
let result = await this._callPlusClient.stopCamera()

另一方将通过 ICallPlusEventListeneronRemoteCameraStateChanged 回调方法接收事件回调。

TypeScript
/**
* 远端用户摄像头开关状态通知
* @param callId 通话 id
* @param userId 远端用户 id
* @param disabled 摄像头开关状态,true 为关闭状态,false 为打开状态
*/
onRemoteCameraStateChanged(callId: string, userId: string, disabled: boolean): void {
console.log('收到摄像头状态通知', callId, userId, disabled)
}

切换前后摄像头

成功打开摄像头后,您可以使用 switchCamera 方法切换前后摄像头。该方法是异步调用的,您可以通过该方法的返回值来获取调用结果。

TypeScript
// 切换前后摄像头
let result = await this._callPlusClient.switchCamera()

配置视频设置

在视频通话开始前或通话过程中,您可以使用 setVideoConfig 方法来调整摄像头采集的配置信息,调整本端发送视频流的分辨率、码率、帧率:

TypeScript
/**
* 设置视频配置分辨率、最大/最小码率、帧率等信息。需要通话建立前设置。
* @param IVideoConfig.maxBitrate 最大码率
* @param IVideoConfig.minBitrate 最小码率
* @param IVideoConfig.frameRate 帧率
* @param IVideoConfig.resolution 分辨率
*/
this._callPlusClient.setVideoConfig({
maxBitrate: 900,
minBitrate: 200,
frameRate: RCCallPlusFrameRate.FPS_15,
resolution: RCCallPlusResolution.SIZE_640_480
});

切换媒体类型

仅在一对一通话过程中,主叫方和被叫方用户可以随时切换通话的媒体类型。

  • 当从视频通话切换为音频通话后,SDK 内部会停止发送本端的视频流,并停止接收远端用户的视频流。这样做只有音频流量,不再涉及视频传输。

需给 ICallPlusEventListener 添加注册两个关键监听事件:

TypeScript
/**
* 收到媒体类型变更请求(仅单聊)
* @param userId 请求发起人
* @param transactionId 事物 id,本次请求和应答的唯一标识
* @param mediaType 请求变更的媒体类型
*/
onReceivedChangeMediaTypeRequest(userId: string, transactionId: string, mediaType: RCCallPlusMediaType): void {
console.log('收到媒体切换请求', userId, transactionId, mediaType)
},
/**
* 媒体类型变更结果(仅单聊)
* @param info.userId
* @param info.transactionId 事物 id,本次请求和应答的唯一标识
* @param info.mediaType 最终的媒体类型
* @param info.code - 升级结果
* - 请求方取消媒体类型变更
* - 应答方拒绝媒体类型切换
* - 服务仲裁允许媒体类型切换
*/
onReceivedChangeMediaTypeResult(info: {
userId: string;
transactionId: string;
mediaType: RCCallPlusMediaType;
code: RCCallPlusMediaTypeChangeResult;
}): void {
console.log('收到媒体切换请求的结果', userId, transactionId, mediaType, code)
}

发起请求

使用 requestChangeMediaType 方法来发起媒体切换请求。SDK 内部以异步方式执行该方法,调用该方法后,触发以下回调:

  • API 调用结果为 Promise<{ code: number, transactionId?: string },code 为 RCCallPlusCode.SUCCESS 时表示请求发起成功,transactionId 表示当前操作的唯一标识。
  • 远端用户会通过事件监听器 ICallPlusEventListeneronReceivedChangeMediaTypeRequest 回调方法接收到切换通话媒体请求的通知。
  • 请求成功后,若远端用户在 60 秒内未做出响应,双方均会收到 ICallPlusEventListeneronReceivedChangeMediaTypeResult 回调。在这个回调中,参数 RCCallPlusMediaTypeChangeResult 若为 RCCallPlusMediaTypeChangeResult.CHANGE_MEDIA_TYPE_TIMEOUT,则表示响应已超时。
TypeScript
/**
* 通话中请求切换为音频通话
* @description
* 1. 该接口为单聊接口
* 2. 由音频切换到音视频,收到媒体类型切换结果通知后,不需要手动打开摄像头
* 3. 由音视频切换到音频,收到媒体类型切换结果通知后,不需要手动关闭摄像头
* @param mediaType 媒体类型
* @returns transactionId 客户端和服务端交互的事务 id,在取消或应答媒体类型切换时当做参数使用
*/
let {code, transactionId} = await this._callPlusClient.requestChangeMediaType(RCCallPlusMediaType.AUDIO)

响应请求

通话过程中收到 onReceivedChangeMediaTypeRequest 通知时,使用 replyChangeMediaType 方法来同意或拒绝该请求。SDK 内部以异步方式执行该方法,调用该方法后,触发以下回调:

  • 本地用户通过该方法的返回值来获取异步调用结果。
  • 如果本地用户同意、拒绝请求,本端和对端用户会收到 ICallPlusEventListeneronReceivedChangeMediaTypeResult 回调。应用程序可以通过该回调中的 RCCallPlusMediaTypeChangeResult 参数来查看媒体类型切换的结果。
TypeScript
// 同意切换
let isAgree = true
/**
* 响应通话中媒体类型切换请求
* @description 该接口为单聊接口
* @param transactionId 事务 id,为 onReceivedChangeMediaTypeRequest 监听收到 transactionId 参数值
* @param isAgree 是否同意
* @returns code 返回是否应答成功
*/
const res = await this._callPlusClient.replyChangeMediaType(transactionId, isAgree)

取消请求

本地用户请求成功后,在远端用户响应之前可以取消请求。调用 cancelChangeMediaType 方法取消指定媒体类型切换请求。

本地用户将通过该方法的返回值来判断接口是否成功,并可以通过 onReceivedChangeMediaTypeResult 回调中的 RCCallPlusMediaTypeChangeResult 参数来查看媒体切换的结果。

TypeScript
/**
* 取消已经发起的媒体类型切换请求
* @param transactionId 客户端和服务端交互的事务 id,为 requestChangeMediaType 方法返回的 transactionId
* @description 仅单呼时支持,可在调用 requestChangeMediaType 之后执行取消
*/
let {code} = await this._callPlusClient.cancelChangeMediaType(transactionId);

通话中接听来电

通话过程中,ICallPlusEventListeneronReceivedCall 事件可能会收到新的来电。由于一次只能进行一个通话,您可以通过以下代码逻辑判断收到的通话是否为第二次来电。如果要接听第二次来电,只需调用 accept 方法即可,或者您也可以调用 hangup 方法来挂断该通话。

注意

CallPlus SDK 不支持在通话过程中保持和恢复通话。

TypeScript
/**
* 呼入通知
* 收到呼入时,可选择接听或挂断通话
* @param session 通话实例
* @param extra 透传呼叫方发起呼叫时携带的附加信息
*/
onReceivedCall: (session: RCCallPlusSession, extra?: string): void => {
const callId = session.getCallId();
const syncData = session.getSyncData();
const isSecret = session.isSecret();
console.log('呼入通知', callId, extra, syncData, isSecret);
let curSession = RCCallPlusClient.getInstance().getCurrentCallSession();

if (curSession.getCallId() !== callId) {
// SDK 会在内部主动挂断上一次通话,接新通话。
let {code} = await RCCallPlusClient.getInstance().accpet(curSession.getCallId())
}
}

通话中精准计时

CallPlus 服务端可统一下发通话开始时间,确保各端计时准确、一致,具体支持以下两种方案:

  • 加入通话成功开始计时:可通过 ICallPlusEventListeneronReceivedCallStartTime 方法获取开始时间
  • 收到首帧开始计时:可通过 ICallPlusEventListeneronReceivedCallFirstFrameTime 方法获取首个音频或视频帧到达的时间

CallPlus 会在通话连接成功后将两个时间戳都回调给 SDK 端(可能会因校准行为导致多次回调),应用程序可以通过计算回调的时间戳与本地时间之间的差值得到精确的通话时长。

注意

为减小误差,CallPlus SDK 会根据用户的网络情况以及本地时间的差异,对通话开始的时间戳进行校准,因此可能存在同一个通话多次回调该方法的情况。建议您在使用时注意及时更新。

TypeScript
/**
* 收到通话开始计时
* @param info.callId 通话 id
* @param info.callType 单聊或群聊
* @param info.callStartTime 通话开始时间
*/
onReceivedCallStartTime?(info: {callId: string, callType: RCCallPlusType, callStartTime: number}): void {
// 通话建立,开始时间
}
/**
* 收到首帧时间
* 收到首帧开始计费
* @param callId 通话 id
* @param callFirstFrameTime 通话首帧到达时间
*/
onReceivedCallFirstFrameTime(callId: string, callFirstFrameTime: number): void {
// 用户可以在当前回调开启定通话计时
}

结束通话

在通话过程中,您可以使用 hangup 方法来挂断通话。

TypeScript
/// 如果不传入 callId,则是挂断当前通话,如果传入 callId 则是挂断指定的通话
let {code} = await this._callPlusClient.hangup();

该方法在 SDK 内部是以异步方式调用的,执行后会触发以下回调:

TypeScript
/**
* 通话结束(群组通话时,客户端挂断不代表通话结束)
* @param session 通话实例
* @param reason 通话结束原因
*/
onCallEnded(session: RCCallPlusSession, reason: RCCallPlusReason): void {
console.log('通话结束', reason);
}
/**
* 收到通话结束的消息记录,可用于在 IM 聊天界面插入通话结束消息
* 仅单聊可收到
* 触发时机:
* 1.单聊在线通话结束后
* 2.离线时收到单聊呼叫,通话结束后,重新连接 IM 在线时
* @param message 通话记录的消息体
*/
onReceivedCallPlusSummaryMessage(message: Message): void {
//结合 IM 插入本地消息,来是现实通话记录
}

管理通话记录

CallPlus 提供服务端通话记录管理能力,包括查询用户通话记录列表、删除通话记录等功能。一则通话记录对应一个 IRCCallPlusCallRecord 对象,其中包含通话 ID、参与用户 ID、通话开始与结束的时间戳、通话时长等信息。

注意

CallPlus SDK 通话记录区分两种

通话结束后获取通话记录

通话结束(或拒接来电)后可以通过 ICallPlusEventListener 的回调方法 onReceivedCallRecord 获取到服务器下发的通话记录。

检索服务端通话记录

应用程序可以使用 getCallRecords 方法向服务端发起请求,获取当前用户的通话历史记录。 参数说明 order 参数,支持倒序查询通话记录。例如,分页获取最近的通话记录。首次可以将 syncTime 设置为 -1。如果需要继续查询,可以将返回的 syncTime 作为下次查询的 syncTime 值。

TypeScript
const syncTime = -1 // 获取通话记录的同步时间 首次获取可传 -1,倒序时,返回最新的通话记录,正序时,返回最早的通话记录
const count = 20 // 获取通话记录的数量
const order: 0 | 1 = 1 // 获取通话记录的排序方式 1:正序,0:倒序
this._callPlusClient.getCallRecords(syncTime, count, order).then((res) => {
if (res.code === RCCallPlusCode.SUCCESS) {
console.log('获取通话记录成功', res.result);
} else {
console.log('获取通话记录失败', res.code);
}
});

删除通话记录

CallPlus SDK 提供两种删除通话记录的接口。deleteCallRecordsFromServerdeleteAllCallRecordsFromServer,前一个是根据 callId 数组批量从服务端删除属于当前用户的通话记录,后一个是全量删除。

TypeScript
// 删除通话记录
let callIds = ['callId1', 'callId2'];
this._callPlusClient.deleteCallRecordsFromServer(callIds).then((res) => {
if (res.code === RCCallPlusCode.SUCCESS) {
console.log('删除通话记录成功');
} else {
console.log('删除通话记录失败', res.code);
}
});

// 删除所有通话记录
this._callPlusClient.deleteAllCallRecordsFromServer().then((res) => {
if (res.code === RCCallPlusCode.SUCCESS) {
console.log('删除所有通话记录成功');
} else {
console.log('删除所有通话记录失败', res.code);
}
});

管理通话质量

在通话过程中,可使用 setStatusReportListener 方法注册 IStatusReportListener 监听,接收或发送丢包率等相关的信息。

TypeScript
/**
* 设置通话质量数据监听
* @description
* 1. 多次调用,后面设置会覆盖前面设置的通话质量数据监听
* 2. 回调频率为 1s 回调一次
*/
this._callPlusClient.setStatusReportListener({
/**
* 上行丢包率及延迟信息回调,每秒回调一次
* @param packetLostRate 丢包率,0-100
* @param delay 发送端的网络延迟,单位毫秒
*/
onSendPacketLoss(packetLostRate: number, delay: number): void {

},
/**
* 下行丢包率及延迟信息回调,每秒回调一次
* @param data key: userId, value: 接收丢包统计数据
* @param data[userId].packetLostRate 丢包率:取值范围是 0-100
* @param data[userId].bitRate 码率大小,单位是 kbps
*/
onReceivePacketLoss(data: {
[userId: string]: RCCallPlusPacketLossStats;
}): void {

}
});

音视频首帧回调

可通过 ICallPlusEventListener 中的 onFirstFrame 获取音频、视频首帧通知。

TypeScript
/**
* 音频或视频首帧可渲染
* @param userId 用户 id
* @param mediaType 媒体类型
*/
onFirstFrame(userId: string, mediaType: RCCallPlusMediaType): void {
console.log('收到首帧', userId, mediaType);
}