Audio control HAL

Audio control HAL was introduced in Android 9 to support audio use cases relevant to automotive. As of Android 14, Audio control HAL supports:

  • Fade and balance
  • HAL audio focus request
  • Device muting and ducking
  • Audio device gain changes
  • Audio port configuration changes

Figure 1 shows a high-level overview of the car audio service architecture, in which the car audio service communicates with the audio control HAL.

Configure multi-zone audio

Figure 1. Configure multi-zone audio.

Audio fade and balance

HIDL audio control HAL version 1 was introduced in Android 9 to support audio fade and balance in automotive use cases. Separate from the generic audio effects already provided in Android, this mechanism allows for system apps to set the audio balance and fade through CarAudioManager APIs:

class CarAudioManager {
       /**
       *   Adjust the relative volume in the front vs back of the vehicle cabin.
       *
       *   @param value in the range -1.0 to 1.0 for fully toward the back through
       *   fully toward the front. 0.0 means evenly balanced.
       */
       @SystemApi
       @RequiresPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME)
       public void setFadeTowardFront(float value);

       /**
       *   Adjust the relative volume on the left vs right side of the vehicle cabin.
       *
       *   @param value in the range -1.0 to 1.0 for fully toward the left through
       *   fully toward the right. 0.0 means evenly balanced.
       */
       @SystemApi
       @RequiresPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME)
       public void setBalanceTowardRight(float value);
}

Once these APIs are called, the respective audio control HAL APIs are called from the car audio service:

interface IAudioControl {
       /**
       *   Control the right/left balance setting of the car speakers.
       */
       oneway setBalanceTowardRight(float value);

       /**
       *   Control the fore/aft fade setting of the car speakers.
       */
       oneway setFadeTowardFront(float value);
}

The API is available on all versions of the audio control HAL, including the new AIDL HAL interface.

Audio focus request from HAL

AAOS, similar to Android, relies on the active participation of apps on audio focus to manage audio playback in cars. The focus information is used to manage which streams to control for volume and ducking. As such, to further expand on the audio focus and to provide a better integration of car specific sounds into the Android experience, the following audio attributes were introduced in Android 11:

  • EMERGENCY
  • SAFETY
  • VEHICLE_STATUS
  • ANNOUNCEMENT

In addition to this change, a mechanism was added for sounds that originate from outside Android to participate in audio focus requests. Thus, the HIDL audio control HAL version 2 was introduced to allow for focus requests that originate from outside Android:

interface IAudioControl {
       /**
       *   Registers focus listener to be used by HAL for requesting and
       *   abandoning audio focus.
       *   @param listener the listener interface
       *   @return closeHandle A handle to unregister observer.
       */
       registerFocusListener(IFocusListener listener)
       generates (ICloseHandle closeHandle);

       /**
       *   Notifies HAL of changes in audio focus status for focuses requested
       *   or abandoned by the HAL.
       *
       *   @param usage The audio usage associated with the focus change
       *   @param zoneId The identifier for the audio zone that the HAL is
       *   playing the stream in
       *   @param focusChange the AudioFocusChange that has occurred
       */
       oneway onAudioFocusChange(bitfield<AudioUsage> usage, int32_t zoneId,
       bitfield<AudioFocusChange> focusChange);
}

Where the IFocusListener is defined as:

interface IFocusListener {
       /**
       *   Called whenever HAL is requesting focus as it is starting to play
       *   audio of a given usage in a specified zone.
       *
       *   @param usage The audio usage associated with the focus request
       *    {@code AttributeUsage}
       *   @param zoneId The identifier for the audio zone where the HAL is
       *    requesting focus
       *   @param focusGain The AudioFocusChange associated with this request.
       */
       oneway requestAudioFocus(bitfield<AudioUsage> usage,
       int32_t zoneId, bitfield<AudioFocusChange> focusGain);
       /**
       *   Called whenever HAL is abandoning focus as it is finished playing audio
       *   of a given usage in a specific zone.
       *
       *   @param usage The audio usage for which the HAL is abandoning focus
       *    {@code AttributeUsage}
       *   @param zoneId The identifier for the audio zone that the HAL
       *    abandoning focus
       */
       oneway abandonAudioFocus(bitfield<AudioUsage> usage, int32_t zoneId);
}

The APIs above can be used to request and abandon audio focus from the HAL, respectively. In response, the car audio service considers the audio focus request and forwards the results asynchronously to the IAudioControl#onAudioFocusChange method.

This API can also be used to monitor changes for the audio focus request that originates from the audio control HAL. In general, any standing audio focus request from the HAL is considered active, which differs from an audio focus request from Android, in which only a corresponding active audio track playback is regarded as active.

Migrate HIDL to AIDL audio control HAL

With the advent of AIDL and the required migration in Android 12 (to learn more, see AIDL for HALs), the audio control HAL was migrated to AIDL. For existing HIDL audio control version 2 APIs, the migration required minor updates to the existing methods:

interface IAudioControl {
       /**
       *   Notifies HAL of changes in audio focus status for focuses requested
       *   or abandoned by the HAL.
       *
       *   @param usage The audio usage associated with the focus change
       *        {@code AttributeUsage}. See {@code audioUsage} in
       *        audio_policy_configuration.xsd for the list of allowed values.
       *   @param zoneId The identifier for the audio zone that the HAL is
       *        playing the stream in
       *   @param focusChange the AudioFocusChange that has occurred.
       */
       oneway void onAudioFocusChange(in String usage, in int zoneId,
              in AudioFocusChange focusChange);
       /**
       *   Registers focus listener to be used by HAL for requesting and
       *   abandoning audio focus.
       *   @param listener the listener interface.
       */
       oneway void registerFocusListener(in IFocusListener listener);
       /**
       *   Control the right/left balance setting of the car speakers.
       */
       oneway void setBalanceTowardRight(in float value);
       /**
       *   Control the fore/aft fade setting of the car speakers.
       */
       oneway void setFadeTowardFront(in float value);
}

And the corresponding IFocusListener:

       interface IFocusListener {
       /**
       *   Called whenever HAL is abandoning focus as it is finished playing audio
       *   of a given usage in a specific zone.
       *
       *   @param usage The audio usage for which the HAL is abandoning focus
       *        {@code AttributeUsage}. See {@code audioUsage} in
       *        audio_policy_configuration.xsd for the list of allowed values.
       *   @param zoneId The identifier for the audio zone that the HAL
       *        abandoning focus
       */
       oneway void abandonAudioFocus(in String usage, in int zoneId);
       /**
       *   Called whenever HAL is requesting focus as it is starting to play audio
       *        of a given usage in a specified zone.
       *
       *   @param usage The audio usage associated with the focus request
       *        {@code AttributeUsage}. See {@code audioUsage} in
       *        audio_policy_configuration.xsd for the list of allowed values.
       *   @param zoneId The identifier for the audio zone where the HAL is
       *        requesting focus
       *   @param focusGain The AudioFocusChange associated with this request.
       */
       oneway void requestAudioFocus(in String usage, in int zoneId,
              in AudioFocusChange focusGain);
}

Volume group muting

Android 12 introduced volume group muting to allow for a more comprehensive mute control during the user's audio interactions. This allows for the audio control HAL to receive muting events as intercepted by car audio service.

To enable the feature, OEMs must set the audioUseCarVolumeGroupMuting config to true in the car service config.xml:

<!-- Configuration to enable muting of individual volume groups.
If this is set to false, muting of individual volume groups is disabled,
instead muting will toggle master mute. If this is set to true, car volume
group muting is enabled and each individual volume group can be muted separately. -->
<bool name="audioUseCarVolumeGroupMuting">true</bool>

Before Android 13, the config had to be overwritten with a runtime resource overlay for packages/services/Car/service/res/values/config.xml (to learn more, see Customizing the build with resource overlays). From Android 13, you can use runtime resource overlays to change a configuration value. To learn more, see Change the value of an app's resources at runtime.

System apps can determine if the feature is enabled by using the CarAudioManager#isAudioFeatureEnabled API. The parameter passed in must be the CarAudioManager.AUDIO_FEATURE_VOLUME_GROUP_MUTING constant. The method returns true if the feature is enabled on the device, otherwise false.

In addition to enabling the audioUseCarVolumeGroupMuting feature, the AIDL audio control HAL must implement the volume group muting mechanism:

interface IAudioControl {
       /**
       *   Notifies HAL of changes in output devices that the HAL should apply
       *   muting to.
       *
       *   This will be called in response to changes in audio mute state for each
       *   volume group and will include a {@link MutingInfo} object per audio
       *   zone that experienced a mute state event.
       *
       *   @param mutingInfos an array of {@link MutingInfo} objects for the audio
       *   zones where audio mute state has changed.
       */
       oneway void onDevicesToMuteChange(in MutingInfo[] mutingInfos);
}

Where muting info contains the pertinent mute information for the audio system:

parcelable MutingInfo {
       /**
       *   ID of the associated audio zone
       */
       int zoneId;
       /**
       *   List of addresses for audio output devices that should be muted.
       */
       String[] deviceAddressesToMute;
       /**
       *   List of addresses for audio output devices that were previously be
       *   muted and should now be unmuted.
       */
       String[] deviceAddressesToUnmute;
}

AAOS has two different mechanisms for muting, based on:

  • Key events using the audio KEYCODE_VOLUME_MUTE {:.external}.

  • Direct calls to the car audio service using the car audio manager mute API, CarAudioManager#setVolumeGroupMute.

When enabled, both mechanisms trigger a call mute to the audio control HAL.

Car audio ducking

Android 12 introduced car audio ducking to optimize control of concurrent playback of audio streams. This allows OEMs to implement their own ducking behavior based on a car’s physical audio configuration and current playback state, as determined by the car audio service.

The ducking mechanism is based on the audio focus stack changes. Whenever a focus change occurs (whether a focus request or focus abandon), the audio control HAL is informed. Similar to the car volume group muting support, car audio ducking can be enabled with the audioUseHalDuckingSignals config flag:

<!-- Configuration to enable IAudioControl#onDevicesToDuckChange API to
inform HAL when to duck. If this is set to true, the API will receive signals
indicating which output devices to duck as well as what usages are currently
holding focus. If set to false, the API will not be called. -->
<bool name="audioUseHalDuckingSignals">true</bool>

To enable the feature, the AIDL audio control HAL must implement the relevant logic with the signal received from the car audio service:

interface IAudioControl {
       /**
       *   Notifies HAL of changes in output devices that the HAL should apply
       *   ducking to.
       *
       *   This will be called in response to changes in audio focus, and will
       *   include a {@link DuckingInfo} object per audio zone that experienced
       *   a change in audo focus.
       *
       *   @param duckingInfos an array of {@link DuckingInfo} objects for the
       *   audio zones where audio focus has changed.
       */
       oneway void onDevicesToDuckChange(in DuckingInfo[] duckingInfos);
}

The relevant audio system information is contained in the audio ducking information:

parcelable DuckingInfo {
       /**
       *   ID of the associated audio zone
       */
       int zoneId;
       /**
       *   List of addresses for audio output devices that should be ducked.
       */
       String[] deviceAddressesToDuck;
       /**
       *   List of addresses for audio output devices that were previously be
       *   ducked and should now be unducked.
       */
       String[] deviceAddressesToUnduck;
       /**
       *   List of usages currently holding focus for this audio zone.
       */
       String[] usagesHoldingFocus;
}

Aside from car audio configuration information contained in the device addresses to (un)duck, ducking information also contains information about which audio attribute usages are holding focus. The intention for this data is to inform the audio system which audio attributes usages are active.

This is required since, in the car audio configuration, multiple audio attributes can be assigned to a single device and, without the extra information, it's not clear which usages are active.

AIDL audio control HAL 2.0

To update APIs and to facilitate new functionality, the AIDL audio control HAL was updated to version 2.0 in Android 13:

  • Audio focus with PlaybackTrackMetadata
  • Audio gains callback

Playback metadata is defined in android.hardware.audio.common as follows:

parcelable PlaybackTrackMetadata {
       AudioUsage usage = INVALID;
       AudioContentType contentType = UNKNOWN;
       float gain;
       AudioChannelLayout channelMask;
       AudioDevice sourceDevice;
       String[] tags;
}

All other functionality from AIDL audio control version 1.0 remained and can be used. An exception pertains to the audio focus change method, as described in On audio focus change method.

Audio control focus with playback track metadata

To expose more information to the audio system below the HAL, updates now expose PlaybackTrackMetadata. Specifically, the audio control HAL was expanded with a new method:

interface IAudioControl {
       /**
       *   Notifies HAL of changes in audio focus status for focuses requested
       *   or abandoned by the HAL.
       *
       *   The HAL is not required to wait for a callback of AUDIOFOCUS_GAIN
       *   before playing audio, nor is it required to stop playing audio in the
       *   event of a AUDIOFOCUS_LOSS callback is received.
       *
       *   @param playbackMetaData The output stream metadata associated with
       *    the focus request
       *   @param zoneId The identifier for the audio zone that the HAL is
       *    playing the stream in
       *   @param focusChange the AudioFocusChange that has occurred.
       */
       oneway void onAudioFocusChangeWithMetaData(
       in PlaybackTrackMetadata playbackMetaData, in int zoneId,
       in AudioFocusChange focusChange);
}

A similar, corresponding, change is made to IFocusListener:

       /**
       *   Called to indicate that the audio output stream associated with
       *   {@link android.hardware.audio.common.PlaybackTrackMetadata} is
       *   abandoning focus as playback has stopped.
       *
       *   @param playbackMetaData The output stream metadata associated with
       *    the focus request
       *   @param zoneId The identifier for the audio zone that the HAL
       *    abandoning focus
       */
       oneway void abandonAudioFocusWithMetaData(
       in PlaybackTrackMetadata playbackMetaData, in int zoneId);
       /**
       *   Called to indicate that the audio output stream associated with
       *   {@link android.hardware.audio.common.PlaybackTrackMetadata} has taken
       *   the focus as playback is starting for the corresponding stream.
       *
       *   @param playbackMetaData The output stream metadata associated with
       *    the focus request
       *   @param zoneId The identifier for the audio zone that the HAL
       *    abandoning focus
       *   @param focusGain The focus type requested.
       */
       oneway void requestAudioFocusWithMetaData(
       in PlaybackTrackMetadata playbackMetaData, in int zoneId,
       in AudioFocusChange focusGain);
}

On audio focus change method

The focus operations above perform in the same way as those described in Audio focus request from HAL. Only the playback track metadata has more information along with the audio attributes usages. In general, unless the extra information provided by playback track metadata is needed, the updated android control HAL can continue to use previous methods.

If HAL developers decide not to support IAudioControl#onAudioFocusChangeWithMetaData, the method should return results with the UNKNOWN_TRANSACTION error as described Using Versioned Interface Methods.

The audio service first calls onAudioFocusChangeWithMetaData and then retries with the onAudioFocusChange method if a UNKNOWN_TRANSACTION failure results.

Car audio ducking with playback track metadata

Version 2.0 of the AIDL audio control HAL added the playback track metadata to the audio ducking info:

parcelable DuckingInfo {
       /**
       *   ID of the associated audio zone
       */
       int zoneId;
       /**
       *   List of addresses for audio output devices that should be ducked.
       */
       String[] deviceAddressesToDuck;
       /**
       *   List of addresses for audio output devices that were previously be
       *   ducked and should now be unducked.
       */
       String[] deviceAddressesToUnduck;
       /**
       *   List of usages currently holding focus for this audio zone.
       */
       String[] usagesHoldingFocus;
       /**
       *   List of output stream metadata associated with the current focus
       *   holder for this audio zone
       */
       @nullable PlaybackTrackMetadata[] playbackMetaDataHoldingFocus;
}

usagesHoldingFocus is deprecated. Developers should now use playbackMetaDataHoldingFocus to determine the audio attribute usage and other audio information. That said, the usagesHoldingFocus parameter still contains the required information until this option is formally removed.

Audio gain callback

To make audio changes below the HAL more visible to the AAOS in Android 13, we added a mechanism you can use to communicate audio gains changes from the car’s audio system to the car audio service. The mechanism exposes audio gain volume index changes with a respective reason why the gain was changed:

  • Blocked or muted restrictions
  • Limitations restrictions
  • Attenuation restrictions

These changes expose these restrictions from below the HAL to the car audio service and, finally, to a system UI app to inform the user. The latter part, exposure to a possible system UI, was further expanded in Android 14 to allow for system UI apps to more readily get this information through a volume group information callback mechanism.

The audio control HAL API registers the gain callback as follows:

interface IAudioControl {
       /**
       *   Registers callback to be used by HAL for reporting unexpected gain(s)
       *    changed and the reason(s) why.
       *
       *   @param callback The {@link IAudioGainCallback}.
       */
       oneway void registerGainCallback(in IAudioGainCallback callback);
}

The IAudioGainCallback is defined as follows:

interface IAudioGainCallback {
       /**
       *   Used to indicate that one or more audio device port gains have changed,
       *   i.e. initiated by HAL, not by CarAudioService.
       *   This is the counter part of the
       *   {@link onDevicesToDuckChange}, {@link onDevicesToMuteChange} and,
       *   {@link setAudioDeviceGainsChanged} APIs.
       *
       *   @param reasons List of reasons that triggered the given gains changed.
       *   @param gains List of gains affected by the change.
       */
       void onAudioDeviceGainsChanged(in Reasons[] reasons,
       in AudioGainConfigInfo[] gains);
}

As highlighted in the API documentation, the gain callback is registered by the car audio service to the audio control HAL. When the API is called from the audio control HAL, the car audio service responds with a corresponding action (such as block, limit, or attenuate gain index) .

The HAL determines when the API is called, primarily to report changes to the gain index status. Specific to regulation requirements, the car’s audio system should take the required action and use the callback to report information to the car audio service to allow for user consumption. For example, to show a UI to the user.

AIDL audio control HAL 3.0

The Android 14 AIDL audio control HAL version is updated to version 3.0 to update the APIs to provide more robust audio gain index functionality. The audio control HAL API allows for the audio service to set and unset an IModuleChangeCallback:

interface IAudioControl {
       /**
       *   Sets callback with HAL for notifying changes to hardware module
       *   (that is: {@link android.hardware.audio.core.IModule}) configurations.
       *
       *   @param callback The {@link IModuleChangeCallback} interface to use
       *    use when new updates are available for
       */
       void setModuleChangeCallback(in IModuleChangeCallback callback);
       /**
       *   Clears module change callback
       */
       void clearModuleChangeCallback();
}

The setModuleChangeCallback is registered by the car audio service when the service starts or when recovering from an error. For example, an audio control HAL binder death notification received by the car audio service. The audio control HAL implementation should replace any existing module change callback when the API is called.

For the clearModuleChangeCallback API, the implementation should clear the existing callback or do nothing if one does not exist. It's a good practice for the audio control implementation to register a death observer for the callback and to then clear the callback if the on binder death is triggered.

IModuleChangeCallback is defined as follows:

oneway interface IModuleChangeCallback {
       /**
       *   Used to indicate that one or more {@link AudioPort} configs have
       *   changed. Implementations MUST return at least one AudioPort.
       *
       *   @param audioPorts list of {@link AudioPort} that are updated
       */
       void onAudioPortsChanged(in AudioPort[] audioPorts);
}

When the module change callback is registered by the car audio service, it's ready to receive audio port changes through the onAudioPortChanged API. The API can be used to initialize volume gains for the audio system as soon as the callback is registered. For other dynamic gain changes, the API can be called anytime. Corresponding changes are applied and the car audio service is updated accordingly.