Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Playing multiple songs with MediaPlayer at the same time: only one is really playing

I need help with playing multiple audio tracks at the same time in Android.

I am supposed to play three audio tracks at the exact same time using Android.Media.MediaPlayer.

Yesterday I managed to make it work doing so :

MediaPlayer track1 = MediaPlayer.create(this, R.raw.track1);
MediaPlayer track2 = MediaPlayer.create(this, R.raw.track2);
MediaPlayer track3 = MediaPlayer.create(this, R.raw.track3);

As you can see, I have three distincts instances of MediaPlayer here.

Because I am asked to, I need to have these MediaPlayer being played in a background thread.

Here is the part where I start the MediaPlayers:

//let's suppose this code snippet is in a run() method inside a Thread (which is the case)
track1.start();
track2.start();
track3.start();

If I say yesterday, it's because the next day, it did not work as supposed to.

Indeed, starting a MediaPlayer seems to stop any previous playing MediaPlayer.

I tested in debugger mode : clearly, track2.start() stops track1's MediaPlayer and following the same pattern, track3.start() stops tack2's MediaPlayer.

So at the end, only track3 is being played, I cannot hear any of the previous tracks, whatever the volume settings are whereas I could cleary hear all of them before : it is supposed to create some sort an ambiance.

Of course, changing the order in which the tracks are started does not change anything : only the last track will be heard.

If I say "heard" it is because in debugger mode, checking the property MediaPlayer.isPlaying is returning true : all three players are saying they are playing but only one can be heard... !

Why the change ? Why did it work once to stop working afterwards ?

NOTE:

  • the audio files have all the same duration which is approximately about 15 minutes
  • the audio files were .mp3 files compressed into .acc files (from 320kbps to 144kbps)
  • I am working under Xamarin Studio in C# but for clarety purpouse I will stick to small Java code snippets.

EDIT 1

According to this Play two mp3 song at the same time my solution should be working, right ?

like image 457
Mackovich Avatar asked Oct 15 '14 09:10

Mackovich


2 Answers

I achieved what you're looking for using a CyclicBarrier instance and an inner class implementation.

Example:

public enum MP_COMMAND {
    START,
    STOP,
    PAUSE
}

/**
 * Uses threads to execute synced commands for the current video media player and 
 * background music player in tandem.
 */
public void syncedCommand(MediaPlayer player1, MediaPlayer player2, MP_COMMAND command) {
    final CyclicBarrier commandBarrier = new CyclicBarrier(2);
    new Thread(new SyncedCommandService(commandBarrier, player1, command)).start();
    new Thread(new SyncedCommandService(commandBarrier, player2, command)).start();
}

/**
 * Inner class that starts a given media player synchronously
 * with other threads utilizing SyncedStartService
 */
private class SyncedCommandService implements Runnable {
    private final CyclicBarrier              mCommandBarrier;
    private       MediaPlayerTest.MP_COMMAND mCommand;
    private       MediaPlayer                mMediaPlayer;

    public SyncedCommandService(CyclicBarrier barrier, MediaPlayer player, MediaPlayerTest.MP_COMMAND command) {
        mCommandBarrier = barrier;
        mMediaPlayer = player;
        mCommand = command;
    }

    @Override public void run() {
        try {
            mCommandBarrier.await();
        } catch (InterruptedException | BrokenBarrierException e) {
            e.printStackTrace();
        }

        switch (mCommand) {
            case START:
                mMediaPlayer.start();
                break;

            case STOP:
                mMediaPlayer.stop();
                break;

            case PAUSE:
                mMediaPlayer.pause();
                break;

            default:
                break;
        }
    }
}

You'd utilize it like so:

syncedCommand(mCurrentVideoPlayer, mBackgroundMusic, MP_COMMAND.START);

If you had the requirement that it be usable for any number of media players, you could easily implement it - my requirements just call for two.

I realize this question is old, but this page is where I found myself while searching for a solution, so I hope this helps anyone stuck on this issue in the future.

like image 162
Carter Hudson Avatar answered Oct 27 '22 01:10

Carter Hudson


Well, I believe I found what I could name "a temporary solution".

MediaPlayer track1 = MediaPlayer.create(this, R.raw.track1);
track1.start();
MediaPlayer track2 = MediaPlayer.create(this, R.raw.track2);
track2.start();
MediaPlayer track3 = MediaPlayer.create(this, R.raw.track3);
track3.start();

The problem with this is that the create() method creates a noticeable gap when the songs are being played.

So this is not it.

After a while, I tried the following :

MediaPlayer track1 = MediaPlayer.create(this, R.raw.track1);
track1.start();
track1.pause();
MediaPlayer track2 = MediaPlayer.create(this, R.raw.track2);
track2.start();
track2.pause();
MediaPlayer track3 = MediaPlayer.create(this, R.raw.track3);
track3.start();
track3.pause();

// resuming...
track1.start(); 
track2.start();
track3.start();

That whay, the songs are more synchronous. I can still hear a very small gap but it is way better. I found this solution quite strange as well as ugly.

Unless someone has another idea, I will stick with that solution.

like image 24
Mackovich Avatar answered Oct 27 '22 01:10

Mackovich