随着移动互联网的发展,行业内衍生了基于移动平台的各种解决方案。其中,设备规模化管理的云控能力是各互联网公司在设备集群控制背景下的诉求。所以涌现了大批提供相似解决方案的平台。如:阿里系的阿里云MQC、阿里无线和菜鸟Nimitz等,阿里以外的有Testin、百度MTC、腾讯WeTest、华为、三星等等。web
目前以上平台在云真机的使用上,都存在一个已知的短板 —— 声音。用户看的到画面,可以响应操做,可是涉及到声音播报、语音交互的场景时则无能为力。尤为对于音乐、视听、短视频、直播客户端等这类多媒体属性强的App,在云真机的使用场景上是受限最大的。网络
如今回到咱们本身的产品。高德地图车机/镜版(后面统称Auto)。其中最多见的导航播报、与系统的多媒体混音交互、以及语音助手多轮对话的交互场景中,这些与声音相关的场景占比高达25%以上。因此解决远程场景下的声音双向交互问题,是云真机要成为一个平常化的生产工具以前必须迈过的坎。架构
在远程音频的双向通信解决方案的背景下,知足基本用户体验的方面也存在如下挑战:工具
能力:知足全部车载设备的声音场景的双向交互能力(由于车载设备在声音部分比手机具备更高的定制性,在覆盖车载场景后,手机基本能够无缝适配);测试
延迟:传输延迟低于500ms(基于必定的网络条件);优化
体验:无明显卡顿、杂音问题。阿里云
设想编码
首先经过下面的一张图来了解一下咱们的需求是什么:设计
将声音经过电脑传输到远端的车机设备(车机系统能正常解析处理);cdn
将车机经过喇叭播报出的声音传输到用户端。
而实现这两条链路,关键核心的两个因素是:
如何获取和写入音频数据;
如何实现实时的音频数据在车机和用户设备间的传输链路。
Android系统音频概要
在思考如何进行设备的音频获取前,咱们先来了解下Android的音频系统架构:
上图描述了音频通讯从应用层、Libraries、HAL、到Driver,最后到硬件模块各层主要实现。而咱们也须要从这条链路中去挖掘获取和写入音频数据的思路。
首先,咱们考虑的是Android对应的音频链路中是否有成熟的支持双向音频的能力。即音频数据在OS内部获取到对外传输。
REMOTE_SUBMIX
API 19新加的MediaRecorder. AudioSource. REMOTE_ SUBMIX,用于传输系统混音的音频流到远端(在API 18也存在,只是属于隐藏属性)。
因为要生效REMOTE_SUBMIX,须要Manifest. permission. CAPTURE_ AUDIO_ OUTPUT权限,而该权限只有系统组件才具有。也就是若是第三方App须要的话,须要进行系统签名或者在烧写OS版本时就修改对应的权限。做为系统方是能够这么操做的,但显然对于要适配全部系统方的咱们来讲不适用。
软件hook
考虑到咱们拿到的车载设备中,root比例高达80%以上。所以咱们想从在音频数据传输到底层硬件驱动前进行“截胡”。也就是hook HAL定义的往驱动写入和读取对应音频数据的方法,来达到音频数据的双向获取。
hw hook的是struct audio_hw_device的 音频输出:open_output_stream、close_output_stream
音频输入:open_input_stream、close_input_stream
system/lib/hw/audio.primary.*.so (不一样的设备有后缀部分差别)
在实际的调研测试中,咱们发现并非每台设备都能经过hook hw 来获取到对应的声音数据,尤为是车载设备。因而咱们又调研了ALSA(Advanced Linux Sound Architecture)高级Linux声音架构。根据官方的推荐,咱们选择了具有GPL-licensed 的external/tinyalsa
hook tinyalsa.so
音频输出:pcm_open、pcm_close、pcm_write、pcm_mmap_write
音频输入:pcm_open、pcm_close、pcm_read、pcm_mmap_read
system/lib/libtinyalsa.so
在实际摸底验证中,咱们发现车机比手机还复杂的缘由在于多了功放的概念,而部分车厂选择在设备的DSP模块去处理混音。带来的问题就是部分设备若是单纯的经过hook播报,对应听到的声音与设备真实经过喇叭播报的效果不一样,这也致使咱们对于该场景的还原并不真实。
所以,在于root设备覆盖不彻底且部分设备存在硬件功放处理混音问题的状况下,软件hook的方案只能适用于部分设备。
hook自身也会带来一个问题,即针对不一样的车机须要每台都进行hook处理,使得hook带来的成本太高。须要批量一键hook来解决这个问题。
分析到这里,咱们回顾下音频传输的链路:
基于以上咱们对音频获取的这条传输链路上的分析,如今理论上可行的获取途径,就只有硬件的对接或者具体的接收端(喇叭、蓝牙)。
usb音频
硬件对接部分,在云控场景下,咱们的设备一般是经过USB线束与咱们的节点PC链接的。所以音频经过USB进行传输的链路,也是一个值得探索的方向。
咱们知道,Android设备在链接usb时有三种模式:Host、Development、Accessory Mode:
主机模式:能够传输音频,可是Android设备做为主机,没法使用adb的能力;
开发者模式:具有adb的能力,可是没有现成的USB音频能力;
配件模式:既保留了adb的能力,在Android4.1后的配件模式下,Android 也能自动将其音频输出导向到USB。
思路:经过实现AOA协议,做为主机角色的设备,必须具备可以将Android设备从开发模式切换到配件模式的主机控制能力,而后主机从适当的端点传输音频数据
该方案的局限性在于:一、单向传输;二、配件模式取决于设备硬件,但并不是全部设备都支持。实测过程当中,车机支持配件模式的比例很低,绝大多数都被“阉割”了。
综上,咱们没法靠单纯的某种USB模式来实现音频的双向交互。但若是是手机集群的场景中,这个方案却是能够做为单向音频传输的一个优选方案。
蓝牙接收
声音除了能够经过usb传输之外,常见的方式还有蓝牙耳机、有线耳机。(这里因为车载设备不存在3.5mm孔,因此咱们先不讨论有线方式,具体可参考后面「硬件转发」的方案)。
关于蓝牙接收的基本思路就是PC端经过安装蓝牙接收器与车机通讯。其中蓝牙接收器起到相似于蓝牙耳机的做用。而后对蓝牙接收器的收发数据在PC端进行编码处理。
蓝牙耳机:具有了能够据说的能力,也就是双向的音频通讯。
摸底验证:部分车机对蓝牙驱动进行了定制,使得蓝牙设备只能做为从设备,没法接入蓝牙耳机功能。咱们测试了35台,其中5台能够用,成功率14%,收益过低,成本太高。这个方案若是是面向手机集群,却是一个不错的选择,理论上成功率应该会大大高于车载设备。
硬件转发
上面提到的有线耳机的思路。在车载设备上,不存在3.5mm孔或者type C口,而是经过主机与功放、音箱外放装置进行链接。在车辆量产上市前的研发阶段,只是一个主机经过线束链接着喇叭的一个过渡状态。因此咱们实际是经过将本来接到喇叭上的音频数据经过一种转换装置转接到PC上,在PC端进行音频编码处理。
大体的参考示意效果以下:
上述方案的优点在于:
跨平台,不论是Android、Linux、QNX或者iOS的设备都适用;
解决了混音问题,因为对接的是最终播报出的声音效果,就不存在软件hook可能还原不真实的问题;
支持双向音频通讯。
缺点:
部分智能车镜设备,因为集成封装性太强,没有暴露出可对接的线束。这类设备不容易经过该方案覆盖;
须要针对车机进行线束定制来实现总体的动态封装性;
须要配套的硬件成本。
硬件转发方案中存在几个方面的问题须要注意,好比失真问题、声卡识别问题、usb兼容上限、声卡与ehci、xhci的兼容性问题以及总体封装设计等等。
小结
综合以上音频传输的整条链路的全部方案,咱们列举对比下这些方案的优劣(特指在车载场景下):
基于上述状况,考虑到车载的应用场景。最终咱们的选型是 「软件hook」 +「硬件转发」的组合方案。
关于音频编码传输这部分的内容,行业中已经有较成熟的解决方案,所以,这部分不展开篇幅讨论,咱们仅针对一些方案作选型评估:
综上,从咱们的应用场景以及高实时性要求考虑,最终选取了webRtc的方案。
结合音频的获取和写入以及总体编码传输的方案,最终的技术方案选型图以下:
对应流程图中,也顺带涵盖了远程画面传输的视频流优化的参考链路。
经过软硬件组合的方案来实现音频数据读写的能力,是一种基于特定背景条件下解决方案。但其基本推演的思路和策略,也是适用于手机平台的。而其中硬件的解决方案,理论上是适用于Android、iOS、Linux、QNX等平台设备的。
相较来讲,手机的硬件转发成本更低。而对于软件的方案,实际的播报效果上仍会有不少细节问题,好比播报声音过小,须要对应设备去调节播报音量比例;出现延迟的场景,可能须要修改采样率;或是须要hook的自动化来下降成本等等。最终落地到项目中时,还须要考虑各方面的适配成本,确保总体的投入产出比。