Play the sound already

I spent all day figuring out how to play a mp3 file in my Android app.  Before you start to question my programming skills (which is fine) let me add a few requirements:

1. The sound file is contained in a subdirectory within my assets

2. The code should work for external assets outside of the bundle as well as assets within the bundle.  For this reason I didn’t want to use resource ids.

3. The file should be streamed and not loaded entirely into memory.

The MediaPlayer seems like the best option to use and I immediately tried coding to that.  I spent most of the time trying to get the Uri implementation to work (ex: “file:///android_asset/sounds/music.mp3”) but that just refused to work for me.

I was able to use the AssetManager to get a AssetFileDescriptor which can give you a FileDescriptor that can be used as a data source for the MediaPlayer.

Here is the code:

// get the asset file descriptor from our context
AssetFileDescriptor afd = mContext.getAssets().openFd(filename);

// media player created in idle state (always call setDataSource next)
MediaPlayer mp = new MediaPlayer();

// setting data source puts media player into the initialized state
mp.setDataSource(afd.getFileDescriptor(), 
                 afd.getStartOffset(), 
                 afd.getLength());

// setting of looping should be done in the initialized or 
// prepared state (not idle state)
mp.setLooping(false);

// prepare required before calling start or stop methods
mp.prepare();

// listeners require running on the ui thread
mp.setOnCompletionListener(new OnCompletionListener()
{
    public void onCompletion(MediaPlayer mp)
    {
        mp.release();
    }
});

// finally play it
mp.start();

// cleanup afd
afd.close();