Search code examples
androidaudiotrack

How to use AudioTrack in static mode


I want to play float arrays on Android. I wanted to go the (what I thought was the) easy way first so thought I'd use AudioTrack. I chose to use static mode because the audio stream is not continuous. In the documentation it says:

In static buffer mode, copies the data to the buffer starting at offset 0, and the write mode is ignored. Note that the actual playback of this data might occur after this function returns.

So initially my implementation looked like:

// constructor ..
audioTrack = new AudioTrack(new AudioAttributes.Builder()
                            .setUsage(AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE)
                            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION).build(),
                                    new AudioFormat.Builder()
                            .setEncoding(AudioFormat.ENCODING_PCM_FLOAT)
                            .setSampleRate(sample_rate)
                            .setChannelMask(AudioFormat.CHANNEL_OUT_STEREO).build(),
                sample_rate * 2 * 10, AudioTrack.MODE_STATIC, AudioManager.AUDIO_SESSION_ID_GENERATE);
[...]
public ... () { // function
    audioTrack.write(sound, 0, sound.length, AudioTrack.WRITE_NON_BLOCKING);
    audioTrack.play()

Which lead to the first problem that a sound could only play once. I found I need to be calling stop() and reloadStaticData() after play(). But this results in the first sound not being played at all. And any following sounds to be played wrongly (meaning the sound is wrong).

I tried out putting stop() and reloadStaticData() after write() and before play(), then the first sound is played but the next ones are wrong (they're a cut off version of the first sound instead of a different sound).

From these experiences it seems to me like write() is not actually writing to the start of the buffer. In general how to use AudioTrack is completely unclear to me. stop() seems to stop playback. But I have to call it after play() to reset the playback head position.


Solution

  • Turns out my phone speakers couldn't play the sound... this is my solution

    public void play_sound(float[] sound) {
            if (audioTrack.getPlayState() == AudioTrack.PLAYSTATE_PLAYING) {
                audioTrack.stop();
                audioTrack.reloadStaticData();
            }
    
            float[] buffer = new float[buffer_size_in_bytes / 4];
            for (int i = 0; i < sound.length; i++) {
                buffer[i] = sound[i];
            }
            // Last arg is ignored.
            audioTrack.write(buffer, 0, buffer.length, AudioTrack.WRITE_BLOCKING);
            audioTrack.play();
        }