前言
设备通话解决方案通常涉及到音频和视频通信技术,包括语音通话、视频通话、实时消息传输等。这些解决方案可以被用于各种应用场景,包括在线教育、远程会议、在线医疗咨询。像这些都是设备通话的一些方案,后面会详细说说。但是这些通话都有一个困难点,那就是如何唤醒。否则只有这个应用内进行呼叫,不然就是再它还没后台杀死中才能进行呼叫,这样用户的体验特别不好。因为你呼叫了,没办法唤醒弹出来。对于这个唤醒,基本上是无解的。因为这跟系统的调度机制有关,与技术无关。目前看到就是,大公司与手机厂商进行合作,加入白名单,才可以做到,或者自己重写安卓系统某些机制,如电话手表这些。还有一种方案就是设备可以支持手机插卡,但这个也是极其不方便的,因为一台设备可以多个人使用。
开头
之前采用的通话方案是腾讯云实时音视频,这个安卓去调对应的SDK就行,但是遇到了开头说的问题,就是没办法通知唤醒用户进行接听通话,遭到了用户的投诉。体验非常不好。也有其它方案,列如采用离线推送,个推,提醒用户进入app。但效果还是不太好。
为此我们调研到了一款不错的解决方案,微信推出的,借助微信小程序音视频通话(for 硬件)能力,硬件开发者可以通过小程序硬件框架(WMPF),实现智能设备和手机微信端的一对一音视频通话,满足实时触达场景,提升通话体验。
介绍
1、主要原理:
借助安卓系统设备运行小程序硬件框架(WMPF),而WMPF中可以运行小程序,与用户手机微信内的小程序进行通话。
2、合作角色
(技术原理,WMPF 技术原理 | 微信开放文档 (qq.com))
作为小程序开发者的角度而言,将开发的小程序通过WMPF硬件展示出来,实现硬件的特殊需求,需要开发者再微信开放平台(微信开放平台 (qq.com))开启相关功能才能授权给WMPF使用(关闭则WMPF无法使用小程序)。
我们基于WMPF硬件开发时,小程序开发者可以通过调用与wx.xxx相似的wmpf.xxx接口,完成与WMPF Client端的通信,实现WMPF小程序下特有的功能(微信开放文档 (qq.com))。
3、WMPF支持的能力
WMPF支持很多的小程序接口,也有一些特有的能力,比如消息推送能力(无条件限制,但一个月内至少启动一次小程序)等等。先由WMPF拉起指定路径的小程序(LaunchWxaApp | 微信开放文档 (qq.com)),其中也有用二维码拉起方式,还可以关闭和预加载小程序的接口api;然后就可以达到硬件依靠利用小程序的能力与移动应用(WMPF Client)通信;其中接口分为两种形式,可以是 WMPF 提供的特有能力接口(例如刷脸支付、消息推送、打印机、设备 SN 码等),也可以是开发者自定义的在小程序与 WMPF Client 之间进行数据通信(Invoke Channel)。
4、VOIP插件
为了方便开发者接入WMPF-VoIP通话,保证设备侧和手机侧通话场景的用户体验,平台提供了小程序VOIP插件(VOIP通话 | 小程序插件 | 微信公众平台 (qq.com))。这个插件只能提供「小程序音视频通话(for 硬件)」的部分基础能力和统一的通话界面,插件提供了一些基本的api接口,比如发起接起通话、自定义通话设置、监听通话事件、硬件设备查询以及其它接口等等。
5、腾讯云实时音视频(TRTC)
TRTC(实时音视频 产品概述-产品简介-文档中心-腾讯云 (tencent.com))主打全平台互通的多人音视频通话和低延时互动直播解决方案,提供小程序、Web、Android、iOS、Electron、Windows、macOS 等平台的 SDK(Software Development Kit–软件开发工具包) 便于开发者快速集成并与实时音视频 TRTC 云服务后台连通TRTC提供包月免费体验TRTC旗舰版中的所有产品以及10000分钟的免费音视频时长包(实时音视频 计费概述-购买指南-文档中心-腾讯云 (tencent.com))。
6、TRTC与微信VOIP的对比
前者依赖于腾讯云平台提供的技术,主打全平台互通的多人音视频通话和低延时互动直播解决方案,适配于很多的场景和平台,而且也可集成其内部提供的TUICALLKIT UI组件,也可以快速地接入demo体验;后者依靠微信小程序内部自身的插件和音视频通话能力,引入插件并申请到音视频通话权限后即可同调用微信api一样调用wmpfVoip接口。
总得来说
像WebRTC,云通讯平台,一些公司如腾讯云、阿里云、环信等提供了完整的云通讯平台,这些平台提供了音视频通话、实时消息传输、文件共享等功能,开发者可以通过使用这些平台提供的SDK和API,快速在自己的应用中集成音视频通话功能。这些其实都跟TRTC是差不多的,能做到音视频通话,但都有相同的痛点就是唤醒。
使用
对于WMPF (安卓工程师需要做的事情)
1.「微信终端合作平台」「微信开放平台」均注册相关所需硬件和移动应用,且绑定指定小程序。
2.下载WMPF Service Apk,安装到安卓硬件上【主要区分64和32的版本】,到 WMPF 发布页面下载。
3.设备认证【安卓】,需要设备厂商内置一个 RPMB 分区读写及通信的服务。(需厂商实现)
4.设备注册【一个个的硬件注册】:(有示例辅助工具代码,需要服务端协助对接实现)
A:公钥(wmpfPublicKeyPath.key)和 私钥(wmpfPrivateKeyPath.key),存放在服务端,已生成,需要和微信终端合作平台登记设备的公钥一致;
B: 获取设备签名signature,需要参数productId、deviceId(安卓设备序列号或唯一标识)、私钥;
C: 获取accessToken,需要参数微信开放平台注册的移动应用appId,移动应用appSecret;
D: 添加设备信息到微信后台,接口:adddevice,所需参数model_name(在微信终端合作平台登记的型号),productId、deviceId(安卓设备序列号或唯一标识)、accessToken;
E:校验结果和签名,需要参数productId、deviceId(安卓设备序列号或唯一标识)、公钥、设备签名signature;
5.WMPF Client 开发:(安卓Apk开发【宿主】,拉起小程序的)
-
初始化:WMPFBoot.init(),所需参数移动应用appId、productId、keyVersion(微信终端合作平台的公钥版本号,一般是1)、deviceId(安卓设备序列号或唯一标识)、设备签名signature;(需服务端协助)
-
设备激活:activateDevice()方法;
-
设备注册(不可逆): 执行一次成功即可,无需重复(需服务端协助)
a) 获取access_token:Cgi.getAccessToken,所需参数微信小程序appId、微信小程序的secret;
b) 获取snTicket:Cgi.getSnTicket,所需参数access_token、deviceId(安卓设备序列号或唯一标识)、modelId(微信公众平台获取的 model_id);
c) registerMiniProgramDevice,需参数微信小程序appId、modelId、deviceId(安卓设备序列号或唯一标识)、snTicket。
-
需要知道当前用户信息、还有拨打给谁的信息。
-
激活license,费用问题:接口是https://api.weixin.qq.com/wxa/business/license/activedevice?access_token= 所需参数pkg_type、device_list[ model_id, sn, acitive_number ]
6)启动小程序:launchMiniProgram。
特点注意:
1.设备需要满足下列条件之一:
- 设备 EMMC/UFS 存储上的 RPMB(Replay Protected Memory Block) 分区未被使用;
- 设备支持 TEE,并能按照《设备认证 TEE 规范》开发 TA 并提交验收。
此外,设备厂商需要内置一个 RPMB 分区读写及通信的 RPMBD 服务,并保证服务能够开机正常启动。
这个由你你的设备厂商决定了你能不能用这个小程序音视频通话。一定要有 RPMBD 服务。
2.每一颗 EMMC/UFS 存储芯片的 RPMB KEY 只能被写一次,不能修改。如果被写入错误的值 (非注册时的 model_id 和 sn),那么这颗芯片就无法继续使用。如果第一次注册时写错了这个参数,不好意思,基本只能换一台了。
3.开发版跟体验版调试进行开发时需要做扫码登陆。
对于小程序(前端)
1.授权需要:
authVoIP() {
wx.requestDeviceVoIP({
sn: '', // Todo 向用户发起通话的设备 sn(需要与设备注册时一致),需要提前准备
snTicket: '', // 获取的 snTicket
modelId: '', // 「设备接入」从微信公众平台获取的 model_id
deviceName: '', // 设备名称,用于授权时显示给用户
success(res) {
console.log(`requestDeviceVoIP success:`, res)
},
fail(err) {
console.error(`requestDeviceVoIP fail:`, err)
}
})
}
2.设备呼叫手机需要:
const wmpfVoip = requirePlugin('wmpf-voip').default
try {
// 2.4.0 以下版本 roomId 为 groupId
const { roomId, isSuccess } = await wmpfVoip.initByCaller({
caller: {
id: 'sn', // 设备 SN
// 不支持传 name,显示的是授权时「deviceName」+「modelId 对应设备型号」
},
listener: {
// 参见 https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html 获取
id: 'openId' // 接听方 用户 openId
name: 'xxxxxx', // 接听方名字,仅显示用
},
roomType: 'video', // 房间类型。voice: 音频房间;video: 视频房间
businessType: 1, // 1 为设备呼叫手机微信
voipToken: 'xxxxxxxxxx', // 使用设备认证 SDK 注册的设备传入 deviceToken,使用 WMPF RegisterMiniProgramDevice 接口注册的设备无需传入(插件 2.3.0 支持)
miniprogramState: 'formal', // 指定接听方使用的小程序版本
})
if (isSuccess) {
// 如果小程序启动直接进入插件页面,则不要调用 wx.redirectTo
wx.redirectTo({
url: wmpfVoip.CALL_PAGE_PATH,
// 插件 2.3.9 开始支持 CALL_PAGE_PATH, 低版本请传入 'plugin-private://wxf830863afde621eb/pages/call-page-plugin/call-page-plugin',
})
} else {
wx.showToast({
title: '呼叫失败',
icon: 'error',
})
}
} catch (e) {
// 参数错误的情况会通过异常抛出
wx.showToast({
title: '呼叫失败',
icon: 'error',
})
}
3.手机呼叫设备:【场景不需要此功能】
const wmpfVoip = requirePlugin('wmpf-voip').default
const roomType = 'video'
try {
const { roomId, isSuccess } = await wmpfVoip.callWMPF({
roomType: 'video', // 房间类型。voice: 音频房间;video: 视频房间
sn: '设备 SN',
modelId: '设备 modelId',
pushToken: '从设备获取的 pushToken',
nickName: '设备端显示的微信用户名称',
deviceName: '我的学习机',
envVersion: 'release', // 指定接听方使用的小程序版本,开发过程可以使用 develop
})
if (/* 当前不在插件页面 */) {
// 跳转到插件的通话页面
wx.redirectTo({
url: wmpfVoip.CALL_PAGE_PATH,
// 插件 2.3.9 开始支持 CALL_PAGE_PATH, 低版本请传入 'plugin-private://wxf830863afde621eb/pages/call-page-plugin/call-page-plugin',
})
}
} catch (e) {
console.error('callWMPF failed:', e)
// 参数错误的情况会通过异常抛出
wx.showToast({
title: '呼叫失败',
icon: 'error',
})
}
总体流程
微信相关后台有固定的小程序appid、小程序secret、移动应用APPID、移动应用secret、model_id、productId、model_name… ——> 创建设备组 ——> 注册设备到微信后台 ——> 将设备添加到设备组 ——> 设备认证(不可逆)——> 设备激活license付费 ——>小程序授权设备组 ——> 拨打电话
微信接口文档
1.微信终端
https://wecooper.weixin.qq.com
2.WMPF
https://developers.weixin.qq.com/miniprogram/dev/framework/device/device-register-wmpf.html
3.小程序后台
https://mp.weixin.qq.com
4.voip
https://developers.weixin.qq.com/miniprogram/dev/framework/device/device-voip.html
1.model_id:(微信后台设备申请提供)
2.SN:安卓提供
appid:(微信后台)
scret:(微信后台)
3.获取access_token
https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=&secret=
4.获取openId(一进来就能获取)
https://api.weixin.qq.com/sns/jscode2session?appid=&secret=&js_code=&grant_type=authorization_code
5.获取sn_ticket
https://api.weixin.qq.com/wxa/getsnticket?access_token=
{
"model_id": "",
"sn": ""
}
raw jSON
安卓效果
代码示例
就两步,一是用户授权,二是设备点击拨号。其它参数可以通过postman调取。去测试运行。
wskang12138/voip-demo: 小程序音视频通话示例 (github.com)
总结
不过是安卓还是ios 它都是跟你微信语音通话的效果是一样的,测试过程中也发现,IOS似乎还是有问题存在的,当通话过程中特别网卡时,一边断开了,另外一边还在继续。同时,安卓跟ios效果是不一样的,安卓是把微信小程序整个唤起,再全屏覆盖,弹出通话接听框,而ios只是通知,当然也有震动跟铃声,没有达到全屏覆盖这个效果,微信对微信发起音视频也是如此效果。