Mackovich
Mackovich

Reputation: 3573

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:

EDIT 1

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

Upvotes: 11

Views: 17370

Answers (5)

Akash Manubansh
Akash Manubansh

Reputation: 1

hi try below code it will work it the song wont stop you just need to select the song from spinner and click on start button, then select next song from spinner and click start it will work.

public class MainActivity extends AppCompatActivity {

    Spinner sp;
    Button bstart;
    MediaPlayer mp;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        sp=(Spinner)findViewById(R.id.sp);
        String [] mys={"demo","democheap","demorehana"};
        ArrayAdapter<String> data=new ArrayAdapter<String>(this,R.layout.support_simple_spinner_dropdown_item,mys);
        sp.setAdapter(data);

    }

    public void code(View v)
    {
        if(sp.getSelectedItem().toString().equals("demo"))
        {
            mp=MediaPlayer.create(this,R.raw.demo);
        }
        else if(sp.getSelectedItem().toString().equals("democheap"))
        {
            mp=MediaPlayer.create(this,R.raw.democheap);
        }
        else if(sp.getSelectedItem().toString().equals("demorehana"))
        {
            mp=MediaPlayer.create(this,R.raw.demorehana);
        }

        if(v.getId()==R.id.bstart)
        {
            mp.start();
        }
    }
}

Upvotes: 0

Boris Karloff
Boris Karloff

Reputation: 1328

I converted my mp3 in ogg file audio (using Audacity) and I am been able to use 2 Mediaplayer istances and listen the audio mixed.

I didn't try is it is possible for more than 3.

Upvotes: 0

Alex
Alex

Reputation: 151

As Andrey Nikishaev already wrote in a comment, it seems like some devices have problems using multiple MediaPlayers at the same time. While only one was playing on my Nexus 5, it worked on my Moto G4 (but still having short breaks during playback). Both running with Android 6.0.1.

I suggest to use the ExoPlayer for this use-case instead. It worked fine for me, at least on my two devices.

Upvotes: 1

Mackovich
Mackovich

Reputation: 3573

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.

Upvotes: 2

Carter Hudson
Carter Hudson

Reputation: 1263

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.

Upvotes: 8

Related Questions