MediaPlayer Overview

The Android multimedia framework supports playing a wide variety of common media types, so you can easily integrate audio, video, and images into your applications. You can use the MediaPlayer API to play audio or video from media files stored in application resources (raw resources), standalone files in the file system, or data streams arriving over a network connection.

This article shows you how to write media player applications that interact with users and systems for good performance and a pleasant user experience.

Note: You can only play back audio data to standard output devices. Currently, this is a mobile device speaker or bluetooth headset. You cannot play a sound file in a call audio file during a call.

The most basic

Use the following classes to play sound and video in the Android framework:

MediaPlayer

This class is the main API for playing sound and video.Copy the code

AudioManager

This class manages the audio source and output on the device.Copy the code

Listing announcement

Before you develop your application using MediaPlayer, make sure there are appropriate declarations in the manifest that allow you to use the features.

  • Internet Permissions – If you are using MediaPlayer to stream web-based content, your application must request network access.
<uses-permission android:name="android.permission.INTERNET" />
Copy the code
  • Wake Lock permission – You must request this permission if your player application needs to prevent screen darkening or processor hibernation, or if you use the mediaPlayer.setScreenonwhile Play () or mediaplayer.setwakemode () methods.
<uses-permission android:name="android.permission.WAKE_LOCK" />
Copy the code

Using the MediaPlayer

One of the most important components of a media framework is the MediaPlayer class. Objects of this class can get, decode, and play audio and video with minimal Settings. It supports several different media sources, such as:

  • Local resources
  • Internal URIs, such as those you might get from a contentProvider
  • External URL (Streaming) For a list of media formats supported by Android, see the Supported media Formats page.

Here’s how to play local audio resources (saved in your application’s RES/RAW/directory):

MediaPlayer mediaPlayer = MediaPlayer.create(context, R.raw.sound_file_1);
mediaPlayer.start(); // no need to call prepare(); create() does that for you
Copy the code

In this case, the “raw” resource is a file that the system does not attempt to parse in any particular way. However, the content of this resource should not be raw audio. It should be a media file properly encoded and formatted in one of the supported formats.

Here’s how you can play from the URIs available locally on the system (for example, the URIs you get through the content parser) :

Uri myUri = .... ; // initialize Uri here MediaPlayer mediaPlayer = new MediaPlayer(); mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); mediaPlayer.setDataSource(getApplicationContext(), myUri); mediaPlayer.prepare(); mediaPlayer.start();Copy the code

The following is played from a remote URL via HTTP streaming media:

String url = "http://........"; // your URL here
MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setDataSource(url);
mediaPlayer.prepare(); // might take long! (for buffering, etc)
mediaPlayer.start();
Copy the code

Note: If you want to stream an online file through a URL, the file must be downloadable step by step.

Note: When using setDataSource(), you must catch or pass IllegalArgumentException and IOException because the file you are referencing may not exist.

Asynchronous preparation

Using MediaPlayer is simple in principle. However, keep in mind that there are a few other things you need to do to properly integrate it into a typical Android application. For example, the call to prepare() might take a long time to execute because it might involve fetching and decoding media data. So, like any method that takes a long time to execute, never call it from the application’s UI thread. Doing so causes the UI to hang until the method returns, which is a very bad user experience and can lead to ANR(application not responding) errors. Even if you want your resources to load quickly, keep in mind that anything that takes more than a tenth of a second to respond in the UI will cause a noticeable pause and give the user the impression that your application is slow.

To avoid suspending the UI thread, generate another thread to prepare the MediaPlayer and notify the main thread when it is finished. However, while you can write your own thread logic, this pattern is very common when using MediaPlayer, so the framework provides a convenient way to do this by using the prepareAsync() method. The method starts preparing the media in the background and returns immediately. When the media to complete the preparation, will call through setOnPreparedListener () configuration MediaPlayer. OnPreparedListener () the onPrepared () method.

Manage state

Another aspect of MediaPlayer that you should keep in mind is that it is state-based. That is, MediaPlayer has an internal state that you must always be aware of when writing code, because certain operations are only valid when the Player is in a particular state. If an operation is performed in the wrong state, the system may throw an exception or cause other undesired behavior.

The documentation in the MediaPlayer class shows a complete state machine that illustrates which methods move the MediaPlayer from one state to another. For example, when you create a new MediaPlayer, it is idle. At this point, you should initialize it by calling setDataSource(), leaving it in the initialized state. After that, you must prepare it using the prepare() or prepareAsync() methods. When MediaPlayer is ready, it enters the ready state, which means you can call start() to make it play media. At this point, you can switch between the start, Pause (), and PlaybackCompleted states by calling methods such as start(), Pause (), and seekTo(). However, when you call stop(), note that you cannot call start() again until you have reprepared the MediaPlayer.

When writing code that interacts with MediaPlayer objects, it’s important to keep state diagrams in mind, because calling its methods from the wrong state is a common cause of errors.

Release media Player

MediaPlayer can consume valuable system resources. Therefore, you should always take extra precautions to ensure that you are not relying too heavily on MediaPlayer instances. After it is processed, release() should always be called to ensure that any system resources allocated to it are properly released. For example, if you are using a media player and the activity receives onStop() calls, you must release the media player, because when your activity is not interacting with the user, it makes no sense to continue holding the instance (unless you are playing media in the background, which is discussed in the next section). When your activity resumes or restarts, of course, you need to create a new MediaPlayer and reprepare it before resuming playback.

Here’s how you should release and cancel MediaPlayer:

mediaPlayer.release();
mediaPlayer = null;
Copy the code

As an example, consider the problem that might occur if you forget to release the MediaPlayer when the activity stops and create a new one when the activity restarts. As you may know, when the user changes the screen orientation (or change the equipment configuration in another way), system process, through to restart the activity (by default), so you may soon consume all system resources of the rotating equipment of back and forth between portrait and landscape, because in every direction, you create a new media player, and you never will Release. (For more information about runtime reboots, see Handling Runtime Changes.)

You might be wondering what happens if you want to continue playing “background media” when the user leaves your activity, which is very similar to how the built-in music application behaves. In this case, what you need is a MediaPlayer controlled by the service, which is discussed in the next section.

Use MediaPlayer in the service

If you want your media to play in the background, even if your application is not on the screen — that is, you want it to continue to play while the user interacts with other applications — then you must start a service and control the MediaPlayer instance from there. You need to embed the MediaPlayer MediaBrowserServiceCompat service, and have it with another MediaBrowserCompat interaction in the activity.

Be careful with this client/server setup. People have expectations about how a player running in a background service will interact with the rest of the system. If your application does not meet these expectations, users may have a bad experience. Read the full details of building an audio application.

This section describes special instructions for managing MediaPlayer when it is implemented in a service.

Asynchronous operation

First, as with activities, all work in a service is done in a single thread by default — in fact, if you run activities and services from the same application, by default they use the same thread (the “main thread”). As a result, the service needs to process incoming intents quickly and never perform lengthy calculations when responding to them. If you expect any heavy work or blocking calls, you must perform these tasks asynchronously: either from another thread that you implement yourself, or using the framework’s many asynchronous processing tools.

When using the MediaPlayer in the main thread, for example, should call the prepareAsync () rather than prepare (), and implement the MediaPlayer. OnPreparedListener purpose is to be notified when after the completion of the ready to start playing. Such as:

public class MyService extends Service implements MediaPlayer.OnPreparedListener {
    private static final String ACTION_PLAY = "com.example.action.PLAY";
    MediaPlayer mMediaPlayer = null;

    public int onStartCommand(Intent intent, int flags, int startId) {
        ...
        if (intent.getAction().equals(ACTION_PLAY)) {
            mMediaPlayer = ... // initialize it here
            mMediaPlayer.setOnPreparedListener(this);
            mMediaPlayer.prepareAsync(); // prepare async to not block main thread
        }
    }

    /** Called when MediaPlayer is ready */
    public void onPrepared(MediaPlayer player) {
        player.start();
    }
}
Copy the code

Handling asynchronous errors

In synchronous operations, errors are usually signaled as exceptions or error codes, but whenever an asynchronous resource is used, you should ensure that the application is notified of the error. For the MediaPlayer, you can realize the MediaPlayer OnErrorListener and set it to the MediaPlayer instance to solve the problem.

public class MyService extends Service implements MediaPlayer.OnErrorListener {
    MediaPlayer mMediaPlayer;

    public void initMediaPlayer() {/ /... initialize the MediaPlayer here... mMediaPlayer.setOnErrorListener(this); } @Override public boolean onError(MediaPlayer mp, int what, int extra) { // ... react appropriately ... // The MediaPlayer has moved to the Error state, must be reset! }}Copy the code

Keep in mind that MediaPlayer will switch to an error state when an error occurs, and you must reset it before using it again.

Use ‘wake locks’

When designing an application that plays media in the background, the device may sleep while the service is running. Since Android tries to save battery while the device is asleep, the system tries to turn off any unnecessary features of the phone, including the CPU and WiFi hardware. However, if your service is playing or streaming music, you want to prevent the system from interfering with your playback.

To ensure that your service continues to run under these conditions, you must use a wakeup lock. Wakelock is a way of signaling to the system that your application is using features that should remain available even when the phone is idle.

Note: You should use wake locks sparingly, and only use them when necessary, as they can greatly reduce the battery life of your device.

To ensure that the CPU continues to run while MediaPlayer is playing, call the setWakeMode() method when MediaPlayer is initialized. Once you do this, MediaPlayer will hold the specified lock while playing and release it when paused or stopped:

mMediaPlayer = new MediaPlayer();
// ... other initialization here ...
mMediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
Copy the code

However, the wakeup lock obtained in this example only keeps the CPU awake. If you’re streaming over the Web and using Wi-Fi, you might also want a WifiLock, which you have to get and release manually. Therefore, when you start preparing MediaPlayer using remote urls, you should create and obtain a Wi-Fi lock. Such as:

WifiLock wifiLock = ((WifiManager) getSystemService(Context.WIFI_SERVICE))
    .createWifiLock(WifiManager.WIFI_MODE_FULL, "mylock");

wifiLock.acquire();
Copy the code

When you pause or stop your media, or when you no longer need the Internet, you should release the lock:

wifiLock.release();
Copy the code

Perform cleanup

As mentioned earlier, the MediaPlayer object can consume a lot of system resources, so you should use it only when you need it and call Release () after using it. It is important to explicitly invoke this cleanup method rather than rely on system garbage collection, because it may take some time for the garbage collector to redeclare MediaPlayer because it is only sensitive to memory requirements and does not lack other media-related resources. Therefore, when using a service, you should always override the onDestroy() method to ensure that MediaPlayer is released:

public class MyService extends Service {
   MediaPlayer mMediaPlayer;
   // ...

   @Override
   public void onDestroy() {
       super.onDestroy()
       if (mMediaPlayer != null) mMediaPlayer.release();
   }
}
Copy the code

Digital Rights Management (DRM)

Since Android 8.0 (API level 26), MediaPlayer has included apis to support playback of DRM protected materials. They are similar to the low-level apis provided by MediaDrm, but they operate at a higher level and do not expose the underlying extractor, DRM, and encrypted objects.

Although the MediaPlayer DRM API does not provide the full capabilities of MediaDrm, it supports the most common use cases. The current implementation can handle the following content types:

  • Widely protected local media files
  • Broadband protects remote/streaming media files

The following code fragment demonstrates how to use the new DRM MediaPlayer method in a simple synchronization implementation.

To manage DRM-controlled media, you need to include new methods in addition to the usual MediaPlayer call stream, as follows:

setDataSource();
setOnDrmConfigHelper(); // optional, for custom configuration
prepare();
if(getDrmInfo() ! = null) { prepareDrm(); getKeyRequest(); provideKeyResponse(); } // MediaPlayer is now ready to use start(); / /... play/pause/resume... stop(); releaseDrm();Copy the code

As usual, initialize the MediaPlayer object and set its source using setDataSource(). Then, to use DRM, perform the following steps:

  1. If you want your application to perform a custom configuration, define the OnDrmConfigHelper interface and attach it to the player using setOnDrmConfigHelper().
  2. Call prepare ().
  3. Call getDrmInfo (). If the source has DRM content, this method returns a non-empty mediaPlayer.drminfo value.

If mediaplayer. DrmInfo exists:

  1. Check the mapping of available Uuid and select one.
  2. Prepare the DRM configuration for the current source program by calling prepareDrm().
    • If you create and register an OnDrmConfigHelper callback, it will be called when prepareDrm() executes. This allows you to perform custom configuration of DRM properties before opening a DRM session. Call the callback function synchronously in the thread calling prepareDrm(). To access DRM properties, call getDrmPropertyString() and setDrmPropertyString(). Avoid lengthy operations.
    • If the device is not already available, prepareDrm() will also visit the configuration server to provide the device. This may take a variable amount of time, depending on the network connection.
  3. To send an opaque array of key request bytes to the license server, call getKeyRequest().
  4. To notify the DRM engine of the key response received from the license server, callprovideKeyResponse(). The result depends on the type of key request:
    • If the response is an offline key request, the result is a keyset identifier. You can use this keyset identifier with restoreKeys() to restoreKeys to a new session.
    • If the response is a stream request or a publish request, the result is empty.

Run prepareDrm() asynchronously

By default, prepareDrm() runs synchronously, blocking until the preparation is complete. However, the first DRM preparation on a new device may also require preparation, which is handled internally by prepareDrm() and may take some time to complete due to the network operations involved. By defining and setting up the MediaPlayer OnDrmPreparedListener, can avoid the prepareDrm obstruction ().

When you set up OnDrmPreparedListener, prepareDrm() performs the request (if required) and preparation in the background. When the DRM is ready, the listener is invoked. You should not make any assumptions about the calling sequence or the thread on which the listener runs (unless the listener is registered with the Handler Thread). Listeners can be called before or after prepareDrm() returns.

Set the DRM asynchronously

You can asynchronously initialization of DRM, by creating and registered MediaPlayer. OnDrmInfoListener used for preparing for DRM and MediaPlayer OnDrmPreparedListener to start the player. They work in conjunction with prepareAsync() as follows:

setOnPreparedListener();
setOnDrmInfoListener();
setDataSource();
prepareAsync();
// ...

// If the data source content is protected you receive a call to the onDrmInfo() callback.
onDrmInfo() {
  prepareDrm();
  getKeyRequest();
  provideKeyResponse();
}

// When prepareAsync() finishes, you receive a call to the onPrepared() callback.
// If there is a DRM, onDrmInfo() sets it up before executing this callback,
// so you can start the player.
onPrepared() {

start();
}
Copy the code

Handling encrypted media

Starting with Android 8.0 (API level 26), MediaPlayer can also decrypt common Encryption Scheme (CENC) and HLS sampled-level encrypted media (METHOD= sample-AES) for h.264 and AAC basic stream types. Previously, full-segment encrypted media (METHOD=AES-128) was supported.

Retrieve the media from the ContentResolver

Another feature that might be useful in a media player application is retrieving local music. You can do this by querying the external media ContentResolver:

ContentResolver contentResolver = getContentResolver();
Uri uri = android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
Cursor cursor = contentResolver.query(uri, null, null, null, null);
if (cursor == null) {
    // query failed, handle error.
} else if(! cursor.moveToFirst()) { // no media on the device }else {
    int titleColumn = cursor.getColumnIndex(android.provider.MediaStore.Audio.Media.TITLE);
    int idColumn = cursor.getColumnIndex(android.provider.MediaStore.Audio.Media._ID);
    do{ long thisId = cursor.getLong(idColumn); String thisTitle = cursor.getString(titleColumn); / /... process entry... }while (cursor.moveToNext());
}
Copy the code

Used in MediaPlayer

long id = /* retrieve it from somewhere */; Uri contentUri = ContentUris.withAppendedId( android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, id); mMediaPlayer = new MediaPlayer(); mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); mMediaPlayer.setDataSource(getApplicationContext(), contentUri); / /... prepare and start...Copy the code

Sample

The SimpleMediaPlayer code example shows how to build a standalone player. The Android-BasicMediadecoder and Android-DeviceOwner examples further illustrate the use of the API described on this page.

To learn more

These pages cover topics related to recording, storing, and playing back audio and video.

Supported media formats

MediaRecorder

Data is stored