Skip to content

Audio

Car audio architecture

Zones, contexts and buses — why car audio is a routing problem before it is a playback problem, and how the configuration file decides everything.

Advanced5 minAudio · CarAudioService · Routing

Phone audio has one output and a volume key. Car audio has a dozen speakers, an external amplifier, chimes that must never be ducked, a rear-seat zone with its own volume, and a navigation prompt that has to be audible over music without stopping it.

The model that handles this is zones, contexts and buses.

Contexts are routed to buses, buses belong to a zoneMUSICNAVIGATIONVOICE_COMMANDCALL / RINGaudio contextsbus0_mediabus1_navbus2_voicebus3_calloutput devices (buses)Zone 0cabin / driverbus0–bus3Zone 1rear seatindependent focuszones
Contexts route to buses, buses belong to zonesAn audio context describes what a sound is for. A bus is a physical output. A zone is a place in the vehicle with its own volume and focus.

The three concepts#

Audio context — what kind of sound is this?#

A semantic category derived from the stream's AudioAttributes: MUSIC, NAVIGATION, VOICE_COMMAND, CALL, ALARM, NOTIFICATION, SYSTEM_SOUND, EMERGENCY, SAFETY, VEHICLE_STATUS.

Context is not a channel. It is a statement of intent, and it is what the routing and ducking rules act on.

Output device (bus) — where does it physically go?#

A bus is an output the audio HAL exposes — bus0_media_out, bus1_nav_out and so on. Behind each is a path through the amplifier to real speakers.

Multiple buses matter because an external amplifier can then mix them independently: navigation can be attenuated relative to music by the amp, in hardware, with no software ducking at all.

Zone — where in the vehicle?#

A set of buses plus its own volume groups and its own focus state. Zone 0 is the main cabin. A rear-seat entertainment system is another zone, where a passenger can play something at their own volume while the driver hears navigation.

Zones have independent focus

Two zones can each have an active focus owner at the same time. That is the whole point: a rear passenger's video should not pause because the driver got a navigation prompt in the front.

The configuration file decides everything#

car_audio_configuration.xml is where the whole topology is declared. Get it wrong and audio either does not play or plays out of the wrong speakers.

car_audio_configuration.xml
<carAudioConfiguration version="3">
  <zones>
    <zone name="primary" isPrimary="true" occupantZoneId="0">
      <volumeGroups>
 
        <group>
          <device address="bus0_media_out">
            <context context="music"/>
            <context context="announcement"/>
          </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="bus3_call_out">
            <context context="call"/>
            <context context="call_ring"/>
          </device>
        </group>
 
        <!-- Safety chimes get their own group so they can never be ducked
             along with media. -->
        <group>
          <device address="bus4_alarm_out">
            <context context="alarm"/>
            <context context="emergency"/>
            <context context="safety"/>
          </device>
        </group>
 
      </volumeGroups>
    </zone>
 
    <zone name="rear_seat" occupantZoneId="1">
      <volumeGroups>
        <group>
          <device address="bus100_rear_media_out">
            <context context="music"/>
            <context context="navigation"/>
            <context context="voice_command"/>
            <context context="call"/>
            <context context="alarm"/>
            <context context="notification"/>
            <context context="system_sound"/>
            <context context="emergency"/>
            <context context="safety"/>
            <context context="vehicle_status"/>
            <context context="announcement"/>
          </device>
        </group>
      </volumeGroups>
    </zone>
  </zones>
</carAudioConfiguration>

Every context must be routed in every zone

A zone that omits a context has undefined behaviour for that sound — typically silence, discovered when someone finally makes a phone call from the rear seat. The rear zone above lists all eleven contexts on one device precisely because of this. Validate exhaustively, not by ear.

Volume groups#

A volume group is a set of devices that move together under one control. The driver's volume knob adjusts the group for whatever is currently dominant, not one global level — which is why turning the knob during a navigation prompt changes navigation volume, not music.

Volume through CarAudioManager
val audio = car.getCarManager(Car.AUDIO_SERVICE) as CarAudioManager
 
val zoneId = CarAudioManager.PRIMARY_AUDIO_ZONE
val groupCount = audio.getVolumeGroupCount(zoneId)
 
val max = audio.getGroupMaxVolume(zoneId, groupId)
val current = audio.getGroupVolume(zoneId, groupId)
 
audio.setGroupVolume(zoneId, groupId, current + 1, /* flags = */ 0)

setGroupVolume needs android.car.permission.CAR_CONTROL_AUDIO_VOLUME, which is signature-level. Ordinary apps change their own stream volume; only system apps drive the vehicle's volume model.

Getting your audio into the right context#

Your app controls its context through AudioAttributes. This is the single most important audio decision an automotive app makes.

Declaring intent correctly
// Music player
val musicAttrs = AudioAttributes.Builder()
    .setUsage(AudioAttributes.USAGE_MEDIA)
    .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
    .build()
 
// Navigation prompt — routed to the nav bus, ducks media rather than pausing it
val navAttrs = AudioAttributes.Builder()
    .setUsage(AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE)
    .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
    .build()

Declare what the sound is. An app that marks navigation prompts as USAGE_MEDIA will have them routed to the media bus, ducked like music, and possibly silenced by a rear passenger's volume control.

Debugging#

Audio state
adb shell dumpsys car_service --services CarAudioService
adb shell dumpsys audio_flinger
adb shell dumpsys audio_policy
 
# What devices does the HAL actually expose?
adb shell lshal | grep -i audio

The CarAudioService dump shows zones, volume groups, device addresses and the current focus holders. When audio comes out of the wrong speaker, compare that dump against your configuration XML — the mismatch is almost always there.

Common failures#

SymptomCause
No audio at all from one appIts context is not routed in that zone
Navigation ducks everything, including chimesSafety contexts share a group with media
Rear zone silent on callscall context missing from the rear zone
Volume knob affects the wrong thingContexts grouped into the wrong volume group
Works on emulator, silent on targetBus addresses in XML do not match the HAL's

That last one is the classic bring-up bug: the configuration references bus0_media_out and the audio HAL calls it bus0_output. Nothing errors; the routing simply never matches.

Next#

Focus and ducking — the policy layer that decides who is audible when.

References & further reading

Code links target the main branch on cs.android.com. AOSP moves — if a path 404s, search the symbol instead.