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