Using a buffer with Android AudioTrack

William Seemann picture William Seemann · Dec 11, 2013 · Viewed 20.3k times · Source

I'm trying to figure how I would use a buffer with AudioTrack to effectively stream music. I know you can queue audio using the write method but once the audio is queued how do you tell how much is left vs. how much has been used/played? Sorry if this is a rudimentary question. I understand the concept of a buffer I'm just not sure how to write one, especially using AudioTrack.

Answer

Andrew Martin picture Andrew Martin · Dec 18, 2013

AudioTrack.write() returns "number of bytes written" as an int, and you specify the number of bytes in the buffer when constructing the AudioTrack.

Therefore, to track how much buffer space remains, you could keep an accumulator variable so you know how many bytes have been written in total, and set this variable to zero whenever you call AudioTrack.flush(). However, the linked documentation states "it is typical to use chunks of 1/2 of the total size to permit double-buffering", so it might be simple enough to simply remember if you've written zero, once or twice since calling flush.

To tell how much of the buffer has been played, use AudioTrack.getPlaybackHeadPosition() which returns the number of frames that have been played of the current buffer (i.e. reset to zero on stop, flush or reload) as signed 32-bit integer but to be interpreted as an unsigned 32-bit integer. All this really means is that you assign it to an int as follows.

int bufferPlaybackFrame = myAudioTrack.getPlaybackHeadPosition() & 0xFF;

You can think of frames as equivalent to samples. i.e. You can work out from the AudioFormat used to construct the AudioTrack how many bits (and hence bytes) are being used per sample.

Finally, in case someone was wondering, you'll never be able to tell how much of the source file or stream is left to play through this object (one reason being it's designed to work with permanent 24/7 streams, with no ending), so if you wanted to make a calculation like you see on some video playing websites, that pause the stream until enough id buffered to see the whole video at your current download rate, you'll have to pass that information in some other way.