2、CarService音频架构基础:Android Automotive OS音频架构、CarService的角色、AudioPolicy与AudioFlinger的关系、音频焦点(AudioFocus)机制
2.1 Android Automotive OS 音频架构总览
Android Automotive OS(AAOS)的音频架构在标准 Android 音频框架基础上,针对车载多音区、多通道、高优先级打断等场景进行了深度定制。整个架构从上到下分为应用层、框架层、原生服务层和硬件抽象层,核心组件包括 CarService、AudioPolicy、AudioFlinger 和 音频焦点(AudioFocus) 管理器。
架构要点:AAOS 音频架构的核心设计目标是实现“多音区独立路由”和“安全关键音频优先”。CarService 作为车载特有的策略决策者,位于应用层与原生 AudioService 之间,负责将车辆信号(如转向灯、倒车雷达)转化为音频路由指令。
2.2 CarService 在音频路由中的角色
CarService 是 AAOS 车载专属的系统服务,运行在 com.android.car 进程中。它不直接处理音频数据,而是作为 音频策略决策者,将车辆信号(CAN 总线、车身域控制器)转换为 Android 音频系统的控制指令。
| 角色 | 职责说明 | 关键接口/类 |
|---|---|---|
| 音区管理 | 定义和管理车内多个独立音区(主驾、副驾、后排、左后、右后) | CarAudioManager、CarVolumeGroupInfo |
| 上下文路由 | 根据车辆状态(行驶/驻车、转向灯、倒车、ADAS 警告)动态切换音频输出 | CarAudioRoutingManager |
| 音量分组 | 将不同音频流(媒体、导航、语音、电话)映射到物理扬声器组,并独立控制音量 | CarVolumeGroup、AudioAttributes |
| 焦点代理 | 作为车载应用的 AudioFocus 请求代理,支持多音区独立焦点管理 | CarAudioFocus、AudioFocusRequest |
开发提示:CarService 的音频路由决策最终通过
AudioPolicy 的 setForceUse() 和 setDeviceConnectionState() 方法执行。语音助手集成时,通常需要监听 CarAudioRoutingManager.KEY_AUDIO_ROUTING_CHANGED 回调来感知路由变化。
2.3 AudioPolicy 与 AudioFlinger 的关系
AudioPolicy 和 AudioFlinger 是 Android 原生音频系统的两大核心服务,均运行在 audioserver 进程中。它们的分工明确:AudioPolicy 负责“路由策略”,AudioFlinger 负责“混音与输出”。
- AudioPolicy(策略层):根据音频属性(
AudioAttributes)、设备状态、焦点持有者,决定音频流应该路由到哪个输出设备(扬声器、蓝牙、耳机、车载功放)。车载场景下,CarService 通过AudioPolicyManager的自定义策略覆盖默认行为。 - AudioFlinger(执行层):接收来自多个应用的音频数据,进行混音(Mixer),然后写入到 AudioPolicy 指定的输出线程(Output Thread)对应的 HAL 设备。它管理着多个
PlaybackThread和RecordThread。
避坑指南:在车载定制中,不要直接修改 AudioFlinger 的混音逻辑。正确的做法是通过
AudioPolicy 的自定义策略(audio_policy_configuration.xml)和 CarService 的 CarAudioRoutingManager 来控制路由。直接修改 AudioFlinger 会导致 OTA 升级兼容性问题。
2.4 音频焦点(AudioFocus)机制
音频焦点机制是 Android 系统中管理多个应用同时播放音频时的优先级与打断策略的核心机制。在车载环境中,由于语音助手、导航、电话、警告音等音频源可能同时存在,焦点管理变得尤为关键。
2.4.1 焦点类型与行为
| 焦点类型 | 持续时间 | 对低优先级应用的影响 | 典型车载场景 |
|---|---|---|---|
| AudioFocusRequest.AUDIOFOCUS_GAIN | 长期 | 低优先级应用暂停播放 | 语音助手开始交互、电话通话 |
| AUDIOFOCUS_GAIN_TRANSIENT | 短暂 | 低优先级应用暂停播放 | 导航语音播报、倒车雷达提示音 |
| AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK | 短暂 | 低优先级应用降低音量(Duck) | 媒体音乐被导航语音短暂压低 |
| AUDIOFOCUS_LOSS | 长期 | 应用应停止播放并释放资源 | 语音助手抢占媒体焦点 |
| AUDIOFOCUS_LOSS_TRANSIENT | 短暂 | 应用暂停播放,焦点恢复后继续 | 电话来电时媒体暂停 |
2.4.2 车载多音区焦点模型
标准 Android 的 AudioFocus 是全局单实例的,即整个系统只有一个焦点持有者。但车载场景需要支持多音区独立焦点:主驾播放媒体时,副驾可以独立播放视频且互不干扰。CarService 通过 CarAudioFocus 扩展了焦点模型,引入了 ZoneId 概念。
// 车载多音区焦点请求示例
CarAudioManager carAudioManager = (CarAudioManager) getSystemService(Context.CAR_AUDIO_SERVICE);
// 为副驾音区请求焦点
AudioFocusRequest focusRequest = new AudioFocusRequest.Builder(AudioFocusRequest.AUDIOFOCUS_GAIN)
.setAudioAttributes(AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA)
.build())
.build();
// 指定 ZoneId(副驾音区)
int zoneId = CarAudioManager.getZoneIdForOccupant(OccupantType.FRONT_PASSENGER);
int result = carAudioManager.requestAudioFocus(focusRequest, zoneId);
集成要点:语音助手在请求焦点时,应使用
AUDIOFOCUS_GAIN 或 AUDIOFOCUS_GAIN_TRANSIENT,并指定正确的 ZoneId。同时需要监听 OnAudioFocusChangeListener 回调,在焦点被更高优先级应用(如紧急电话)抢占时及时暂停播放。
2.4.3 焦点优先级链
在车载系统中,音频焦点的优先级从高到低通常为:
- 安全关键音频:倒车雷达、ADAS 警告、转向灯提示(通常绕过焦点机制,直接由 CarService 强制路由)
- 电话通话:蓝牙电话、VoIP 通话
- 语音助手:用户唤醒后的交互会话
- 导航播报:导航指令语音
- 媒体播放:音乐、视频、播客
- 系统音效:按键音、通知音
最佳实践:语音助手集成时,建议在唤醒后立即请求
AUDIOFOCUS_GAIN 焦点,并在交互结束时释放。如果同时需要播放导航提示,语音助手应作为导航音频的“焦点代理”,避免导航与语音助手互相打断。