Android* MediaPlayer Sample Code Walkthrough on Intel® Architecture

Introduction

Media playback is becoming one of the most popular usage models on mobile devices. People expect to be able to play common multimedia types on their mobile devices and view video on the go. This document will discuss the basics of creating Android media applications, and provide a sample code walkthrough of the MediaPlayer API on Intel® architecture-based platforms.

Android Multimedia Framework – MediaPlayer API

The Android multimedia framework provides developers a way to easily integrate audio and video playback into applications, and supports most of the common media types. The MediaPlayer class is the key in Android multimedia framework. It can be used to play media on the local file system, media files stored in the application’s resources, as well as data streaming over a network connection.

Managing the state

MediaPlayer is a state-based class; it has an internal state machine managing all the states in the life cycle of a MediaPlayer object. The diagram below shows the state changes of the MediaPlayer object for the playback control. In this diagram, a single arrow represents synchronous method calls, and a double arrow represents asynchronous method calls and callbacks.


Figure 1. State Changes of MediaPlayer Object. (Single arrows represent synchronous method calls, and double arrows represent asynchronous method calls)

From the diagram, you can see that the MediaPlayer object has several states in the life cycle. At the beginning, creating a new MediaPlayer or calling the reset() method causes the MediaPlayer to go in to the Idle state. Idle state is where everything starts from, but playback cannot yet occur. If any playback controlling methods are invoked such as start(), stop(), seekTo(int), etc., a programming error will result.

The next thing the app must do is call the setDataSource() method to point to a valid media source, causing the player to go in to the Initialized state. The source can be either a local file or data streaming from a network connection.

In the Initialized state and before playback can be started, the app can call prepare() or prepareAsync() to go in to the Prepared state. The prepare() method does the work of fetching, buffering, and decoding the media file. However, prepare() can take a very long time to return when fetching media data from a network URL, particularly if the network connection is slow. So it’s not recommended to run prepare() in application UI thread, which might result in the application not responding and a bad user experience. Use prepareAsync() instead, which was designed to address this problem and provide a convenient way to prepare the media data while keeping the UI responsive. prepareAsync() runs in the background and returns immediately once done, sending out a OnPreparedListener.onPrepared() callback, in order to bring the MediaPlayer object in to the Prepared state.

From the Prepared state, you can start the playback and control it by calling start() and seekTo(). Once the media playback is started, the MediaPlayer object goes into the Started state.

After playback is started, you can control the playback using the pause() method to move it into the Paused state, or call start() to bring it back to the Started state. If the playback goes to the end and looping is not set to make it start over from the beginning, the MediaPlayer moves in to the PlaybackCompleted state. At this point, you can also call the start() method to start playback again, and the state goes back to the Started state. However, if you call stop() from Started/Paused/PlaybackCompleted, the state machine moves into the Stopped state. From here, you can go to the End state and release the MediaPlayer, or if you want to play the media again, you have to prepare the media data before calling start() again.

You should always remember to call the release() method after each use to put the MediaPlayer object in to the End state; otherwise, it keeps consuming system resources. If you keep creating new MediaPlayer instances without calling the release() method, your application can consume all the system resources very quickly.

If you registered OnErrorListener, the OnErrorListener.onError() callback method will be invoked in all error conditions, so that you can handle errors accordingly.

Using MediaPlayer to play Audio and Video

Now let’s take a look at the code for how to play audio and video using MediaPlayer.

For Audio:

private void playAudio(Integer media) {
    try {
        switch (media) {
            case LOCAL_AUDIO:
                path = "/sdcard/Download/music/1.mp3";
                mMediaPlayer = new MediaPlayer();
                mMediaPlayer.setDataSource(path);
                mMediaPlayer.prepare();
                mMediaPlayer.start();
                break;
            case RESOURCES_AUDIO:
                mMediaPlayer = MediaPlayer.create(this, R.raw.test_cbr);
                mMediaPlayer.start();

        }
    } catch (Exception e) {
        Log.e(TAG, "error: " + e.getMessage(), e);
    }

}

@Override
protected void onDestroy() {
    super.onDestroy();
    // TODO Auto-generated method stub
    if (mMediaPlayer != null) {
        mMediaPlayer.release();
        mMediaPlayer = null;
    }

}

For Video:

private void playVideo(Integer Media) {
    doCleanUp();
    try {

        switch (Media) {
            case LOCAL_VIDEO:
                path = "/sdcard/Download/video/2.mp4";
                break;
            case STREAM_VIDEO:
                path = "Your URL here";
                break;
        }
        mMediaPlayer = new MediaPlayer();
        mMediaPlayer.setDataSource(path);
        mMediaPlayer.setDisplay(holder);
        mMediaPlayer.prepare();
        mMediaPlayer.setOnBufferingUpdateListener(this);
        mMediaPlayer.setOnCompletionListener(this);
        mMediaPlayer.setOnPreparedListener(this);
        mMediaPlayer.setOnVideoSizeChangedListener(this);
        mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);

    } catch (Exception e) {
        Log.e(TAG, "error: " + e.getMessage(), e);
    }
}
public void onBufferingUpdate(MediaPlayer arg0, int percent) {
    Log.d(TAG, "onBufferingUpdate percent:" + percent);
}
public void onCompletion(MediaPlayer arg0) {
    Log.d(TAG, "onCompletion called");
}
public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
    Log.v(TAG, "onVideoSizeChanged called");
    if (width == 0 || height == 0) {
        Log.e(TAG, "invalid video width(" + width + ") or height(" + height + ")");
        return;
    }
    mIsVideoSizeKnown = true;
    mVideoWidth = width;
    mVideoHeight = height;
    if (mIsVideoReadyToBePlayed && mIsVideoSizeKnown) {
		startVideoPlayback();
    }
}
public void onPrepared(MediaPlayer mediaplayer) {
    Log.d(TAG, "onPrepared called");
    mIsVideoReadyToBePlayed = true;
    if (mIsVideoReadyToBePlayed && mIsVideoSizeKnown) {
        startVideoPlayback();
    }
}
@Override
protected void onPause() {
    super.onPause();
    releaseMediaPlayer();
    doCleanUp();
}
@Override
protected void onDestroy() {
    super.onDestroy();
    releaseMediaPlayer();
    doCleanUp();
}
private void releaseMediaPlayer() {
    if (mMediaPlayer != null) {
        mMediaPlayer.release();
        mMediaPlayer = null;
    }
}
private void doCleanUp() {
    mVideoWidth = 0;
    mVideoHeight = 0;
    mIsVideoReadyToBePlayed = false;
    mIsVideoSizeKnown = false;
}
private void startVideoPlayback() {
    Log.v(TAG, "startVideoPlayback");
    holder.setFixedSize(mVideoWidth, mVideoHeight);
    mMediaPlayer.start();
}

As you can see from the code, for both audio and video, the MediaPlayer moves through the life cycle and state changes according to the state change diagram we discussed above.

 Visit Intel Android page to get more resources for your apps on Android IA projects.

Reference

  1. http://developer.android.com/reference/android/media/MediaPlayer.html
  2. http://developer.android.com/reference/android/widget/MediaController.html

Intel and the Intel logo are trademarks of Intel Corporation in the U.S. and/or other countries.
Copyright © 2013 Intel Corporation. All rights reserved.
*Other names and brands may be claimed as the property of others.