matdev
matdev

Reputation: 4283

Android's Media Player: Why is an audio loop not staying synced with metronome playing at the same BPM?

I am using Android's MediaPlayer to loop audio files. I set the media player looping with

mMediaPlayer.setLooping(true);

After several repetitions, the loop starts earlier than it should do i.e. if I play the same loop on a computer, with a metronome running independently at the same BPM as the loop, Android's Media player and metronome stay synced for a few bars, but after a couple of loop, the loop played with the app starts too early.

I've read about other peoples complaining about this problem.

I reproduce this problem both on Android 4.4 and Android 6

Here is a minimal Android project for reproducing the problem: https://drive.google.com/open?id=0B9FRLIzBQgR1WWdMU29ZcHdsMXc

Upvotes: 1

Views: 558

Answers (2)

Kaushal28
Kaushal28

Reputation: 5557

In my project, I had the same issue and I found he solution in SO somewhere, I don't remember exactly where. But here what I've done:

You can try using a handler to set seek to beginning x milliseconds before the end of file

loopTimer = new Timer();
loopTask = new TimerTask() {               
    @Override public void run() {
        mMediaPlayer.seekTo(0);
    }
};
long waitingTime = mMediaPlayer.getDuration()-mLoopingPreview;
loopTimer.schedule(loopTask, waitingTime, waitingTime);

Now just set mLoopingPreview to some reasonable time value. I'm using 80ms.

Upvotes: 2

rafsanahmad007
rafsanahmad007

Reputation: 23881

I also faced this problem...in Mediaplayer

There is couple of solution:

1.use ogg format sound file (https://en.wikipedia.org/wiki/.ogg)

2.Can use soundpool it has a looping and caching facility for media play (https://developer.android.com/reference/android/media/SoundPool.html)

3.Also you can use the following class: it initialize a new mediaplayer as soon as the first one finishes..so the delay is less more obvious

    public class LoopMediaPlayer {

    public static final String TAG = LoopMediaPlayer.class.getSimpleName();

    private Context mContext = null;
    private int mResId = 0;
    private int mCounter = 1;

    private MediaPlayer mCurrentPlayer = null;
    private MediaPlayer mNextPlayer = null;

    public static LoopMediaPlayer create(Context context, int resId) {
        return new LoopMediaPlayer(context, resId);
    }

    private LoopMediaPlayer(Context context, int resId) {
        mContext = context;
        mResId = resId;

        mCurrentPlayer = MediaPlayer.create(mContext, mResId);
        mCurrentPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
            @Override
            public void onPrepared(MediaPlayer mediaPlayer) {
                mCurrentPlayer.start();
            }
        });

        createNextMediaPlayer();
    }

    private void createNextMediaPlayer() {
        mNextPlayer = MediaPlayer.create(mContext, mResId);
        mCurrentPlayer.setNextMediaPlayer(mNextPlayer);
        mCurrentPlayer.setOnCompletionListener(onCompletionListener);
    }

    private MediaPlayer.OnCompletionListener onCompletionListener = new MediaPlayer.OnCompletionListener() {
        @Override
        public void onCompletion(MediaPlayer mediaPlayer) {
            mediaPlayer.release();
            mCurrentPlayer = mNextPlayer;

            createNextMediaPlayer();

            Log.d(TAG, String.format("Loop #%d", ++mCounter));
        }
    };
}

to use it just call

LoopMediaPlayer.create(context, R.raw.sound_file_name);

instead of mp.setLooping(true);

Upvotes: 0

Related Questions