Audio Focus

Before starting a logical stream, an app should request audio focus using the same audio attributes as it is used for its logical stream. While sending such a focus request is recommended, it isn't enforced by the system. Some apps may explicitly skip sending the request to achieve specific behaviors (for example, to intentionally play sound during a phone call).

For this reason, you should consider focus as a way to indirectly control and deconflict playback, and not as a primary audio control mechanism; the vehicle shouldn't depend on the focus system for operation of the audio subsystem.

Focus interactions

To support the needs of AAOS, audio focus requests are handled based on predefined interactions between the request's CarAudioContext and that of current focus holders. There are three types of interactions: exclusive, reject, and concurrent.

Exclusive interaction

In exclusive interactions only one application is allowed to hold focus at a time. Therefore the incoming focus request is granted focus while the existing focus holder loses focus. An example of this would be when a user starts a new music application while music is already playing in an existing application. Since both are playing media, only one of the applications is allowed to hold focus at a time. As a result, the newly started application's focus request returns with AUDIOFOCUS_REQUEST_GRANTED and the application currently playing music receives a focus change event with a loss status that corresponds to the type of request that was made. This is the interaction model most commonly seen with Android.

Reject interaction

With reject interactions, the incoming request is always rejected. Attempting to play music while a call is in progress is an example of a rejected interaction. In this case, if the dialer is currently holding audio focus for a call and a second application request focus to play music, the music application receives AUDIOFOCUS_REQUEST_FAILED in response to its request. Since the focus request is rejected, no focus loss of any type is dispatched to the current focus holder.

Concurrent interaction

Most unique to AAOS are the concurrent interactions. This gives applications requesting audio focus in the car the ability to hold focus concurrently with other applications. For a concurrent interaction to take place, the following conditions must be met. The:

If these criteria are met, then the focus request returns with AUDIOFOCUS_REQUEST_GRANTED while the current focus holder has no change in focus. However, if the current focus holder opts to receive duck events or to pause when ducked, the current focus holder loses focus just as with an exclusive interaction.

Handling concurrent streams

While the concurrent interaction has many useful applications, OEMs must take care of the mixing and ducking at the hardware level across output devices. Because of this, it is strongly recommended that CarAudioContexts only be routed to the same output device as CarAudioContexts that they cannot play concurrently with. By having separate output devices for concurrent streams, this enables the HAL to duck one of the streams before mixing them together, or to route the physical streams to different speakers in the vehicle. If the logical streams are mixed within Android, their gains are not altered and are delivered as part of the same physical stream.

For example, when navigation and media are delivered simultaneously, the gain for the media stream could temporarily be reduced (ducked) so the navigation instructions can be heard more clearly. Alternatively, the navigation stream could be routed to the driver side speakers while media continues to play throughout the rest of the cabin.

Interaction matrix

The table below shows the interaction matrix as defined by CarAudioService. The rows represent the current focus holder's CarAudioContext and the columns represent that of the incoming request.

Looking at an example, where a music media app is currently holding focus and a navigation app request focus, the matrix shows that the two interactions can play concurrently, assuming the other criteria for Concurrent interactions are met.

Because of the concurrent interactions, it is possible for more than one focus holder to exist. In this case, an incoming focus request is compared with each of the current focus holders before deciding what sort of interaction to apply. In this case, the most conservative interaction wins out (reject, then exclusive, and finally concurrent).

In the following table, focus interactions between the CarAudioContext for an incoming focus request (columns) and the context of existing focus holders (rows) are provided. Each cell represents the expected interaction type for the two contexts.

Audio focus interactions

Figure 1. Audio focus interactions

In Android 11, a new user setting has been introduced to allow users to alter the interaction behavior between navigation and phone calls. When set, android.car.KEY_AUDIO_FOCUS_NAVIGATION_REJECTED_DURING_CALL changes the interaction between incoming NAVIGATION focus requests and current CALL focus holders from concurrent to reject. So if a user would prefer not to have navigation instructions interrupting their call, they can enable this setting. This is persisted for the user, and can be set dynamically so that subsequent focus requests respect the new setting value.

Delayable audio focus

In Android 11, AAOS has added support for requesting delayable audio focus. This allows non-transient focus requests to be delayed when their interaction with current focus holders would normally result in them being rejected. Once a change in focus results in a state where the delayed request can gain focus, the request is granted.

Rules for delayed audio focus requests

  • Non-transient requests only - as previously mentioned, a delayed request can only be made for non-transient sources. This is to avoid having a transient sound play long after it's relevant.
  • Only one request can be delayed at a time - If a delayable request is made while there is already a delayed request, the original delayed request receives a AUDIOFOCUS_LOSS change event, and the new request receives a synchronous response of AUDIOFOCUS_REQUEST_DELAYED.
  • Delayable requests must have an OnAudioFocusChangeListener. Once a request is delayed, the listener is used to notify the requester when the request eventually is granted (AUDIOFOCUS_GAIN), or if it's rejected later on (AUDIOFOCUS_LOSS).

Request delayable focus

To build a request that can be delayed, use the AudioFocusRequest.Builder#setAcceptsDelayedFocusGain:

mMediaWithDelayedFocusListener = new MediaWithDelayedFocusListener();

mDelayedFocusRequest = new AudioFocusRequest
     .Builder(AudioManager.AUDIOFOCUS_GAIN)
     .setAudioAttributes(mMusicAudioAttrib)
     .setOnAudioFocusChangeListener(mMediaWithDelayedFocusListener)
     .setForceDucking(false)
     .setWillPauseWhenDucked(false)
     .setAcceptsDelayedFocusGain(true)
     .build();

Then, when making the request, handle the AUDIOFOCUS_REQUEST_DELAYED response:

int delayedFocusRequestResults = mAudioManager.requestAudioFocus(mDelayedFocusRequest);
if (delayedFocusRequestResults == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
// start audio playback
return;
}
if (delayedFocusRequestResults == AudioManager.AUDIOFOCUS_REQUEST_DELAYED) {
     // audio playback delayed to audio focus listener
     return;
}

When the request is delayed, the focus listener is responsible for handling changes in focus:

private final class MediaWithDelayedFocusListener implements
OnAudioFocusChangeListener {
       @Override
       public void onAudioFocusChange(int focusChange) {
           synchronized (mLock) {
               switch (focusChange) {
                   case AudioManager.AUDIOFOCUS_GAIN:
                        // Start focus playback
                   case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
                        // Pause media transiently
                   case AudioManager.AUDIOFOCUS_LOSS:
                        // Stop media

Multi-zone focus management

For vehicles with multiple audio zones, audio focus is managed independently for each zone. As such, a request to one zone doesn't take into account what is holding focus in other zones, nor does it cause focus holders in other zones to lose focus. With this, the main cabin's focus can be managed separately from a rear seat entertainment system, thus avoiding interrupting the audio playback in one zone by the changes in focus in another.

For all applications focus management is taken care of by the CarAudioService automatically. A focus request's audio zone is determined based on its associated UserId or UID. For details, see Audio Routing.

Requesting audio from multiple zones concurrently

If an app wants to play audio in multiple zones concurrently, it must request focus for each zone by including AUDIOFOCUS_EXTRA_REQUEST_ZONE_ID in the bundle:

// Create attribute with bundle and AUDIOFOCUS_EXTRA_REQUEST_ZONE_ID
Bundle bundle = new Bundle();
bundle.putInt(CarAudioManager.AUDIOFOCUS_EXTRA_REQUEST_ZONE_ID,
               zoneId);

AudioAttributes attributesWithZone = new AudioAttributes.Builder()
     .setUsage(AudioAttributes.USAGE_MEDIA)
     .addBundle(bundle)
     .build();

// Create focus request using built attributesWithZone

This bundle parameter allows the requester to override the automatic audio zone mappings to instead use the specified zone ID. Therefore, with this an app could issue separate requests for different audio zones.

HAL Audio Focus

Starting in Android 11, the HAL is now enabled to request focus on behalf of external streams. While optional, these APIs are highly encouraged to enable external sounds to be better participants in the Android ecosystem and to provide a smoother user experience.

Keep in mind that the HAL is still responsible for making the final call around what sounds should get priority. To this extent, emergency and safety critical sounds should be played regardless of whether or not the HAL is granted audio focus, and should continue to be played as appropriate even if the HAL loses audio focus. The same is true for any sounds required by regulations.

Along the same lines, the HAL should still proactively mute Android streams as appropriate when playing emergency or safety critical sounds to ensure they are heard clearly.

AudioControl@2.0

Version 2.0 of AudioControl HAL introduces several new APIs:

API Purpose
IAudioControl#registerFocusListener Registers an instance of IFocusListener with the AudioControl HAL. This listener enables the HAL to request and abandon audio focus. The HAl is expected to provide an ICloseHandle instance to be used by Android to unregister the listener.
IAudioControl#onAudioFocusChange Notifies the HAL of changes in status to focus requests made by the HAL through the IFocusListener. This includes responses to initial focus requests.
IFocusListener#requestAudioFocus Requests focus on behalf of the HAL for a specified usage, zone Id, and focus gain type.
IFocusListener#abandonAudioFocus Abandons existing HAL focus requests for the specified usage and zone Id.

The HAL can have multiple focus requests at the same time, but is limited to one request per usage and zone Id pairing. Note that Android assumes the HAL immediately starts to play sounds for a usage once a request has been made, and continues to do so till it abandons focus.

Other than registerFocusListener, these requests are all oneway to ensure that Android does not delay the HAL while a focus request is processed. The HAL should not wait to gain focus before playing safety-critical sounds. It's optional for the HAL to listen for and respond to changes in audio focus through IAudioControl#onAudioFocusChange, although encouraged when appropriate.