• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1page.title=Media Playback
2page.tags=mediaplayer,soundpool,audiomanager
3@jd:body
4
5    <div id="qv-wrapper">
6    <div id="qv">
7
8<h2>In this document</h2>
9<ol>
10<li><a href="#basics">The Basics</a>
11<li><a href="#manifest">Manifest Declarations</a></li>
12<li><a href="#mediaplayer">Using MediaPlayer</a>
13   <ol>
14      <li><a href='#preparingasync'>Asynchronous Preparation</a></li>
15      <li><a href='#managestate'>Managing State</a></li>
16      <li><a href='#releaseplayer'>Releasing the MediaPlayer</a></li>
17   </ol>
18</li>
19<li><a href="#mpandservices">Using a Service with MediaPlayer</a>
20   <ol>
21      <li><a href="#asyncprepare">Running asynchronously</a></li>
22      <li><a href="#asyncerror">Handling asynchronous errors</a></li>
23      <li><a href="#wakelocks">Using wake locks</a></li>
24      <li><a href="#foregroundserv">Running as a foreground service</a></li>
25      <li><a href="#audiofocus">Handling audio focus</a></li>
26      <li><a href="#cleanup">Performing cleanup</a></li>
27   </ol>
28</li>
29<li><a href="#noisyintent">Handling the AUDIO_BECOMING_NOISY Intent</a>
30<li><a href="#viacontentresolver">Retrieving Media from a Content Resolver</a>
31</ol>
32
33<h2>Key classes</h2>
34<ol>
35<li>{@link android.media.MediaPlayer}</li>
36<li>{@link android.media.AudioManager}</li>
37<li>{@link android.media.SoundPool}</li>
38</ol>
39
40<h2>See also</h2>
41<ol>
42<li><a href="{@docRoot}guide/topics/media/jetplayer.html">JetPlayer</a></li>
43<li><a href="{@docRoot}guide/topics/media/audio-capture.html">Audio Capture</a></li>
44<li><a href="{@docRoot}guide/appendix/media-formats.html">Android Supported Media Formats</a></li>
45<li><a href="{@docRoot}guide/topics/data/data-storage.html">Data Storage</a></li>
46</ol>
47
48</div>
49</div>
50
51<p>The Android multimedia framework includes support for playing variety of common media types, so
52that you can easily integrate audio, video and images into your applications. You can play audio or
53video from media files stored in your application's resources (raw resources), from standalone files
54in the filesystem, or from a data stream arriving over a network connection, all using {@link
55android.media.MediaPlayer} APIs.</p>
56
57<p>This document shows you how to write a media-playing application that interacts with the user and
58the system in order to obtain good performance and a pleasant user experience.</p>
59
60<p class="note"><strong>Note:</strong> You can play back the audio data only to the standard output
61device. Currently, that is the mobile device speaker or a Bluetooth headset. You cannot play sound
62files in the conversation audio during a call.</p>
63
64<h2 id="basics">The Basics</h2>
65<p>The following classes are used to play sound and video in the Android framework:</p>
66
67<dl>
68  <dt>{@link android.media.MediaPlayer}</dt>
69  <dd>This class is the primary API for playing sound and video.</dd>
70  <dt>{@link android.media.AudioManager}</dt>
71  <dd>This class manages audio sources and audio output on a device.</dd>
72</dl>
73
74<h2 id="manifest">Manifest Declarations</h2>
75<p>Before starting development on your application using MediaPlayer, make sure your manifest has
76the appropriate declarations to allow use of related features.</p>
77
78<ul>
79  <li><strong>Internet Permission</strong> - If you are using MediaPlayer to stream network-based
80content, your application must request network access.
81<pre>
82&lt;uses-permission android:name="android.permission.INTERNET" /&gt;
83</pre>
84  </li>
85  <li><strong>Wake Lock Permission</strong> - If your player application needs to keep the screen
86from dimming or the processor from sleeping, or uses the {@link
87android.media.MediaPlayer#setScreenOnWhilePlaying(boolean) MediaPlayer.setScreenOnWhilePlaying()} or
88{@link android.media.MediaPlayer#setWakeMode(android.content.Context, int)
89MediaPlayer.setWakeMode()} methods, you must request this permission.
90<pre>
91&lt;uses-permission android:name="android.permission.WAKE_LOCK" /&gt;
92</pre>
93  </li>
94</ul>
95
96<h2 id="mediaplayer">Using MediaPlayer</h2>
97<p>One of the most important components of the media framework is the
98{@link android.media.MediaPlayer MediaPlayer}
99class. An object of this class can fetch, decode, and play both audio and video
100with minimal setup. It supports several different media sources such as:
101<ul>
102   <li>Local resources</li>
103   <li>Internal URIs, such as one you might obtain from a Content Resolver</li>
104   <li>External URLs (streaming)</li>
105</ul>
106</p>
107
108<p>For a list of media formats that Android supports,
109see the <a href="{@docRoot}guide/appendix/media-formats.html">Android Supported Media
110Formats</a> document. </p>
111
112<p>Here is an example
113of how to play audio that's available as a local raw resource (saved in your application's
114{@code res/raw/} directory):</p>
115
116<pre>MediaPlayer mediaPlayer = MediaPlayer.create(context, R.raw.sound_file_1);
117mediaPlayer.start(); // no need to call prepare(); create() does that for you
118</pre>
119
120<p>In this case, a "raw" resource is a file that the system does not
121try to parse in any particular way. However, the content of this resource should not
122be raw audio. It should be a properly encoded and formatted media file in one
123of the supported formats.</p>
124
125<p>And here is how you might play from a URI available locally in the system
126(that you obtained through a Content Resolver, for instance):</p>
127
128<pre>Uri myUri = ....; // initialize Uri here
129MediaPlayer mediaPlayer = new MediaPlayer();
130mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
131mediaPlayer.setDataSource(getApplicationContext(), myUri);
132mediaPlayer.prepare();
133mediaPlayer.start();</pre>
134
135<p>Playing from a remote URL via HTTP streaming looks like this:</p>
136
137<pre>String url = "http://........"; // your URL here
138MediaPlayer mediaPlayer = new MediaPlayer();
139mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
140mediaPlayer.setDataSource(url);
141mediaPlayer.prepare(); // might take long! (for buffering, etc)
142mediaPlayer.start();</pre>
143
144<p class="note"><strong>Note:</strong>
145If you're passing a URL to stream an online media file, the file must be capable of
146progressive download.</p>
147
148<p class="caution"><strong>Caution:</strong> You must either catch or pass
149{@link java.lang.IllegalArgumentException} and {@link java.io.IOException} when using
150{@link android.media.MediaPlayer#setDataSource setDataSource()}, because
151the file you are referencing might not exist.</p>
152
153<h3 id='preparingasync'>Asynchronous Preparation</h3>
154
155<p>Using {@link android.media.MediaPlayer MediaPlayer} can be straightforward in
156principle. However, it's important to keep in mind that a few more things are
157necessary to integrate it correctly with a typical Android application. For
158example, the call to {@link android.media.MediaPlayer#prepare prepare()} can
159take a long time to execute, because
160it might involve fetching and decoding media data. So, as is the case with any
161method that may take long to execute, you should <strong>never call it from your
162application's UI thread</strong>. Doing that will cause the UI to hang until the method returns,
163which is a very bad user experience and can cause an ANR (Application Not Responding) error. Even if
164you expect your resource to load quickly, remember that anything that takes more than a tenth
165of a second to respond in the UI will cause a noticeable pause and will give
166the user the impression that your application is slow.</p>
167
168<p>To avoid hanging your UI thread, spawn another thread to
169prepare the {@link android.media.MediaPlayer} and notify the main thread when done. However, while
170you could write the threading logic
171yourself, this pattern is so common when using {@link android.media.MediaPlayer} that the framework
172supplies a convenient way to accomplish this task by using the
173{@link android.media.MediaPlayer#prepareAsync prepareAsync()} method. This method
174starts preparing the media in the background and returns immediately. When the media
175is done preparing, the {@link android.media.MediaPlayer.OnPreparedListener#onPrepared onPrepared()}
176method of the {@link android.media.MediaPlayer.OnPreparedListener
177MediaPlayer.OnPreparedListener}, configured through
178{@link android.media.MediaPlayer#setOnPreparedListener setOnPreparedListener()} is called.</p>
179
180<h3 id='managestate'>Managing State</h3>
181
182<p>Another aspect of a {@link android.media.MediaPlayer} that you should keep in mind is
183that it's state-based. That is, the {@link android.media.MediaPlayer} has an internal state
184that you must always be aware of when writing your code, because certain operations
185are only valid when then player is in specific states. If you perform an operation while in the
186wrong state, the system may throw an exception or cause other undesireable behaviors.</p>
187
188<p>The documentation in the
189{@link android.media.MediaPlayer MediaPlayer} class shows a complete state diagram,
190that clarifies which methods move the {@link android.media.MediaPlayer} from one state to another.
191For example, when you create a new {@link android.media.MediaPlayer}, it is in the <em>Idle</em>
192state. At that point, you should initialize it by calling
193{@link android.media.MediaPlayer#setDataSource setDataSource()}, bringing it
194to the <em>Initialized</em> state. After that, you have to prepare it using either the
195{@link android.media.MediaPlayer#prepare prepare()} or
196{@link android.media.MediaPlayer#prepareAsync prepareAsync()} method. When
197the {@link android.media.MediaPlayer} is done preparing, it will then enter the <em>Prepared</em>
198state, which means you can call {@link android.media.MediaPlayer#start start()}
199to make it play the media. At that point, as the diagram illustrates,
200you can move between the <em>Started</em>, <em>Paused</em> and <em>PlaybackCompleted</em> states by
201calling such methods as
202{@link android.media.MediaPlayer#start start()},
203{@link android.media.MediaPlayer#pause pause()}, and
204{@link android.media.MediaPlayer#seekTo seekTo()},
205amongst others. When you
206call {@link android.media.MediaPlayer#stop stop()}, however, notice that you
207cannot call {@link android.media.MediaPlayer#start start()} again until you
208prepare the {@link android.media.MediaPlayer} again.</p>
209
210<p>Always keep <a href='{@docRoot}images/mediaplayer_state_diagram.gif'>the state diagram</a>
211in mind when writing code that interacts with a
212{@link android.media.MediaPlayer} object, because calling its methods from the wrong state is a
213common cause of bugs.</p>
214
215<h3 id='releaseplayer'>Releasing the MediaPlayer</h3>
216
217<p>A {@link android.media.MediaPlayer MediaPlayer} can consume valuable
218system resources.
219Therefore, you should always take extra precautions to make sure you are not
220hanging on to a {@link android.media.MediaPlayer} instance longer than necessary. When you
221are done with it, you should always call
222{@link android.media.MediaPlayer#release release()} to make sure any
223system resources allocated to it are properly released. For example, if you are
224using a {@link android.media.MediaPlayer} and your activity receives a call to {@link
225android.app.Activity#onStop onStop()}, you must release the {@link android.media.MediaPlayer},
226because it
227makes little sense to hold on to it while your activity is not interacting with
228the user (unless you are playing media in the background, which is discussed in the next section).
229When your activity is resumed or restarted, of course, you need to
230create a new {@link android.media.MediaPlayer} and prepare it again before resuming playback.</p>
231
232<p>Here's how you should release and then nullify your {@link android.media.MediaPlayer}:</p>
233<pre>
234mediaPlayer.release();
235mediaPlayer = null;
236</pre>
237
238<p>As an example, consider the problems that could happen if you
239forgot to release the {@link android.media.MediaPlayer} when your activity is stopped, but create a
240new one when the activity starts again. As you may know, when the user changes the
241screen orientation (or changes the device configuration in another way),
242the system handles that by restarting the activity (by default), so you might quickly
243consume all of the system resources as the user
244rotates the device back and forth between portrait and landscape, because at each
245orientation change, you create a new {@link android.media.MediaPlayer} that you never
246release. (For more information about runtime restarts, see <a
247href="{@docRoot}guide/topics/resources/runtime-changes.html">Handling Runtime Changes</a>.)</p>
248
249<p>You may be wondering what happens if you want to continue playing
250"background media" even when the user leaves your activity, much in the same
251way that the built-in Music application behaves. In this case, what you need is
252a {@link android.media.MediaPlayer MediaPlayer} controlled by a {@link android.app.Service}, as
253discussed in <a href="#mpandservices">Using a Service with MediaPlayer</a>.</p>
254
255<h2 id="mpandservices">Using a Service with MediaPlayer</h2>
256
257<p>If you want your media to play in the background even when your application
258is not onscreen&mdash;that is, you want it to continue playing while the user is
259interacting with other applications&mdash;then you must start a
260{@link android.app.Service Service} and control the
261{@link android.media.MediaPlayer MediaPlayer} instance from there.
262You should be careful about this setup, because the user and the system have expectations
263about how an application running a background service should interact with the rest of the
264system. If your application does not fulfil those expectations, the user may
265have a bad experience. This section describes the main issues that you should be
266aware of and offers suggestions about how to approach them.</p>
267
268
269<h3 id="asyncprepare">Running asynchronously</h3>
270
271<p>First of all, like an {@link android.app.Activity Activity}, all work in a
272{@link android.app.Service Service} is done in a single thread by
273default&mdash;in fact, if you're running an activity and a service from the same application, they
274use the same thread (the "main thread") by default. Therefore, services need to
275process incoming intents quickly
276and never perform lengthy computations when responding to them. If any heavy
277work or blocking calls are expected, you must do those tasks asynchronously: either from
278another thread you implement yourself, or using the framework's many facilities
279for asynchronous processing.</p>
280
281<p>For instance, when using a {@link android.media.MediaPlayer} from your main thread,
282you should call {@link android.media.MediaPlayer#prepareAsync prepareAsync()} rather than
283{@link android.media.MediaPlayer#prepare prepare()}, and implement
284a {@link android.media.MediaPlayer.OnPreparedListener MediaPlayer.OnPreparedListener}
285in order to be notified when the preparation is complete and you can start playing.
286For example:</p>
287
288<pre>
289public class MyService extends Service implements MediaPlayer.OnPreparedListener {
290    private static final String ACTION_PLAY = "com.example.action.PLAY";
291    MediaPlayer mMediaPlayer = null;
292
293    public int onStartCommand(Intent intent, int flags, int startId) {
294        ...
295        if (intent.getAction().equals(ACTION_PLAY)) {
296            mMediaPlayer = ... // initialize it here
297            mMediaPlayer.setOnPreparedListener(this);
298            mMediaPlayer.prepareAsync(); // prepare async to not block main thread
299        }
300    }
301
302    /** Called when MediaPlayer is ready */
303    public void onPrepared(MediaPlayer player) {
304        player.start();
305    }
306}
307</pre>
308
309
310<h3 id="asyncerror">Handling asynchronous errors</h3>
311
312<p>On synchronous operations, errors would normally
313be signaled with an exception or an error code, but whenever you use asynchronous
314resources, you should make sure your application is notified
315of errors appropriately. In the case of a {@link android.media.MediaPlayer MediaPlayer},
316you can accomplish this by implementing a
317{@link android.media.MediaPlayer.OnErrorListener MediaPlayer.OnErrorListener} and
318setting it in your {@link android.media.MediaPlayer} instance:</p>
319
320<pre>
321public class MyService extends Service implements MediaPlayer.OnErrorListener {
322    MediaPlayer mMediaPlayer;
323
324    public void initMediaPlayer() {
325        // ...initialize the MediaPlayer here...
326
327        mMediaPlayer.setOnErrorListener(this);
328    }
329
330    &#64;Override
331    public boolean onError(MediaPlayer mp, int what, int extra) {
332        // ... react appropriately ...
333        // The MediaPlayer has moved to the Error state, must be reset!
334    }
335}
336</pre>
337
338<p>It's important to remember that when an error occurs, the {@link android.media.MediaPlayer}
339moves to the <em>Error</em> state (see the documentation for the
340{@link android.media.MediaPlayer MediaPlayer} class for the full state diagram)
341and you must reset it before you can use it again.
342
343
344<h3 id="wakelocks">Using wake locks</h3>
345
346<p>When designing applications that play media
347in the background, the device may go to sleep
348while your service is running. Because the Android system tries to conserve
349battery while the device is sleeping, the system tries to shut off any
350of the phone's features that are
351not necessary, including the CPU and the WiFi hardware.
352However, if your service is playing or streaming music, you want to prevent
353the system from interfering with your playback.</p>
354
355<p>In order to ensure that your service continues to run under
356those conditions, you have to use "wake locks." A wake lock is a way to signal to
357the system that your application is using some feature that should
358stay available even if the phone is idle.</p>
359
360<p class="caution"><strong>Notice:</strong> You should always use wake locks sparingly and hold them
361only for as long as truly necessary, because they significantly reduce the battery life of the
362device.</p>
363
364<p>To ensure that the CPU continues running while your {@link android.media.MediaPlayer} is
365playing, call the {@link android.media.MediaPlayer#setWakeMode
366setWakeMode()} method when initializing your {@link android.media.MediaPlayer}. Once you do,
367the {@link android.media.MediaPlayer} holds the specified lock while playing and releases the lock
368when paused or stopped:</p>
369
370<pre>
371mMediaPlayer = new MediaPlayer();
372// ... other initialization here ...
373mMediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
374</pre>
375
376<p>However, the wake lock acquired in this example guarantees only that the CPU remains awake. If
377you are streaming media over the
378network and you are using Wi-Fi, you probably want to hold a
379{@link android.net.wifi.WifiManager.WifiLock WifiLock} as
380well, which you must acquire and release manually. So, when you start preparing the
381{@link android.media.MediaPlayer} with the remote URL, you should create and acquire the Wi-Fi lock.
382For example:</p>
383
384<pre>
385WifiLock wifiLock = ((WifiManager) getSystemService(Context.WIFI_SERVICE))
386    .createWifiLock(WifiManager.WIFI_MODE_FULL, "mylock");
387
388wifiLock.acquire();
389</pre>
390
391<p>When you pause or stop your media, or when you no longer need the
392network, you should release the lock:</p>
393
394<pre>
395wifiLock.release();
396</pre>
397
398
399<h3 id="foregroundserv">Running as a foreground service</h3>
400
401<p>Services are often used for performing background tasks, such as fetching emails,
402synchronizing data, downloading content, amongst other possibilities. In these
403cases, the user is not actively aware of the service's execution, and probably
404wouldn't even notice if some of these services were interrupted and later restarted.</p>
405
406<p>But consider the case of a service that is playing music. Clearly this is a service that the user
407is actively aware of and the experience would be severely affected by any interruptions.
408Additionally, it's a service that the user will likely wish to interact with during its execution.
409In this case, the service should run as a "foreground service." A
410foreground service holds a higher level of importance within the system&mdash;the system will
411almost never kill the service, because it is of immediate importance to the user. When running
412in the foreground, the service also must provide a status bar notification to ensure that users are
413aware of the running service and allow them to open an activity that can interact with the
414service.</p>
415
416<p>In order to turn your service into a foreground service, you must create a
417{@link android.app.Notification Notification} for the status bar and call
418{@link android.app.Service#startForeground startForeground()} from the {@link
419android.app.Service}. For example:</p>
420
421<pre>String songName;
422// assign the song name to songName
423PendingIntent pi = PendingIntent.getActivity(getApplicationContext(), 0,
424                new Intent(getApplicationContext(), MainActivity.class),
425                PendingIntent.FLAG_UPDATE_CURRENT);
426Notification notification = new Notification();
427notification.tickerText = text;
428notification.icon = R.drawable.play0;
429notification.flags |= Notification.FLAG_ONGOING_EVENT;
430notification.setLatestEventInfo(getApplicationContext(), "MusicPlayerSample",
431                "Playing: " + songName, pi);
432startForeground(NOTIFICATION_ID, notification);
433</pre>
434
435<p>While your service is running in the foreground, the notification you
436configured is visible in the notification area of the device. If the user
437selects the notification, the system invokes the {@link android.app.PendingIntent} you supplied. In
438the example above, it opens an activity ({@code MainActivity}).</p>
439
440<p>Figure 1 shows how your notification appears to the user:</p>
441
442<img src='images/notification1.png' />
443&nbsp;&nbsp;
444<img src='images/notification2.png' />
445<p class="img-caption"><strong>Figure 1.</strong> Screenshots of a foreground service's
446notification, showing the notification icon in the status bar (left) and the expanded view
447(right).</p>
448
449<p>You should only hold on to the "foreground service" status while your
450service is actually performing something the user is actively aware of. Once
451that is no longer true, you should release it by calling
452{@link android.app.Service#stopForeground stopForeground()}:</p>
453
454<pre>
455stopForeground(true);
456</pre>
457
458<p>For more information, see the documentation about <a
459href="{@docRoot}guide/components/services.html#Foreground">Services</a> and
460<a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">Status Bar Notifications</a>.</p>
461
462
463<h3 id="audiofocus">Handling audio focus</h3>
464
465<p>Even though only one activity can run at any given time, Android is a
466multi-tasking environment. This poses a particular challenge to applications
467that use audio, because there is only one audio output and there may be several
468media services competing for its use. Before Android 2.2, there was no built-in
469mechanism to address this issue, which could in some cases lead to a bad user
470experience. For example, when a user is listening to
471music and another application needs to notify the user of something very important,
472the user might not hear the notification tone due to the loud music. Starting with
473Android 2.2, the platform offers a way for applications to negotiate their
474use of the device's audio output. This mechanism is called Audio Focus.</p>
475
476<p>When your application needs to output audio such as music or a notification,
477you should always request audio focus. Once it has focus, it can use the sound output freely, but it
478should
479always listen for focus changes. If it is notified that it has lost the audio
480focus, it should immediately either kill the audio or lower it to a quiet level
481(known as "ducking"&mdash;there is a flag that indicates which one is appropriate) and only resume
482loud playback after it receives focus again.</p>
483
484<p>Audio Focus is cooperative in nature. That is, applications are expected
485(and highly encouraged) to comply with the audio focus guidelines, but the
486rules are not enforced by the system. If an application wants to play loud
487music even after losing audio focus, nothing in the system will prevent that.
488However, the user is more likely to have a bad experience and will be more
489likely to uninstall the misbehaving application.</p>
490
491<p>To request audio focus, you must call
492{@link android.media.AudioManager#requestAudioFocus requestAudioFocus()} from the {@link
493android.media.AudioManager}, as the example below demonstrates:</p>
494
495<pre>
496AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
497int result = audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC,
498    AudioManager.AUDIOFOCUS_GAIN);
499
500if (result != AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
501    // could not get audio focus.
502}
503</pre>
504
505<p>The first parameter to {@link android.media.AudioManager#requestAudioFocus requestAudioFocus()}
506is an {@link android.media.AudioManager.OnAudioFocusChangeListener
507AudioManager.OnAudioFocusChangeListener},
508whose {@link android.media.AudioManager.OnAudioFocusChangeListener#onAudioFocusChange
509onAudioFocusChange()} method is called whenever there is a change in audio focus. Therefore, you
510should also implement this interface on your service and activities. For example:</p>
511
512<pre>
513class MyService extends Service
514                implements AudioManager.OnAudioFocusChangeListener {
515    // ....
516    public void onAudioFocusChange(int focusChange) {
517        // Do something based on focus change...
518    }
519}
520</pre>
521
522<p>The <code>focusChange</code> parameter tells you how the audio focus has changed, and
523can be one of the following values (they are all constants defined in
524{@link android.media.AudioManager AudioManager}):</p>
525
526<ul>
527<li>{@link android.media.AudioManager#AUDIOFOCUS_GAIN}: You have gained the audio focus.</li>
528
529<li>{@link android.media.AudioManager#AUDIOFOCUS_LOSS}: You have lost the audio focus for a
530presumably long time.
531You must stop all audio playback. Because you should expect not to have focus back
532for a long time, this would be a good place to clean up your resources as much
533as possible. For example, you should release the {@link android.media.MediaPlayer}.</li>
534
535<li>{@link android.media.AudioManager#AUDIOFOCUS_LOSS_TRANSIENT}: You have
536temporarily lost audio focus, but should receive it back shortly. You must stop
537all audio playback, but you can keep your resources because you will probably get
538focus back shortly.</li>
539
540<li>{@link android.media.AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}: You have temporarily
541lost audio focus,
542but you are allowed to continue to play audio quietly (at a low volume) instead
543of killing audio completely.</li>
544</ul>
545
546<p>Here is an example implementation:</p>
547
548<pre>
549public void onAudioFocusChange(int focusChange) {
550    switch (focusChange) {
551        case AudioManager.AUDIOFOCUS_GAIN:
552            // resume playback
553            if (mMediaPlayer == null) initMediaPlayer();
554            else if (!mMediaPlayer.isPlaying()) mMediaPlayer.start();
555            mMediaPlayer.setVolume(1.0f, 1.0f);
556            break;
557
558        case AudioManager.AUDIOFOCUS_LOSS:
559            // Lost focus for an unbounded amount of time: stop playback and release media player
560            if (mMediaPlayer.isPlaying()) mMediaPlayer.stop();
561            mMediaPlayer.release();
562            mMediaPlayer = null;
563            break;
564
565        case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
566            // Lost focus for a short time, but we have to stop
567            // playback. We don't release the media player because playback
568            // is likely to resume
569            if (mMediaPlayer.isPlaying()) mMediaPlayer.pause();
570            break;
571
572        case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
573            // Lost focus for a short time, but it's ok to keep playing
574            // at an attenuated level
575            if (mMediaPlayer.isPlaying()) mMediaPlayer.setVolume(0.1f, 0.1f);
576            break;
577    }
578}
579</pre>
580
581<p>Keep in mind that the audio focus APIs are available only with API level 8 (Android 2.2)
582and above, so if you want to support previous
583versions of Android, you should adopt a backward compatibility strategy that
584allows you to use this feature if available, and fall back seamlessly if not.</p>
585
586<p>You can achieve backward compatibility either by calling the audio focus methods by reflection
587or by implementing all the audio focus features in a separate class (say,
588<code>AudioFocusHelper</code>). Here is an example of such a class:</p>
589
590<pre>
591public class AudioFocusHelper implements AudioManager.OnAudioFocusChangeListener {
592    AudioManager mAudioManager;
593
594    // other fields here, you'll probably hold a reference to an interface
595    // that you can use to communicate the focus changes to your Service
596
597    public AudioFocusHelper(Context ctx, /* other arguments here */) {
598        mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
599        // ...
600    }
601
602    public boolean requestFocus() {
603        return AudioManager.AUDIOFOCUS_REQUEST_GRANTED ==
604            mAudioManager.requestAudioFocus(mContext, AudioManager.STREAM_MUSIC,
605            AudioManager.AUDIOFOCUS_GAIN);
606    }
607
608    public boolean abandonFocus() {
609        return AudioManager.AUDIOFOCUS_REQUEST_GRANTED ==
610            mAudioManager.abandonAudioFocus(this);
611    }
612
613    &#64;Override
614    public void onAudioFocusChange(int focusChange) {
615        // let your service know about the focus change
616    }
617}
618</pre>
619
620
621<p>You can create an instance of <code>AudioFocusHelper</code> class only if you detect that
622the system is running API level 8 or above. For example:</p>
623
624<pre>
625if (android.os.Build.VERSION.SDK_INT &gt;= 8) {
626    mAudioFocusHelper = new AudioFocusHelper(getApplicationContext(), this);
627} else {
628    mAudioFocusHelper = null;
629}
630</pre>
631
632
633<h3 id="cleanup">Performing cleanup</h3>
634
635<p>As mentioned earlier, a {@link android.media.MediaPlayer} object can consume a significant
636amount of system resources, so you should keep it only for as long as you need and call
637{@link android.media.MediaPlayer#release release()} when you are done with it. It's important
638to call this cleanup method explicitly rather than rely on system garbage collection because
639it might take some time before the garbage collector reclaims the {@link android.media.MediaPlayer},
640as it's only sensitive to memory needs and not to shortage of other media-related resources.
641So, in the case when you're using a service, you should always override the
642{@link android.app.Service#onDestroy onDestroy()} method to make sure you are releasing
643the {@link android.media.MediaPlayer}:</p>
644
645<pre>
646public class MyService extends Service {
647   MediaPlayer mMediaPlayer;
648   // ...
649
650   &#64;Override
651   public void onDestroy() {
652       if (mMediaPlayer != null) mMediaPlayer.release();
653   }
654}
655</pre>
656
657<p>You should always look for other opportunities to release your {@link android.media.MediaPlayer}
658as well, apart from releasing it when being shut down. For example, if you expect not
659to be able to play media for an extended period of time (after losing audio focus, for example),
660you should definitely release your existing {@link android.media.MediaPlayer} and create it again
661later. On the
662other hand, if you only expect to stop playback for a very short time, you should probably
663hold on to your {@link android.media.MediaPlayer} to avoid the overhead of creating and preparing it
664again.</p>
665
666
667
668<h2 id="noisyintent">Handling the AUDIO_BECOMING_NOISY Intent</h2>
669
670<p>Many well-written applications that play audio automatically stop playback when an event
671occurs that causes the audio to become noisy (ouput through external speakers). For instance,
672this might happen when a user is listening to music through headphones and accidentally
673disconnects the headphones from the device. However, this behavior does not happen automatically.
674If you don't implement this feature, audio plays out of the device's external speakers, which
675might not be what the user wants.</p>
676
677<p>You can ensure your app stops playing music in these situations by handling
678the {@link android.media.AudioManager#ACTION_AUDIO_BECOMING_NOISY} intent, for which you can
679register a receiver by
680adding the following to your manifest:</p>
681
682<pre>
683&lt;receiver android:name=".MusicIntentReceiver"&gt;
684   &lt;intent-filter&gt;
685      &lt;action android:name="android.media.AUDIO_BECOMING_NOISY" /&gt;
686   &lt;/intent-filter&gt;
687&lt;/receiver&gt;
688</pre>
689
690<p>This registers the <code>MusicIntentReceiver</code> class as a broadcast receiver for that
691intent. You should then implement this class:</p>
692
693<pre>
694public class MusicIntentReceiver extends android.content.BroadcastReceiver {
695   &#64;Override
696   public void onReceive(Context ctx, Intent intent) {
697      if (intent.getAction().equals(
698                    android.media.AudioManager.ACTION_AUDIO_BECOMING_NOISY)) {
699          // signal your service to stop playback
700          // (via an Intent, for instance)
701      }
702   }
703}
704</pre>
705
706
707
708
709<h2 id="viacontentresolver">Retrieving Media from a Content Resolver</h2>
710
711<p>Another feature that may be useful in a media player application is the ability to
712retrieve music that the user has on the device. You can do that by querying the {@link
713android.content.ContentResolver} for external media:</p>
714
715<pre>
716ContentResolver contentResolver = getContentResolver();
717Uri uri = android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
718Cursor cursor = contentResolver.query(uri, null, null, null, null);
719if (cursor == null) {
720    // query failed, handle error.
721} else if (!cursor.moveToFirst()) {
722    // no media on the device
723} else {
724    int titleColumn = cursor.getColumnIndex(android.provider.MediaStore.Audio.Media.TITLE);
725    int idColumn = cursor.getColumnIndex(android.provider.MediaStore.Audio.Media._ID);
726    do {
727       long thisId = cursor.getLong(idColumn);
728       String thisTitle = cursor.getString(titleColumn);
729       // ...process entry...
730    } while (cursor.moveToNext());
731}
732</pre>
733
734<p>To use this with the {@link android.media.MediaPlayer}, you can do this:</p>
735
736<pre>
737long id = /* retrieve it from somewhere */;
738Uri contentUri = ContentUris.withAppendedId(
739        android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, id);
740
741mMediaPlayer = new MediaPlayer();
742mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
743mMediaPlayer.setDataSource(getApplicationContext(), contentUri);
744
745// ...prepare and start...
746</pre>
747