sjngm
sjngm

Reputation: 12861

Android: AudioTrack vs. multithreading

I'm facing a problem where I want to play a half second long AudioTrack in static mode repeatedly, but the sound is choppy. However, I noticed that the sound is perfectly clear while a TransitionDrawable is running in parallel.

A simplified skeleton of my code is:

thread = new Thread(new Runnable() {

  public void run() {
    createTransition();

    try {
      createAudioTrack();

      while (true) {
        if (audio) {
          playSoundClip();
        }

        if (display) {
          playScreenTransition();
        }

        Thread.sleep(getDelayBetweenBeats());
      }
    } catch (InterruptedException e) {
    } finally {
      resetScreenTransition();
      stopSoundClip();
    }
  }

  private void createAudioTrack() {
    short[] samples = generateSamples();
    track = new AudioTrack(AudioManager.STREAM_MUSIC, SAMPLERATE, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, samples.length * 2, AudioTrack.MODE_STATIC);
    if (track.getState() != AudioTrack.STATE_UNINITIALIZED) {
      track.write(samples, 0, samples.length);
    }
  }

  private void playSoundClip() {
    if (track != null && track.getState() != AudioTrack.STATE_UNINITIALIZED) {
      track.stop();
      track.reloadStaticData();
      track.play();
    }
  }

  private void playScreenTransition() {
    view.post(new Runnable() {

      public void run() {
        view.setBackgroundDrawable(transition);
        transition.startTransition(DURATION);
      }

    });
  }

});
thread.start();

As you can see thread is not performed on the UI-thread so I assume that the track is facing multithreading problems. I don't think that the UI-thread that plays the transition consumes the entire CPU since my audio is playing in parallel. It seems as if the activity somehow consumes the CPU and nothing else is executed.

I had tried to use view.post(new Runnable() {...}); in playSoundClip(), too, but that didn't help.

I thought about changing all into an AsyncTask, but IMHO that wouldn't change anything as it would still be a background task. Since I don't need to update an UI-element with the sound and the transition still has to play in parallel I didn't even try that.

A solution would probably be to always have some transition running in parallel (the actual one or a dummy one), but that just sounds bad (pun?) to me.

Does anyone know of another way how I can make track play clear at all times?


EDIT:
After working some more in this issue and extending my program I noticed that I have to use a threaded approach like I lined out above as the logic in there takes some time to complete and I can't do it all on the UI-thread any more. Currently I play a dummy transition while the audio is playing, which still sounds bad to me. Therefore, if you can still contribute some insights into this topic you are welcome to post/answer them here.

Upvotes: 1

Views: 2569

Answers (2)

devunwired
devunwired

Reputation: 63293

You might want to take a look at SoundPool, which would allow you to statically load your short audio sample into memory once and then play it on-demand with much lower latency. The way in which you are using AudioTrack is a good use of replaying the audio without reloading, but it might still be a bit heavy-weight for such a short and often repeated sound byte.

You might also consider not using a background thread at all. It looks from your snippet like you are really just using the Thread as a timer, and you might get better performance out of using a Handler to post your Runnable on a timed interval (which would also allow you to call your audio/transition methods on the main thread) instead.

HTH

Upvotes: 2

eliteslayer
eliteslayer

Reputation: 190

I have much larger chunks of audio but I have had luck playing them in a Service that I created.

P.S. Nice Pun

Upvotes: 0

Related Questions