|
| 1 | +page.title=Managing Audio Focus |
| 2 | +parent.title=Managing Audio Playback and Focus |
| 3 | +parent.link=index.html |
| 4 | + |
| 5 | +trainingnavtop=true |
| 6 | +previous.title=Controlling Your App's Volume and Playback |
| 7 | +previous.link=volume-playback.html |
| 8 | +next.title=Dealing with Audio Output Hardware |
| 9 | +next.link=audio-output.html |
| 10 | + |
| 11 | +@jd:body |
| 12 | + |
| 13 | + |
| 14 | +<div id="tb-wrapper"> |
| 15 | +<div id="tb"> |
| 16 | + |
| 17 | +<h2>This lesson teaches you to</h2> |
| 18 | +<ol> |
| 19 | + <li><a href="#RequestFocus">Request the Audio Focus</a></li> |
| 20 | + <li><a href="#HandleFocusLoss">Handle the Loss of Audio Focus</a></li> |
| 21 | + <li><a href="#DUCK">Duck!</a></li> |
| 22 | +</ol> |
| 23 | + |
| 24 | + |
| 25 | +<h2>You should also read</h2> |
| 26 | +<ul> |
| 27 | + <li><a href="{@docRoot}guide/topics/media/mediaplayer.html">Media Playback</a></li> |
| 28 | +</ul> |
| 29 | + |
| 30 | +</div> |
| 31 | +</div> |
| 32 | + |
| 33 | + |
| 34 | +<p>With multiple apps potentially playing audio it's important to think about how they should |
| 35 | +interact. To avoid every music app playing at the same time, Android uses audio focus to moderate |
| 36 | +audio playback—only apps that hold the audio focus should play audio.</p> |
| 37 | + |
| 38 | +<p>Before your app starts playing audio it should request—and receive—the audio focus. |
| 39 | +Likewise, it should know how to listen for a loss of audio focus and respond appropriately when that |
| 40 | +happens.</p> |
| 41 | + |
| 42 | + |
| 43 | +<h2 id="RequestFocus">Request the Audio Focus</h2> |
| 44 | + |
| 45 | +<p>Before your app starts playing any audio, it should hold the audio focus for the stream |
| 46 | +it will be using. This is done with a call to {@link android.media.AudioManager#requestAudioFocus |
| 47 | +requestAudioFocus()} which returns |
| 48 | +{@link android.media.AudioManager#AUDIOFOCUS_REQUEST_GRANTED} if your request is successful.</p> |
| 49 | + |
| 50 | +<p>You must specify which stream you're using and whether you expect to require transient or |
| 51 | +permanent audio focus. Request transient focus when you expect to play audio for only a short time |
| 52 | +(for example when playing navigation instructions). Request permanent audio focus when you |
| 53 | +plan to play audio for the foreseeable future (for example, when playing music).</p> |
| 54 | + |
| 55 | +<p>The following snippet requests permanent audio focus on the music audio stream. You should |
| 56 | +request the audio focus immediately before you begin playback, such as when the user presses |
| 57 | +play or the background music for the next game level begins.</p> |
| 58 | + |
| 59 | +<pre> |
| 60 | +AudioManager am = mContext.getSystemService(Context.AUDIO_SERVICE); |
| 61 | +... |
| 62 | + |
| 63 | +// Request audio focus for playback |
| 64 | +int result = am.requestAudioFocus(afChangeListener, |
| 65 | + // Use the music stream. |
| 66 | + AudioManager.STREAM_MUSIC, |
| 67 | + // Request permanent focus. |
| 68 | + AudioManager.AUDIOFOCUS_GAIN); |
| 69 | + |
| 70 | +if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) { |
| 71 | + am.unregisterMediaButtonEventReceiver(RemoteControlReceiver); |
| 72 | + // Start playback. |
| 73 | +} |
| 74 | +</pre> |
| 75 | + |
| 76 | +<p>Once you've finished playback be sure to call {@link |
| 77 | +android.media.AudioManager#abandonAudioFocus abandonAudioFocus()}. This notifies |
| 78 | +the system that you no longer require focus and unregisters the associated {@link |
| 79 | +android.media.AudioManager.OnAudioFocusChangeListener}. In the case of abandoning transient focus, |
| 80 | +this allows any interupted app to continue playback.</p> |
| 81 | + |
| 82 | +<pre> |
| 83 | +// Abandon audio focus when playback complete |
| 84 | +am.abandonAudioFocus(afChangeListener); |
| 85 | +</pre> |
| 86 | + |
| 87 | +<p>When requesting transient audio focus you have an additional option: whether or not you want to |
| 88 | +enable "ducking." Normally, when a well-behaved audio app loses audio focus it immediately |
| 89 | +silences its playback. By requesting a transient audio focus that allows ducking you tell other |
| 90 | +audio apps that it’s acceptable for them to keep playing, provided they lower their volume until the |
| 91 | +focus returns to them.</p> |
| 92 | + |
| 93 | +<pre> |
| 94 | +// Request audio focus for playback |
| 95 | +int result = am.requestAudioFocus(afChangeListener, |
| 96 | + // Use the music stream. |
| 97 | + AudioManager.STREAM_MUSIC, |
| 98 | + // Request permanent focus. |
| 99 | + AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK); |
| 100 | + |
| 101 | +if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) { |
| 102 | + // Start playback. |
| 103 | +} |
| 104 | +</pre> |
| 105 | + |
| 106 | +<p>Ducking is particularly suitable for apps that use the audio stream intermittently, such as for |
| 107 | +audible driving directions.</p> |
| 108 | + |
| 109 | +<p>Whenever another app requests audio focus as described above, its choice between permanent and |
| 110 | +transient (with or without support for ducking) audio focus is received by the listener you |
| 111 | +registered when requesting focus.</p> |
| 112 | + |
| 113 | + |
| 114 | +<h2 id="HandleFocusLoss">Handle the Loss of Audio Focus</h2> |
| 115 | + |
| 116 | +<p>If your app can request audio focus, it follows that it will in turn lose that focus when another |
| 117 | +app requests it. How your app responds to a loss of audio focus depends on the manner of that |
| 118 | +loss.</p> |
| 119 | + |
| 120 | +<p>The {@link android.media.AudioManager.OnAudioFocusChangeListener#onAudioFocusChange |
| 121 | +onAudioFocusChange()} callback method of they audio focus change listener you registered when |
| 122 | +requesting audio focus receives a parameter that describes the focus change event. Specifically, |
| 123 | +the possible focus loss events mirror the focus request types from the previous |
| 124 | +section—permanent loss, transient loss, and transient with ducking permitted.</p> |
| 125 | + |
| 126 | +<p>Generally speaking, a transient (temporary) loss of audio focus should result in your app |
| 127 | +silencing it’s audio stream, but otherwise maintaining the same state. You should continue to |
| 128 | +monitor changes in audio focus and be prepared to resume playback where it was paused once you’ve |
| 129 | +regained the focus.</p> |
| 130 | + |
| 131 | +<p>If the audio focus loss is permanent, it’s assumed that another application is now being used to |
| 132 | +listen to audio and your app should effectively end itself. In practical terms, that means stopping |
| 133 | +playback, removing media button listeners—allowing the new audio player to exclusively handle |
| 134 | +those events—and abandoning your audio focus. At that point, you would expect a user action |
| 135 | +(pressing play in your app) to be required before you resume playing audio.</p> |
| 136 | + |
| 137 | +<p>In the following code snippet, we pause the playback or our media player object if the audio |
| 138 | +loss is transien and resume it when we have regained the focus. If the loss is permanent, it |
| 139 | +unregisters our media button event receiver and stops monitoring audio focus changes.<p> |
| 140 | + |
| 141 | +<pre> |
| 142 | +OnAudioFocusChangeListener afChangeListener = new OnAudioFocusChangeListener() { |
| 143 | + public void onAudioFocusChange(int focusChange) { |
| 144 | + if (focusChange == AUDIOFOCUS_LOSS_TRANSIENT |
| 145 | + // Pause playback |
| 146 | + } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) { |
| 147 | + // Resume playback |
| 148 | + } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) { |
| 149 | + am.unregisterMediaButtonEventReceiver(RemoteControlReceiver); |
| 150 | + am.abandonAudioFocus(afChangeListener); |
| 151 | + // Stop playback |
| 152 | + } |
| 153 | + } |
| 154 | +}; |
| 155 | +</pre> |
| 156 | + |
| 157 | +<p>In the case of a transient loss of audio focus where ducking is permitted, rather than pausing |
| 158 | +playback, you can "duck" instead.</p> |
| 159 | + |
| 160 | + |
| 161 | +<h2 id="DUCK">Duck!</h2> |
| 162 | + |
| 163 | +<p>Ducking is the process of lowering your audio stream output volume to make transient audio from |
| 164 | +another app easier to hear without totally disrupting the audio from your own application.</p> |
| 165 | + |
| 166 | +<p>In the following code snippet lowers the volume on our media player object when we temporarily |
| 167 | +lose focus, then returns it to its previous level when we regain focus.</p> |
| 168 | + |
| 169 | +<pre> |
| 170 | +OnAudioFocusChangeListener afChangeListener = new OnAudioFocusChangeListener() { |
| 171 | + public void onAudioFocusChange(int focusChange) { |
| 172 | + if (focusChange == AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK |
| 173 | + // Lower the volume |
| 174 | + } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) { |
| 175 | + // Raise it back to normal |
| 176 | + } |
| 177 | + } |
| 178 | +}; |
| 179 | +</pre> |
| 180 | + |
| 181 | +<p>A loss of audio focus is the most important broadcast to react to, but not the only one. The |
| 182 | +system broadcasts a number of intents to alert you to changes in user’s audio experience. |
| 183 | +The next lesson demonstrates how to monitor them to improve the user’s overall experience.</p> |
0 commit comments