Skip to content

Most visited

Recently visited

navigation

Audio Focus Enhancements

Android assigns audio focus to one app at a time.

Beginning with Android 2.2 (API level 8), apps manage audio focus by calling requestAudioFocus() and abandonAudioFocus(). They also register an AudioManager.OnAudioFocusChangeListener with both calls in order to receive callbacks and manage their own audio level.

Android O introduces a new class, AudioFocusRequest, which contains information about the audio context and capabilities of your app. The system uses AudioFocusRequest to help manage the gain and loss of audio focus.

Major changes in the O Preview release

Requesting and abandoning audio focus

Beginning with Android O, the method requestAudioFocus() takes only one argument, an AudioFocusRequest. The method abandonAudioFocusRequest() replaces the method abandonAudioFocus(), and also takes an AudioFocusRequest as its argument. The same AudioFocusRequest instance should be used when requesting and abandoning focus.

Automatic ducking

Prior to Android O, when an app lost and regained audio focus while playing, it performed its own volume decrease and restoration in the onAudioFocusChange callback. Now, in Android O, when another application requests focus with AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK the system can duck and restore the volume without calling the app.

While automatic ducking is acceptable behavior for music and video playback applications, it isn't useful when playing spoken content (for instance, an audio book). In this case the application should pause instead.

If you want your app to pause when asked to duck rather than decrease its volume, create an OnAudioFocusChangeListener with an onAudioFocusChange() callback method that implements the desired pause/resume behavior. Call setOnAudioFocusChangeListener() to register the listener, and call setWillPauseWhenDucked(true) to tell the system to use your callback rather than perform automatic ducking.

Delayed focus gain

Sometimes the system cannot grant a request for audio focus because the focus is "locked" by another app (for instance, during a phone call). In this case requestAudioFocus() returns AUDIOFOCUS_REQUEST_FAILED. When this happens your application should not proceed with audio playback because it did not gain focus. Prior to Android O, there was no way for an app to wait for focus when the lock was lifted. An app would need to continually send requests until focus was granted.

Android O provides a method, setAcceptsDelayedFocusGain(true), that lets your app handle a request for focus asynchronously. With this flag set, a request made when the focus is locked returns AUDIOFOCUS_REQUEST_DELAYED. When the condition that locked the audio focus no longer exists (for instance, at the end of a phone call), the system grants the pending focus request and calls onAudioFocusChange() to notify your app.

In order to handle the delayed gain of focus, you must create an OnAudioFocusChangeListener with an onAudioFocusChange() callback method that implements the desired behavior and register the listener by calling setOnAudioFocusChangeListener().

AudioFocusRequest

The Android O requestAudioFocus() method takes a single object, AudioFocusRequest. Use an AudioFocusRequest.Builder to define the fields of the request. Since a focus request must always specify the type of the request, it is included in the constructor for the builder. Use the builder's methods to set the other fields of the request.

The FocusGain field is required, all the other fields are optional.

MethodNotes
setFocusGain() This field is required in every request. It takes the same values as the durationHint used in the pre-Android O call to requestAudioFocus(): AUDIOFOCUS_GAIN, AUDIOFOCUS_GAIN_TRANSIENT, AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, or AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE.
setAudioAttributes() AudioAttributes describes the use case for your app. The system looks at them when an app gains and loses audio focus. Attributes supersede the notion of stream type. (In Android O, stream types for any operation other than volume controls are deprecated.) Use the same attributes in the focus request that you use in your audio player (as shown in the example below).

Use an AudioAttributes.Builder to specify the attributes first, then use this method to assign the attributes to the request.

If not specified, AudioAttributes defaults to AudioAttributes.USAGE_MEDIA.

setWillPauseWhenDucked() In Android O, when another application requests focus with AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, the application that has focus does not usually receive an onAudioFocusChange callback because the system can do the ducking by itself. When you need to pause playback rather than duck the volume, call setWillPauseWhenDucked(true) and create and set an OnAudioFocusChangeListener as described above, in automatic ducking.
setAcceptsDelayedFocusGain() A request for audio focus can fail when the focus is locked by another app. This method enables delayed focus gain: the ability to asynchronously acquire focus when it becomes available.

Note that delayed focus gain only works if you also specify an OnAudioChangeFocusListener in the audio request, since your application needs to receive the callback in order to know that focus was granted.

setOnAudioFocusChangeListener() An OnAudioFocusChangeListener is only required if you also specify WillPauseWhenDucked(true) or AcceptsDelayedFocusGain(true) in the request.

There are two methods for setting the listener: one with and one without a handler argument. The handler is the thread on which the listener runs. If you do not specify a handler, the handler associated with the main Looper is used.

The following example shows how to use an AudioFocusRequest.Builder to build an AudioFocusRequest and request and abandon audio focus:

mAudioManager = (AudioManager) Context.getSystemService(Context.AUDIO_SERVICE);
mPlaybackAttributes = new AudioAttributes.Builder()
        .setUsage(AudioAttributes.USAGE_GAME)
        .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
        .build();
mFocusRequest = new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN)
        .setAudioAttributes(mPlaybackAttributes)
        .setAcceptsDelayedFocusGain(true)
        .setOnAudioFocusChangeListener(mMyFocusListener, mMyHandler)
        .build();
mMediaPlayer = new MediaPlayer();
final Object mFocusLock = new Object();

boolean mPlaybackDelayed = false;
boolean mPlaybackNowAuthorized = false;

// ...
int res = mAudioManager.requestAudioFocus(mFocusRequest);
synchronized(mFocusLock) {
    if (res == AUDIOFOCUS_REQUEST_FAILED) {
        mPlaybackNowAuthorized = false;
    } else if (res == AUDIOFOCUS_REQUEST_GRANTED) {
        mPlaybackNowAuthorized = true;
        playbackNow();
    } else if (res == AUDIOFOCUS_REQUEST_DELAYED) {
       mPlaybackDelayed = true;
       mPlaybackNowAuthorized = false;
    }
}

// ...
@Override
public void onAudioFocusChange(int focusChange) {
    switch (focusChange) {
        case AudioManager.AUDIOFOCUS_GAIN:
            if (mPlaybackDelayed || mResumeOnFocusGain) {
                synchronized(mFocusLock) {
                    mPlaybackDelayed = false;
                    mResumeOnFocusGain = false;
                }
                playbackNow();
            } 
            break;
        case AudioManager.AUDIOFOCUS_LOSS:
            synchronized(mFocusLock) {
                mResumeOnFocusGain = false;
                mPlaybackDelayed = false;
            }
            pausePlayback();
            break;
        case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
            synchronized(mFocusLock) {
                mResumeOnFocusGain = true;
                mPlaybackDelayed = false;
            }
            pausePlayback();
            break;
        case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
            // ... pausing or ducking depends on your application
            break;
        }
    }
}
This site uses cookies to store your preferences for site-specific language and display options.

Get the latest Android developer news and tips that will help you find success on Google Play.

* Required Fields

Hooray!

Browse this site in ?

You requested a page in , but your language preference for this site is .

Would you like to change your language preference and browse this site in ? If you want to change your language preference later, use the language menu at the bottom of each page.

This class requires API level or higher

This doc is hidden because your selected API level for the documentation is . You can change the documentation API level with the selector above the left navigation.

For more information about specifying the API level your app requires, read Supporting Different Platform Versions.

Take a one-minute survey?
Help us improve Android tools and documentation.