Sander Versluys
Sander Versluys

Reputation: 74447

How to create and play a sound or audio queue in Android

I have many short audio fragments which should be played sequentially with minimum latency.

How can I queue these sounds efficiently?

Upvotes: 4

Views: 4449

Answers (2)

Melinda Green
Melinda Green

Reputation: 2140

One way is to concatenate them into a single audio file, then create a MediaPlayer for it and set an OnSeekCompleteListener. Seek to each segment in tern in whichever order you like and then play them in onSeekComplete(). It's timing not exact and MediaPlayer is touchy to use so it may not be the best choice for you but it's good enough for my purposes.

Here's my code:

private MediaPlayer MP = new MediaPlayer();

@Override
public void onCreate(Bundle savedInstanceState) {
    //...

    FileDescriptor fd = getResources().openRawResourceFd(R.raw.pronounciations).getFileDescriptor();
    try {
        setVolumeControlStream(AudioManager.STREAM_MUSIC); // Lets the user control the volume.
        MP.setDataSource(fd);
        MP.setLooping(false);
        MP.prepare();
        MP.start(); // HACK! Some playing seems required before seeking will work.
        Thread.sleep(60); // Really need something like MediaPlayer.bufferFully().
        MP.pause();
        MP.setOnErrorListener(new OnErrorListener() {
            public boolean onError(MediaPlayer mp, int what, int extra) {
                return false;
            }
        });
        MP.setOnSeekCompleteListener(new OnSeekCompleteListener() {
            public void onSeekComplete(MediaPlayer mp) {
                // The clip is queued up and read to play.
                // I needed to do this in a background thread for UI purposes.
                // You may not need to.
                new Thread() {
                    @Override
                    public void run() {
                        MP.start();
                        try {
                            Thread.sleep(soundRanges[curWordID][1]);
                        } catch(InterruptedException e) {}
                        MP.pause();
                    }
                }.start();
            }
        });
    } catch(Throwable t) {}
}

private void playCurrentWord() {
    if(soundRanges != null && !MP.isPlaying() && !silentMode) {
        try {
            MP.seekTo(soundRanges[curWordID][0]);
        }
        catch(Throwable t) {}
    }
}

You would likely need to concatenate your clips using an external sound editing tool. I used Audacity to find and edit the clip beginnings and lengths that I saved in a file.

soundRanges[curWordID][0] is the offset in the sound file of the beginning of a clip and soundRanges[curWordID][1] is its length.

Upvotes: 1

Ken Wolf
Ken Wolf

Reputation: 23269

There are two ways I can see this working: using a MediaPlayer or a SoundPool

MediaPlayer

You can use MediaPlayer.OnCompletionListener combined with a list of files to simply listen for completion and play the next one. By and large this works quite well and I have used it to play sequences of very short clips (< 1s) without problems.

SoundPool

Another way is to use the SoundPool class combined with a handler to simply queue up play events in advance. This assumes you know the length of each clip but depending on the format you should be able to find this out.

Which solution you choose depends on a number of factors: how many files, how short they are, what format they are in, where you are getting them from, how fixed or variable the list is, etc.

Personally I would go with MediaPlayer as this is easier to implement and would probably fit your needs.

Upvotes: 3

Related Questions