Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android MediaPlayer loop has gaps even with OGG format

Tags:

android

audio

In Android 4.x my audio looping app has 0.2 to 0.5 second gaps in the sound loops.

I'm using MediaPlayer as my sounds can be quite large (2-3mb each in some cases) and it can run multiple instances at the same time.

I have researched this quite a bit and I see there is a bug for Android 4.x... however, I have tried many work arounds and I can't seem to get any of them working.

  • Converted all the wavs to OGG using Audacity (quality level 2 to 10, it didn't matter)
  • Tried setNextMediaPlayer()
  • Tried to use seekTo(0) on stop and repeat
  • Tried soundPool which has its own bugs

Here's a sample of the code I'm using:

public class SoundPlayer implements OnCompletionListener {
    private MediaPlayer mp = null;

    public void initPlayer() {
        if(mp == null) {
            mp = new MediaPlayer();
        }
    }

    public void prepare(Context context, int resource) {
    initPlayer();
    try{
        mp.reset();
        Uri uri = Uri.parse("android.resource://com.myapp.app/"+resource);
        mp.setDataSource(context,uri);
        mp.prepare();
        isPrepared = true;
        mp.setOnCompletionListener(this);
    } catch(Exception e) {
        e.printStackTrace();
    }
    }


.......... etc (Uses typical MediaPlayer methods such as stop(), start(), setLooping(true)


}

I'm not using anything special, so I'm just wondering if anyone knows of a work around for the looping bug on Android.

like image 875
user3217336 Avatar asked Jan 21 '14 01:01

user3217336


1 Answers

Okay old Post, but this solution works. This is kind of hack. It'll help somebody if somebody came to this answer.

I am just using three media players. mp1, mp2, mp3. mp1 gets play, and I set mp2 to its setNextMediaPlayer. when mp1 ends, I set mp3 to mp2's setNextMediaPlayer. when mp2 ends, I set mp1 to mp3's setNextMediaPlayer. Following is the complete code which play pause, stop, set vol. Just create an object BZMediaPlayer, start it by providing uri, or resource id.

import android.content.Context;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.net.Uri;
import android.util.Log;

public class BZMediaPlayer {


    private Context context;
    private Uri uri;
    private int resourceId;

    // which file is getting played
    public static final int URI_PLAYING = 1;
    public static final int RESOURCE_PLAYING = 2;
    private int filePlaying;

    // states of the media player
    public static final int STATE_PLAYING = 1;
    public static final int STATE_PAUSED = 2;
    public static final int STATE_STOP = 3;

    // current state
    private int state = STATE_STOP;

    // current mediaPlayer which is playing
    private int mediaPlayerIndex = -1;

    // 3 media players
    private MediaPlayer mp[] = new MediaPlayer[3];

    // current volume
    private float vol;


    public BZMediaPlayer(Context context) {
        this.context = context;
    }

    /**
     * plays the provided uri
     * @param uri
     */
    public void play(Uri uri) {
        this.uri = uri;
        // current playing file
        filePlaying = URI_PLAYING;
        // stop any playing session
        stop();

        // initialize and set listener to three mediaplayers
        for (int i = 0; i < mp.length; i++) {
            mp[i] = MediaPlayer.create(context, uri);
            mp[i].setOnCompletionListener(completionListener);
        }

        // set nextMediaPlayers
        mp[0].setNextMediaPlayer(mp[1]);
        mp[1].setNextMediaPlayer(mp[2]);

        // start the first MediaPlayer
        mp[0].start();
        // set mediaplayer inex
        mediaPlayerIndex = 0;
        // set state
        state = STATE_PLAYING;
    }

    /**
     * play file from resource
     * @param resourceId
     */
    public void play(int resourceId) {
        this.resourceId = resourceId;
        filePlaying = RESOURCE_PLAYING;
        stop();
        for (int i = 0; i < mp.length; i++) {
            mp[i] = MediaPlayer.create(context, resourceId);
            mp[i].setOnCompletionListener(completionListener);
        }

        mp[0].setNextMediaPlayer(mp[1]);
        mp[1].setNextMediaPlayer(mp[2]);

        mp[0].start();
        mediaPlayerIndex = 0;
        state = STATE_PLAYING;
    }

    /**
     * play if the mediaplayer is pause
     */
    public void play() {
        if (state == STATE_PAUSED) {
            mp[mediaPlayerIndex].start();
            Log.d("BZMediaPlayer", "playing");
            state = STATE_PLAYING;
        }
    }

    /**
     * pause current playing session
     */
    public void pause() {
        if (state == STATE_PLAYING) {
            mp[mediaPlayerIndex].pause();
            Log.d("BZMediaPlayer", "pausing");
            state = STATE_PAUSED;
        }
    }

    /**
     * get current state
     * @return
     */
    public int getState() {
        return state;
    }

    /**
     * stop every mediaplayer
     */
    public void stop() {
        for(int i = 0 ; i < mp.length ; i++) {
            if (mp[i] != null) { 
                mp[i].stop();

                if(mp[i].isPlaying()) {
                    mp[i].release();
                }
            }   
        }
        state = STATE_STOP;
    }

    /**
     * set vol for every mediaplayer
     * @param vol
     */
    public void setVol(float vol) {
        this.vol = vol;
        for(int i = 0 ; i < mp.length ; i++) {
            if (mp[i] != null && mp[i].isPlaying()) {
                mp[i].setVolume(vol, vol);
            }   
        }
    }

    /**
     * internal listener which handles looping thing
     */
    private MediaPlayer.OnCompletionListener completionListener = new OnCompletionListener() {

        @Override
        public void onCompletion(MediaPlayer curmp) {
            int mpEnds = 0;
            int mpPlaying = 0;
            int mpNext = 0;
            if(curmp == mp[0]) {
                mpEnds = 0;
                mpPlaying = 1;
                mpNext = 2;
            }
            else if(curmp == mp[1]) {
                mpEnds = 1;
                mpPlaying = 2;
                mpNext = 0;  // corrected, else index out of range
            }
            else if(curmp == mp[2]) {
                mpEnds = 2;
                mpPlaying = 0; // corrected, else index out of range
                mpNext = 1; // corrected, else index out of range
            }

            // as we have set mp2 mp1's next, so index will be 1
            mediaPlayerIndex = mpPlaying;
            Log.d("BZMediaPlayer", "Media Player " + mpEnds);
            try {
                // mp3 is already playing release it
                if (mp[mpNext] != null) {
                    mp[mpNext].release();
                }
                // if we are playing uri
                if (filePlaying == URI_PLAYING) {
                    mp[mpNext] = MediaPlayer.create(context, uri);
                } else {
                    mp[mpNext] = MediaPlayer.create(context, resourceId);
                }
                // at listener to mp3
                mp[mpNext].setOnCompletionListener(this);
                // set vol
                mp[mpNext].setVolume(vol, vol);
                // set nextMediaPlayer
                mp[mpPlaying].setNextMediaPlayer(mp[mpNext]);
                // set nextMediaPlayer vol
                mp[mpPlaying].setVolume(vol, vol);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    };

}

Hope it will help somebody

Edit: clean code

like image 159
moonzai Avatar answered Oct 18 '22 18:10

moonzai