# 实现一对一通话
本章将介绍如何实现多个 APP 应用间的视频通话,视频通话的 API 调用时序见下图:
# 获取设备权限
使用 reqPermissionsFromUser
方法,获取设备的麦克风和相机使用权限。
import abilityAccessCtrl, { Permissions } from '@ohos.abilityAccessCtrl';
const permissions: Array<Permissions> = ['ohos.permission.MICROPHONE', 'ohos.permission.CAMERA'];
async aboutToAppear() {
...
// 获取设备权限
reqPermissionsFromUser(permissions,this.context)
}
/*申请权限*/
static reqPermissionsFromUser(permissions: Array<Permissions>, context: common.UIAbilityContext | undefined): void {
let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
// requestPermissionsFromUser会判断权限的授权状态来决定是否唤起弹窗
atManager.requestPermissionsFromUser(context, permissions).then((data) => {
let grantStatus: Array<number> = data.authResults;
let length: number = grantStatus.length;
for (let i = 0; i < length; i++) {
if (grantStatus[i] === 0) {
// 用户授权,可以继续访问目标操作
console.log('授权成功');
} else {
// 用户拒绝授权,提示用户必须授权才能访问当前页面的功能,并引导用户到系统设置中打开相应的权限
console.log('授权失败');
return;
}
}
// 授权成功
}).catch((err: BusinessError) => {
console.error(`Failed to request permissions from user. Code is ${err.code}, message is ${err.message}`);
})
}
# 初始化
调用 JCMediaDevice.create (opens new window) 和 JCCall.create (opens new window) 以初始化实现一对一通话需要的模块。
export class JCManager implements JCCallCallback, JCMediaDeviceCallback {
// 声明对象
public call: JCCall | undefined;
public mediaDevice: JCMediaDevice | undefined;
// 初始化函数
initialize(context: Context, createParam: CreateParam): boolean {
//1. 媒体类
this.mediaDevice = JCMediaDevice.create(this.client, this);
//2. 通话类
this.call = JCCall.create(this.client, this.mediaDevice, this);
}
// 所有一对一接口回调的实现
...
// 所有媒体接口回调的实现
...
}
# 拨打通话
调用 call (opens new window) 发起语音通话,需要填写的参数有:
- userID 填写对方的用户 ID。
- video 选择是否为视频通话, true 表示拨打视频通话, false 表示拨打语音通话。
- callParam 通话参数对象,此参数可为空,详细定义见:CallParam (opens new window)
let callParam = new CallParam("extraParam", "ticket");
this.call?.call("userId", isVideo, callParam)
拨打通话后,主叫和被叫均会收到新增通话的回调 onCallItemAdd (opens new window),此时通话状态变为 CallState.STATE_PENDING (opens new window) 。您可以通过重写 onCallItemAdd (opens new window) 执行逻辑操作。 示例代码
// 1. 发起语音通话
this.call("userID", isVideo , new JCCall.CallParam("extraParam", "ticket"));
// 2. 重写回调
onCallItemAdd(item: JCCallItem): void {// 业务逻辑
if (item.getDirection() == CallDirection.DIRECTION_IN) {// 如果是被叫...
} else {// 如果是主叫...
}
}
如果主叫想取消通话,可以直接转到挂断通话部分。调用挂断接口后,通话状态变为 CallState.STATE_CANCEL (opens new window)。
# 应答通话
- 被叫收到 onCallItemAdd (opens new window) 回调,在回调中调用 JCCallItem (opens new window) 中的 getVideo (opens new window) 方法获取 video 属性来判断是视频呼入还是语音呼入,从而做出相应的处理。
onCallItemAdd(item: JCCallItem): void { // 1. 如果是语音呼入且在振铃中 if (item.getDirection() == CallDirection.DIRECTION_IN && !item.getVideo()) { // 2. 做出相应的处理,如在界面上显示“振铃中” ... } }
- 调用 answer (opens new window) 接听通话。通话接听后,通话状态变为 CallState.STATE_CONNECTING (opens new window)。 如果被叫要在此时拒绝通话,请调用挂断通话的接口。这种情况下调用挂断后,通话状态变为 CallState.STATE_CANCELED (opens new window)。
this.call?.answer(item, false);
# 挂断通话
主叫或者被叫均可以挂断通话
调用 getActiveCallItem (opens new window) 获取当前活跃的通话对象:
this.call?.getActiveCallItem()
调用 term (opens new window) 挂断当前活跃通话:
this.call?.term(item, reason, description); 示例代码 // 1. 获取当前活跃通话 let item = this.call?.getActiveCallItem(); if (item != null) { // 2. 挂断当前活跃通话 this.call?.term(item, 0, "reason"); }