With automotive comes a new set of use cases around concurrent users interacting with the platform and looking to consume separate media. For example, a driver can play music in the cabin while passengers in the back seat are watching a YouTube video on the rear display. Multi-zone audio enables this by allowing different audio sources to play concurrently through different areas of the vehicle.
Multi-zone audio in Android 10 enables OEMs to configure audio into separate zones. Each zone is a collection of devices within the vehicle with its own volume groups, routing configuration for contexts, and focus management. In this manner, the main cabin could be configured as one audio zone, while the rear display's headphone jacks be configured as a second zone.
The zones are defined as part of car_audio_configuration.xml
.
CarAudioService then reads the configuration and helps AudioService route audio
streams based on their associated zone. Each zone still defines rules for
routing based on contexts and the applications uid. When a player is created,
CarAudioService determines for which zone the player is associated with, and
then based on the usage, which device the AudioFlinger should route the audio
to.
Focus is also maintained independently for each audio zone. This enables applications in different zones to independently produce audio without interfering with each other while having applications still respect changes in focus within their zone. CarZonesAudioFocus within CarAudioService is responsible for managing focus for each zone.
Figure 1. Configure multi-zone audio
Configuring multiple zones
In Android 10 car_audio_configuration.xml
replaces car_volumes_groups.xml
and IAudioControl.getBusForContext
.
In the new configuration file, a list of zones is defined. Each zone has one or more
volume groups with their associated devices, and each device has the contexts that
should be routed it within that zone. It's required that all contexts are represented
within each zone.
The audio_policy, which typically lives in the vendor partition, represents
the audio hardware configuration of the board. All devices referenced in
car_audio_configuration.xml will be defined within the
audio_policy_configuration.xml
.
Enabling multi-zone support
When the multi-zone audio is present, you must set the
audioUseDynamicRouting
flag to true
:
<resources> <bool name="audioUseDynamicRouting">true</bool> </resources>
When false, the CarAudioService will fall back to using car_volumes_groups.xml
and IAudioControl.getBusForContext
. While no changes are required at the
HAL layer, since the car_audio_configuration.xml
file defines the device
to context relationship the IAudioControl.getBusForContext
is
deprecated for Android 10.
Primary Zone
The primary zone is where all audio will be routed to by default. There can
only be one primary zone, which is indicated in the configuration by the
attribute isPrimary="true"
. If no primary zone is specified, the system
will by default nominate the first zone in the list.
Sample Configuration
For the example use case defined earlier, the vehicle would need two zones, a
primary zone and a rear seat entertainment system. With that,
a possible car_audio_configuration.xml
would be defined as follows:
<audioZoneConfiguration version="1.0"> <zone name="primary zone" isPrimary="true"> <volumeGroups> <group> <device address="bus0_media_out"> <context context="music"/> </device> <device address="bus3_call_ring_out"> <context context="call_ring"/> </device> <device address="bus6_notification_out"> <context context="notification"/> </device> <device address="bus7_system_sound_out"> <context context="system_sound"/> </device> </group> <group> <device address="bus1_navigation_out"> <context context="navigation"/> </device> <device address="bus2_voice_command_out"> <context context="voice_command"/> </device> </group> <group> <device address="bus4_call_out"> <context context="call"/> </device> </group> <group> <device address="bus5_alarm_out"> <context context="alarm"/> </device> </group> </volumeGroups> <displays> <display port="0"/> </displays> </zone> <zone name="rear seat zone"> <volumeGroups> <group> <device address="bus100_rear_seat"> <context context="music"/> <context context="navigation"/> <context context="voice_command"/> <context context="call_ring"/> <context context="call"/> <context context="alarm"/> <context context="notification"/> <context context="system_sound"/> </device> </group> </volumeGroups> <displays> <display port="1"/> </displays> </zones> </audioZoneConfiguration>
Here the primary zone has separated out contexts to individual devices. This
enables the HAL to apply different post-processing effects and mixing on each
device output using the vehicle's hardware. The devices have been arranged into
four volume groups: media, navigation, calls, and alarms. If the system is
configured to useFixedVolume
, then the volume levels for each group
will be passed onto the HAL to apply to the output of these devices.
For the secondary zone, the expected output is through a single headphone jack. In this example, all usages are routed to the single device and volume group to keep things simple.
For each zone, an optional list of displays can be included, with a physical display port associated with each display. This enables some applications to query for the zone associated with a specific display that it wants to target (see below).
New hidden APIs (OEMs and system applications only)
A series of hidden APIs have been introduced to CarAudioManager
in 10 to allow apps to query and set audio zones and focus.
int[] getAudioZoneIds(); int getZoneIdForUid(int uid); boolean setZoneIdForUid(int zoneId, int uid); boolean clearZoneIdForUid(int uid); int getZoneIdForDisplay(Display display);
Changing zones for an app
By default, all audio routes to the primary zone. To update an application to
be routed to a different zone, use setZoneIdForUid
:
int zoneIdForDisplayId = mCarAudioManager.getZoneIdForDisplay(selectedDisplay);
Int uid = mContext.getPackageManager() .getApplicationInfo(mContext.getPackageName(), 0) .uid;
if (mCarAudioManager.setZoneIdForUid(zoneId, info.uid)) { Log.d(TAG, "Zone successfully updated"); } else { Log.d(TAG, "Failed to change zone"); }
Note: Streams cannot dynamically switch zones. Therefore, playback must be stopped to change zones.