Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the proper way to use AudioTrack in static mode?

I have an Android game that I need to play short sounds. SoundPool crashes on dual core phones, Mediaplayer has up to 200ms+ delays, OpenSL requires SDK 9+ (I support 1.5). So that leaves AudioTrack.

This is what I have tried. I create the AudioTrack objects like this.

protected AudioTrack createAudioTrack() {
    final int trackSize = 17408;
    return new AudioTrack(AudioManager.STREAM_MUSIC, 44100, AudioFormat.CHANNEL_CONFIGURATION_STEREO, AudioFormat.ENCODING_PCM_16BIT, trackSize, AudioTrack.MODE_STATIC);
}

I then create a runnable for each in game sound (about 8).

private static class SoundRunnable implements Runnable {

    private final AudioTrack sound;
    private final byte[] rawAudio;

    public SoundRunnable(final AudioTrack sound, final byte[] rawAudio){
        this.sound = sound;
        this.rawAudio = rawAudio;
        sound.write(rawAudio, 0, rawAudio.length);
    }

    @Override
    public void run() {
        playSound();
    }

    private synchronized void playSound() {
        switch (sound.getPlayState()) {
        case AudioTrack.PLAYSTATE_PAUSED:
            sound.stop();
            sound.reloadStaticData();
            sound.play();
        break;
        case AudioTrack.PLAYSTATE_PLAYING:
            sound.stop();
            sound.reloadStaticData();
            sound.play();
        break;
        case AudioTrack.PLAYSTATE_STOPPED:
            sound.reloadStaticData();
            sound.play();
        break;
        default:
            break;
        }
    }   

    public synchronized void release() {
        sound.release();
    }

}

Then when I need to play the sound I send it to a ThreadPool.

private void playSound(final int soundToPlay) {
    final SoundRunnable soundRunnable = mediaPlayers.get(soundToPlay);
    if(soundRunnable != null){
        threadPool.execute(soundRunnable);
    }
}

The main issue I have is that sounds play twice the first time I execute the runnable. After that every once in a while I still might get a double sound but it works pretty well.

I have also experimented with creating a single AudioTrack in streaming mode and writing raw audio from the runnables. This was somewhat successfull but was difficult to know when to stop the play back. I you stop to early the sound is cut short, too late and you get an obtainBuffer error and the app locks up. Also playing two sounds at the same time is difficult (could possiblly use a pool of AudioTracks).

I would love to see sample code for AudioTrack that doesn't involve streaming audio.

like image 251
theJosh Avatar asked Nov 14 '22 02:11

theJosh


1 Answers

I asked this question during Google office hours. They said that AudioTrack has the same bug as SoundPool. The only solution to this problem is to write a native media player. Although, this issue does only seem to effect Dual Core phones running Gingerbread.

like image 103
theJosh Avatar answered Nov 16 '22 04:11

theJosh