9、多媒体系统:音频焦点管理(Audio Focus),CarAudioService 与音频路由策略
音频系统在车载环境里,说实话,比手机复杂得多。
手机嘛,基本上就是一个人用。但车里呢?司机要导航,副驾在听歌,后排小孩可能在看动画片。这些声音怎么共存?谁该出声,谁该闭嘴?这就是我们今天要聊的核心——音频焦点管理和路由策略。
我个人习惯把车载音频系统拆成三个层面来看:应用层(谁在发声)、服务层(谁有权限)、硬件层(声音从哪出来)。今天重点讲中间那层。
9.1 音频焦点:谁说了算?
先问一个问题:如果导航说“前方300米右转”,同时音乐正在高潮部分,你希望哪个声音更清晰?
答案很明显。导航必须清晰,音乐可以压低。这就是音频焦点要解决的问题。
核心概念:音频焦点(Audio Focus)是 Android 系统用来协调多个应用同时播放音频的机制。只有获得焦点的应用,才能正常发声。其他应用要么暂停,要么降低音量。
在 Android Automotive OS 里,焦点的管理比手机更严格。手机里你还可以让两个应用同时出声,车里不行——尤其是涉及安全提示的场景。
9.1.1 焦点请求的类型
应用在播放音频前,必须先请求焦点。请求时得告诉系统:你要干嘛?有多重要?
| 请求类型 | 说明 | 典型场景 |
|---|---|---|
| AUDIOFOCUS_GAIN | 长期占用焦点,其他应用必须暂停 | 音乐播放、视频播放 |
| AUDIOFOCUS_GAIN_TRANSIENT | 短暂占用,其他应用暂停一下 | 导航提示、语音指令 |
| AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK | 短暂占用,但允许其他应用降低音量继续播 | 消息通知、低优先级提示音 |
| AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE | 独占焦点,连降低音量都不行 | 紧急广播、电话通话 |
我在项目中遇到过一个问题:某个音乐应用在导航播报时,没有正确处理焦点丢失。结果导航说完了,音乐也不恢复了。用户以为系统坏了。后来查代码,发现是焦点监听回调里忘了调用 abandonAudioFocus()。
避坑指南:我曾经调试过一个案例,第三方音乐应用在请求 GAIN_TRANSIENT_MAY_DUCK 时,把 duck 音量设成了 0。这相当于让其他应用静音了。记住:duck 的意思是“降低”,不是“静音”。建议 duck 系数控制在 0.3~0.5 之间。
9.1.2 焦点变化的回调处理
应用需要注册一个 OnAudioFocusChangeListener,当焦点状态变化时,系统会回调这个方法:
audioManager.requestAudioFocus(
new AudioManager.OnAudioFocusChangeListener() {
@Override
public void onAudioFocusChange(int focusChange) {
switch (focusChange) {
case AudioManager.AUDIOFOCUS_GAIN:
// 获得焦点,恢复播放
player.start();
break;
case AudioManager.AUDIOFOCUS_LOSS:
// 永久失去焦点,停止播放
player.stop();
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
// 暂时失去焦点,暂停播放
player.pause();
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
// 降低音量继续播
player.setVolume(0.3f);
break;
}
}
},
AudioManager.STREAM_MUSIC,
AudioManager.AUDIOFOCUS_GAIN
);
嗯,这里要注意:很多开发者只处理了 GAIN 和 LOSS,忽略了 CAN_DUCK。结果导航播报时,音乐直接停了,体验很差。
9.2 CarAudioService:车载音频的总管家
CarAudioService 是 Android Automotive 里专门为车载场景设计的音频服务。它比普通的 AudioService 多了几个关键能力:
- 音频分区管理:不同座位可以有不同的音频策略
- 音量分组:导航、电话、媒体可以独立调节音量
- 路由策略:声音从哪个扬声器出来,由 CarAudioService 决定
说白了,CarAudioService 就是车载音频的大脑。它知道现在谁在开车,谁在听歌,哪个声音更重要。
9.2.1 音频分区的概念
在车里,不同座位的人可能想听不同的内容。司机需要导航,副驾想听歌,后排可能在看电影。CarAudioService 通过 音频分区(Audio Zone) 来实现这个需求。
每个分区可以有自己的:
- 音量控制
- 焦点管理
- 音频路由
举个例子:司机区的导航提示,不会影响到副驾正在播放的音乐。这在传统 Android 里是做不到的。
9.2.2 音量分组策略
CarAudioService 把音频流分成了几个组,每个组可以独立调节音量:
| 音量组 | 包含的音频类型 | 典型场景 |
|---|---|---|
| 媒体 | 音乐、视频、游戏 | 听歌、看电影 |
| 导航 | 导航语音、路况提示 | 导航播报 |
| 通话 | 电话、VoIP | 蓝牙电话 |
| 系统 | 提示音、警告音 | 安全带提醒、转向灯 |
| 紧急 | 紧急广播、安全警告 | 碰撞预警、故障报警 |
我建议在配置音量组时,把导航和紧急组的最大音量设得高一些。因为安全相关的提示,必须能在任何环境下被听到。
9.3 音频路由策略:声音从哪出来?
音频路由,说白了就是决定声音从哪个扬声器播放。手机很简单,要么听筒要么扬声器。车里呢?可能有十几个扬声器。
CarAudioService 的路由策略基于几个因素:
- 音频类型:导航走前门扬声器,电话走头枕扬声器
- 用户位置:司机的声音从左边出,副驾从右边出
- 当前状态:倒车时,所有非安全音频都要降低或静音
核心逻辑:路由策略的优先级是:安全 > 通信 > 导航 > 媒体。紧急广播可以打断一切,电话可以压低音乐,导航可以 duck 媒体。
9.3.1 动态路由示例
假设这样一个场景:
- 司机在听音乐(媒体流,前门扬声器)
- 副驾在打电话(通话流,头枕扬声器)
- 导航突然播报(导航流,前门扬声器)
CarAudioService 会怎么处理?
- 导航获得焦点,音乐被 duck(音量降到 30%)
- 通话不受影响,因为走的是不同的扬声器
- 导航播报结束后,音乐恢复音量
你看,这就是分区和路由配合的效果。不同音频流可以互不干扰。
9.4 知识体系总览
下面这张图,是我梳理的音频焦点与路由的整体架构。建议你多看几遍,把每个模块的职责搞清楚。
9.5 实战中的几个坑
最后,分享几个我在实际项目中踩过的坑:
坑一:焦点泄漏
应用在退出时没有释放焦点。结果其他应用永远拿不到焦点。我曾经排查过一个 case,导航播报一直没声音,最后发现是一个音乐 App 在后台死锁了焦点。
坑二:路由冲突
两个音频流被路由到了同一个扬声器通道。结果声音混在一起,谁也听不清。解决方案是在 CarAudioService 里配置好每个音频类型的默认路由,并加上冲突检测。
建议:在开发阶段,打开 CarAudioService 的日志开关。把焦点变化和路由决策都打出来。你会发现很多隐藏的问题。
好了,这一章的内容就到这里。音频焦点和路由策略,是车载多媒体系统的基石。搞懂了这两个东西,你就能理解为什么车里不同声音可以互不干扰,也能知道怎么去设计和调试一个复杂的车载音频系统。
公众号:蓝海资料掘金营,微信deep3321