5

I have a small app that basically sets up a timer and plays sets of 2 sounds one after another.

I've tried 2 timers, because I wanted both sounds to start exactly at the same time each time. I gave the app 500ms for setting both timers before they start

    Calendar cal = Calendar.getInstance();
    Date start = new Date(cal.getTime().getTime() + 500);

    timerTask1 = new TimerTask() { //1st timer
      @Override
      public void run() {
          soundManager.playSound(1);
      }
    };
    timer1 = new Timer();
    timer1.schedule(timerTask1, start, 550);


    timerTask2 = new TimerTask() { //2nd timer
      @Override
      public void run() {
          soundManager.playSound(2);
      }
    };
    timer2 = new Timer();
    timer2.schedule(timerTask2, start, 550);
}

soundManager is a SoundManager object which is based on this tutorial. Thew only change I've made was decreasing number of avalible streams from 20 to 2 since I play only 2 sounds at the same time.

Now the problem. It's not playing at the equal rate neither on my Motorola RAZR or the emulator. The app slows sometimes, making a longer brake than desired. I can't let that happen. What could be wrong here?

I'm using very short sounds in OGG format

EDIT: I've made some research. Used 2 aproaches. I was measuring milisecond distances between sound was fired. Refresh rate was 500 ms.

  • 1st aproach was TimerTask - it is a big fail. It started at 300ms, then was constantly growing, and after some time (2 mins) stabilized at 497ms which would be just fine if it started as that.
  • 2nd aproach was while loop on AsyncTask - it was giving me outputs from 475 to 500ms which is better than TimerTask but still inaccurate

At the end none of aproach was playing smoothly. There were always lags

Community
  • 1
  • 1
Jacek Kwiecień
  • 12,397
  • 20
  • 85
  • 157
  • 2
    First, `TimerTask` is not guaranteed to be real-time, so I can well imagine something interrupting your process in the 50 milliseconds between each sound. Second, it seems that calling `soundManager.playSound(1);` then `soundManager.playSound(2);` [will play sequentially](http://stackoverflow.com/questions/4342491/how-to-sync-sounds-using-soundpool). – Ken Y-N Aug 20 '12 at 07:45
  • note that both sounds are played from separated threads, so I hoped they start in the exact same time, since they were give same start time. What would be some equivalent for timer task then? – Jacek Kwiecień Aug 20 '12 at 12:49
  • What is the size of the each ogg file – Sherif elKhatib Aug 23 '12 at 22:49

2 Answers2

5

I know it may be a little too much, but you could try a different implementation of SoundPool:

public class Sound {
    SoundPool soundPool;
    int soundID;

    public Sound(SoundPool soundPool, int soundID) {
        this.soundPool = soundPool;
        this.soundID = soundID;
    }

    public void play(float volume) {
        soundPool.play(soundID, volume, volume, 0, 0, 1);
    }

    public void dispose() {
        soundPool.unload(soundID);
    }
}

To use it you can do something like this:

SoundPool soundPool = new SoundPool(20, AudioManager.STREAM_MUSIC, 0);
AssetFileDescriptor assetFileDescriptor = activity.getAssets().openFd(fileName);
int soundID = soundPool.load(assetFileDescriptor, 0);

Sound sound = new Sound(soundPool, soundID);

And then play:

sound.play(volume);

P.S. If the problem persists even with this code, post a comment and I'll get back to you.

dragostis
  • 2,574
  • 2
  • 20
  • 39
  • I think the problem might be somewhere else than in SoundPool. According to this article http://masterex.github.com/archive/2012/05/28/android-audio-synthesis.html the TimerTask cant guarantee me execution in the right time... – Jacek Kwiecień Aug 26 '12 at 13:09
  • 1
    Try to use AudioTrack then. It might be the case that SoundPool is not efficient enough. In this case, AudioTrack shall be a better choice: [Android Developers Docs](http://developer.android.com/reference/android/media/AudioTrack.html) The implementation can be similar to the Sound class only this one need a little bit more info. If you have problems implementing it, I can help. Just comment or PM me. – dragostis Aug 26 '12 at 13:43
  • http://www.martinhoeller.net/2012/01/13/developing-a-musical-instrument-app-for-android/ found this nice tutorial, did everything as stated there. Still basically same lags. i think its not the case of sound manager, rather the loop lags. I don't know how to fix that. I added notes in the question – Jacek Kwiecień Aug 26 '12 at 20:27
  • Maybe you should try Fork/Join from Java 7: [Java Docs](http://docs.oracle.com/javase/tutorial/essential/concurrency/forkjoin.html) – dragostis Aug 27 '12 at 09:02
  • Finally tried approach you posted, but the output is the same. Fork/Join from Java7? I don't think android 2.1 has that...? – Jacek Kwiecień Aug 29 '12 at 18:16
  • If you have Java 7, if will use the libraries from Java 7, so they are usable. Just look it up. I gave you a link. Search Google for more about Fork/Join. – dragostis Aug 29 '12 at 18:48
  • I don't think that using another threading system will help. The loop I've created is pretty accurate. It's the sound itself which lags. In the metronome sample its developer created constatnt AudioTrack from a sound and proper time of silence.. I think this might be the only way... however I'm not sure if its doable for set of 5 sounds – Jacek Kwiecień Aug 29 '12 at 19:07
1

Are you using SoundPool? It is quicker than MediaPlayer. The best chance of getting the two sounds together is when playing them on the same thread.

Sameer
  • 4,379
  • 1
  • 23
  • 23