Typically, there is at most one application which holds audio focus globally at any time. When another application requests focus, the former one receives a focus loss event, and then the new one is granted focus. There are some exceptions to this behavior; for example, when a call holds focus, new focus requests are rejected.
New context interaction definitions
Starting in Android 9, car audio focus is managed differently. An interaction matrix has been introduced to CarAudioFocus that captures the desired behavior when a focus request comes based on the usage types of both the new source as well as the one currently holding focus. There are three interaction types:
Exclusive Interaction
In exclusive application context interactions only one application is allowed
to hold focus at a time. An example of this would be two media player
applications, since both are playing media only one of the applications is
allowed to hold focus. This is the default interaction between most focus holder
and focus requester when both request AudioManager.AUDIOFOCUS_GAIN
.
In such case, when the incoming focus request is granted an AudioManager.AUDIOFOCUS_LOSS
is dispatched to current focus holders. Exclusive usage interactions
may also request different audio focus other then AudioManager.AUDIOFOCUS_GAIN
.
Still, the interaction will be exclusive and a focus loss of the appropriate
type will be dispatched.
Reject Interaction
With reject context interaction, the request is always rejected for the incoming focus requester. Attempts to transition from Notification to Alarm is an example of reject usage interaction. In this case, if an application playing notification ringtone is currently holding audio focus and a second application request focus to play alarm, the alarm application will receive a focus request rejection. Since the focus request is rejected no focus loss of any type is dispatched to current focus holder.
Concurrent Interaction
Most interesting to the car audio users are the concurrent context
interactions. This gives applications requesting audio focus in the car the
ability to play sound concurrently with other applications. This, along with the
car audio routing, gives OEM the ability to concurrently route audio sounds to
different parts of the car. In order for a concurrent interaction to take
place, the focus requester must ask for AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
.
setPauseWhenDucked(true)
when used in conjunction with AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
continues to work as expected. Dk events will be delivered for concurrent
focus requests so that the application can pause playback. The latter is
typically used by audio books applications to keep user from missing any event
in the audio.
While the concurrent interaction has many useful applications, OEMs must take care of the mixing and ducking at the hardware level across output devices. For example, when navigation and media are delivered simultaneously, OEM may want to temporarily mute media playing in the driver side speaker (duck media) and play navigation instead. If the configuration of the car is such that media and navigation are delivered to different devices this can be accomplished by ducking media when any data is delivery to the navigation device. In this manner OEM can play navigation instructions on the driver side while media continues to play through the rest of the cabin. If however the two sources are mixed into the same output device, then no ducking will be applied. It's therefore recommended that any contexts that can be played concurrently should be routed to separate devices so that ducking can be handled appropriately.
Interaction Matrix
Table 1 below shows the interaction matrix defined in CarAudioFocus. In the table, rows represent the current application holding focus and columns represent the incoming focus requester.
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. If the focus requested by the incoming navigation
application is AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
,
then focus request will be granted and no focus loss will be sent to the media
application. It is possible for more than one focus holder to exist. In this case, an
incoming focus requester will be compared with each of the current focus holders
before deciding what sort of transitions to apply.
Table 1. Car Audio Focus usage interaction matrix.
Context of an incoming focus requester:
Context | Invalid | Music | Nav | Voice | Ring | Call | Alarm | Noti | Sys |
---|---|---|---|---|---|---|---|---|---|
Invalid | REJ | REJ | REJ | REJ | REJ | REJ | REJ | REJ | REJ |
Music | REJ | EXC | CON | EXC | EXC | EXC | EXC | CON | CON |
Nav | REJ | CON | CON | EXC | CON | EXC | CON | CON | CON |
Voice | REJ | CON | REJ | CON | EXC | EXC | REJ | REJ | REJ |
Ring | REJ | REJ | CON | CON | CON | CON | REJ | REJ | CON |
Call | REJ | REJ | CON | REJ | CON | CON | CON | CON | REJ |
Alarm | REJ | CON | CON | EXC | EXC | EXC | CON | CON | CON |
Noti | REJ | CON | CON | EXC | EXC | EXC | CON | CON | CON |
Sys | REJ | CON | CON | EXC | EXC | EXC | CON | CON | CON |
Legend:
- REJ. Reject
- EXC. Exclusive
- CON. Concurrent
For details, see packages/services/Car/service/src/com/android/car/audio/CarAudioFocus.java
Multi-zone focus management
In Android 10, the rules for application usage interactions from Android 9 are maintained but focus is further separated for each audio zone. 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 and set via the CarAudioManager.setZoneIdForUid
API. Once a UID has been mapped to a particular zone focus will be automatically
requested from that zone. Here is an example of focus request:
//Create focus ret = mAudioManager .requestAudioFocus(mFocusListener, mMusicAudioAttrib,AudioManager.AUDIOFOCUS_GAIN, 0);
if (ret == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) { Log.i(TAG, "Got focus for usage " + mMusicAudioAttrib.getUsage()); start(); } else { Log.i(TAG, "MediaPlayer denied focus for usage " + mMusicAudioAttrib.getUsage()); }
This is no different as to how a third party app would request focus, thus third party apps can still use the audio zone capability with the caveat that zone management must be taken be cared by an OEM app launcher or some other management app.
Streaming to multiple zones concurrently
In the case of apps streaming to a single zone, audio focus operates the same
from the app's perspective, and zone management can be set by using
CarAudioManager.setZoneIdForUid
. However, 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, zoneIdForDisplayId);
mMusicAudioAttribForDisplay = new AudioAttributes.Builder() .setUsage(AudioAttributes.USAGE_MEDIA) .addBundle(bundle) .build();
//Create focus