Android Audio 多区音频功能主要针对的是 Android Automotive 这样的场景,它允许在同一个 Android 设备上支持多个独立的音频区域,每个区域可以有不同的音频输出设置。这种功能特别适用于汽车环境,因为车内通常有多个乘客,他们可能希望听不同的音频内容。
一、概念介绍
在 Android 10 中,多区音频得到了进一步的支持和增强。允许多个音频流同时播放到不同的物理输出设备或区域,支持独立的音量控制和混合,可以构建后座娱乐系统(RSE)解决方案,让后排乘客能够独立控制他们的音频体验。
汽车音频服务使用 Core Audio 动态音频政策来为车载使用场景提供协助。
1、Core Audio
Core Audio 是 Android 中用于处理音频的核心组件,它主要负责音频的播放、录制、混音、路由等功能。
为每位乘客单独播放音频(称为多区音频),其中每个音频区允许并发播放声音。
动态音频区配置。
乘客主区音频投放。
乘客的音频镜像。
在每个用例中,车载音频服务都使用动态音频政策自动将音频路由到指定的输出设备。
2、多区音频
借助多区音频,多个用户可以同时与 AAOS 互动。一组输出设备与一个音频区相关联,每个音频区都保持音频焦点和音量级别。乘客可以聆听自己的音频,同时驾驶员收听主音频区(通常是主车厢)中的另一个音源。
多区音频架构
汽车音频区是音频输出、音频焦点和其他音频设置的抽象化,所有这些设置都可以单独管理。为便于路由,每个音频区均定义为一组音频输出总线设备,按照音频政策配置进行排列。每种音频区定义的设备各不相同。在上图中,总线设备 1 到 5 属于音频区 0,总线设备 6 到 8 属于音频区 1,总线设备 9 到 11 属于音频区 2。
车载音频配置
通常,输出设备会分配到一个音频区。每个音频区都在 car_audio_configuration.xml 中定义。以下代码段显示了上图中的汽车音频配置:
<carAudioConfiguration version="3">
<zones>
<zone name="Zone0" audioZneId="0" occupantZoneI="0">
<zoneConfigs>
<zoneConfig name="config0" isDefault="true">
<volumeGoups>
<group>
<device address="bus_1">
<context context="music"/>
</device>
</group>
<group>
<device address="bus_2">
<context context="navigation"/>
</device>
</group>
...
</volumeGroups>
<displays>
<display port="0"/>
</displays>
</zoneConfig>
</zoneConfigs>
</zone>
<zone name="Zone1" audioZoneId="1" occupantZoneId="1">
<zoneConfigs>
<zoneConfig name="config0" isDefault="true">
<volumeGroups>
<group>
<device address="bus_6">
<context context="music"/>
</device>
</group>
<group>
<device address="bus_7">
<context context="navigation"/>
</device>
</group>
...
</volumeGroups>
<displays>
<display port="1"/>
</displays>
</zoneConfig>
</zoneConfigs>
</zone>
...
...
</zones>
</carAudioConfiguration>
对于这段代码是不是比较熟悉,我们在前面的《音量Group设置(九)》中介绍过,这里再来看一下。
- carAudioConfiguration:配置文件的根节点,包含了所有关于车载音频系统的配置信息。其中 version="3" 表示此配置文件的版本号为 3。
- zones:列出了所有可用的音频区域。
- zone:定义一个音频区域,每个区域可以有自己的音频配置,包括 name(区域的名称)、audioZoneId(区域唯一标识符)和occupantZoneId(乘客区域标识符,用于区分不同的乘客位置)。
- zoneConfigs:列出了该区域可用的音频配置。实际开发中该属性可以省略。
- zoneConfig:定义一个具体的音频配置方案,其中 name 为配置的名称,isDefault 为否为默认配置。
- volumeGroups:对应配置方案中的音量组,每个音量组可以包含一个或多个音频设备。
- group:定义一个音量组,该组内的设备共享相同的音量设置。
- device:定义一个音频输出设备。其中属性 address 为设备的地址,用于标识特定的音频输出设备。
- context:定义了设备可以播放的内容类型,如 music, navigation 等
- displays:一组显示设备的容器标签。
- display:单个显示设备。包含了 port 属性,用于标识显示设备的端口号,端口号通常用于标识不同的输出接口,比如 HDMI、VGA 或 DVI 等。
可以看到这里的 bus_1 对应 music,说明只有地址为 bus_1 的输出设备才会播放音乐类型的音频流。
occupantZoneId 是由 CarOccupantZoneManager 管理的汽车服务定义。它在汽车中用于定义汽车用户到特定座位位置的映射。CarOccupantZoneService 还定义了用户登录显示屏后从乘员区到显示屏、其他外围设备和用户之间的映射。音频区具备以下内容:
音频区 ID 和乘员区 ID。
- 将音频区映射到乘员区(座位、显示屏和其他外围设备)。
- 在登录时确定为音频区分配哪个用户 ID了。
音频配置列表(每项音频配置都有一组音量组,每个音量组都有一组音频总线设备)
当音量发生变化时,组中的所有音频设备均以相同的方式进行控制。
每个音频设备都分配有一个音频属性列表。此信息用于构建分配有不同音频属性的音频政策混音。
此配置允许将不同的音频属性使用情况路由到每个音频区中的不同输出设备。不同的声音可以同时播放,具体取决于用例。例如,您可以选择将主驾驶舱(主区)配置为在所有扬声器上播放媒体声音,但仅在离驾驶员最近的扬声器上播放导航声音。通过并发播放声音,主驾驶舱在系统向驾驶员播放导航声音时继续聆听媒体。
多区音频乘客登录工作流程
下面的序列图显示了乘客登录其相应屏幕时启用音频路由的流程:
在这个序列中,用户登录信息通过乘员区服务传播到汽车音频服务。
- 汽车音频服务(针对特定音频区)使用 AudioPolicy#removeUserIdDeviceAffinity API 取消用户设备关联性。此 API 接受用户 ID。在此示例中为上一个音频区的用户。
- AudioPolicy#setUserIdDeviceAffinity API 将新用户分配到某个音频区,该音频区会接受用户 ID 以及特定音频区配置的所有设备。
3、动态音频区配置
Android 14 中引入了动态音频区配置,以允许 OEM 为乘客配置不同的设备组。该用例允许后座的乘客在后座头枕扬声器和后座耳机外围设备之间切换。
在这种情况下,需要进行两种配置。后座头枕和耳机外围设备各一个。特定用户的音频一次只能路由到一个配置。
上图展示了动态音频区配置工作流程的架构。音频区 1 包含两种配置(Config 0 和 Config 1),它们分别与输出设备扬声器和头枕相关联。
登录后,系统会自动为用户分配默认配置。 当用户选择更改配置时(通常通过系统界面),汽车音频服务会在两种配置之间切换。这样,输出设备就会在 Z1 扬声器和 Z1 头枕之间切换。
以下代码段展示了此动态音频区配置的设置。
<carAudioConfiguration version="3">
<zones>
<zone name="Zone1" audioZoneId="1" occupantZoneId="1">
<zoneConfigs>
<zoneConfig name="Zone 1 Config 0" isDefault="true">
<volumeGroups>
<group>
<device address="bus_100">
<context context="music"/>
***
</device>
</group>
</volumeGroups>
</zoneConfig>
<zoneConfig name="Zone 1 Config 1">
<volumeGroups>
<group>
<device address="bus_101">
<context context="music"/>
***
</device>
</group>
</volumeGroups>
</zoneConfig>
</zoneConfigs>
</zone>
</zones>
为方便管理音频配置,汽车音频管理器会公开用于管理配置的 API:
- 可用于音频区的查询配置。
- 查询当前为音频区设置的配置。
- 切换到其他配置。
系统界面应用或服务可以使用这些 API 管理音频区的配置,如下图所示。Query API 向乘客公开这两者。用户可以通过点按所需配置的命令选择其他配置。
4、主区乘客音频投放
主区乘客音频投放是 Android 14 中引入的一项功能,可让乘客将其媒体音频投放到主区。这样,乘客的媒体音频便可投放到主驾驶舱,同时驾驶员仍保持完全控制。
下图显示了主区乘客媒体音频投放的简化版架构。
此图显示驾驶员的媒体输出设备与乘客共用,这种情况仅在乘客投放到主区模式时才会发生。动态音频政策还可用于管理驾驶员的音频路由,但不会对驾驶员的设备关联性应用任何更改。对于乘客,输出设备列表按如下方式更改:
- 从设备列表中移除了乘客的媒体输出设备
- 向设备列表中添加了驾驶员媒体输出设备
- 乘客音频区的其余输出设备保留在设备列表中
这个新的设备列表由 AudioPolicy#setUserIdDeviceAffinity API 分配给乘客。传递给该 API 的参数是设备列表和乘客用户 ID。当音频系统的音频政策服务查询要为与乘客关联的媒体轨道选择哪个音频混音时,系统会选择与主区相关联的媒体混音。
主区音频投放的一项关键要求是主区的媒体输出设备与其他音频属性使用情况隔离开来。否则,在构建混音期间,系统会向混音中添加其他音频属性。音频系统在选择混音时,连接到混音的所有声音都会在主驾驶舱中选择播放。
5、乘客区音频镜像
音频镜像功能使乘客能够共享音频。镜像功能会复制每个音频区中的音频数据,以便所有乘客都能聆听相同的音频。在这种情况下,音频焦点会与音频镜像涉及的乘客共享。
音频镜像路由
至少需要两名乘客才能启用音频镜像。因此,仅包含两个乘客音频区的音频配置需要一台镜像输出设备。根据上述定义,可以启动两个并发镜像会话。
下图显示了两名乘客之间的多区音频镜像的简化示意图。两名乘客的音频都被路由到音频镜像设备 bus_1000
。音频 HAL 将信号复制到源区。
只有当乘客处于镜像模式时,系统才会启用此路由。否则,系统会将音频区的相应设备分配给乘客。首次为乘客启用镜像时,AudioPolicy#setUserIdDeviceAffinity API 会修改路由:
- 从设备列表中移除了乘客的媒体输出设备。
- 已将镜像输出设备添加到设备列表。
- 乘客音频区的其余输出设备保留在设备列表中。
对于设备列表,使用更新后的设备列表和乘客的用户 ID 调用 API。下面是音频镜像工作流程的序列图。
在上图中,用于管理音频镜像的车载音频管理器 API 是从媒体系统服务调用的。具体而言,即用于为用户 1 和用户 2 启用音频镜像的 API CarAudioManager#enableMirrorForAudioZones。
汽车音频服务按上述方法为用户乘客配置音频路由。汽车音频服务还会向音频 HAL 发送信号,以配置音频并将其从镜像设备复制到相应的音频区。
在上图中,汽车音频服务会发送 mirroring_src=bus_1000,mirroring_dest=bus_10、bus_20。其中 bus_1000 是来源总线,bus_10 和 bus_20 是目标总线。
序列图中未显示通过 AudioManager#setParameters API 发送的信号,该信号通过音频服务到达 HAL。
停用音频镜像后,系统会发送以下信号:mirroring_src=bus_1000,mirroring=off。未启用音频镜像时,HAL 可以使用此信号停用音频复制操作。为了定义音频镜像设备,汽车音频配置文件包含一个名为 mirroringDevices 的部分,如以下代码段所示。
在此代码段中,定义了两个镜像设备(bus_1000 和 bus_2000),以便四名乘客可以使用音频镜像。
<carAudioConfiguration version="3">
<mirroringDevices>
<mirroringDevice address="bus_1000"/>
<mirroringDevice address="bus_2000"/>
</mirroringDevices>
<zones>
....
</zones>
</carAudioConfiguration>
这篇文章主要参考 Android 官方文档的多区音频介绍,目的是更好的了解多区音频的相关概念,便于理解后面相关代码的分析。
标签:输出设备,乘客,音频,配置,多区,镜像,Android,Audio,设备 From: https://blog.csdn.net/c19344881x/article/details/141392934