2015年4月6日 星期一

[Android] Why the sound is not playing smoothly when using AudioTrack()?

When we use AudioTrack(), if the tone is too high or too low, the problem may be caused by wrong format or wrong sample length.

What if the sound is not playing smoothly?
Especilly when we encounter the error message similar with the following:
W/AudioTrack(..): releaseBuffer() track 0x6eaf04d0 name=0x1 disabled, restarting
How should we do?

In general, it means that we feed the data too slowly.
For local file, it should not have such problem.
But for streaming source, the input data rate is not constant.
We may encounter the problem of buffer underflow sometimes.

We can either add the buffer mechanism in the network part when receiving streaming data, or can we add buffer when feeding data into AudioTrack.

Let's see the demo for second method - adding buffer for AudioTrack.

private static void queueAudioData(byte[] buf, int size) {  
 if((audioPcmBufferDataCount + size)> audioBufferSize)
 {
  return;  
 }
 if((audioPcmBufferFront + size) > audioBufferSize)
 {
  //rewind
  System.arraycopy(buf, 0, audioPCMData, audioPcmBufferFront, audioBufferSize - audioPcmBufferFront);
  audioPcmBufferDataCount += (audioBufferSize - audioPcmBufferFront);
  size -= (audioBufferSize - audioPcmBufferFront);
  audioPcmBufferFront = 0;      
 }
 System.arraycopy(buf, 0, audioPCMData, audioPcmBufferFront, size);
 audioPcmBufferFront += size;
 audioPcmBufferDataCount += size;
} 

The PCM data from audio decoder is queued to the queue buffer through queueAudioData().
After that, we write the data to AudioTrack in a stable rate.
private class playAudio extends Thread {
 @Override
 public void run() {  
  super.run();
  int len = 512;
  while(!isInterrupted()) {
   try {
    if(audioPcmBufferDataCount < len)
    {
     Thread.sleep(10);
     continue;
    }

    if((audioPcmBufferEnd + len) > audioBufferSize)
     writeSize = audioBufferSize - audioPcmBufferEnd;
    else
     writeSize = len;
    playAudioTrack.write(audioPCMData, audioPcmBufferEnd, writeSize);
    Thread.sleep(1);
    audioPcmBufferDataCount -= writeSize;
    audioPcmBufferEnd += writeSize;
    if(audioPcmBufferEnd >= audioBufferSize)
     audioPcmBufferEnd=0;
    
    if(playAudioTrack.getPlayState()!=AudioTrack.PLAYSTATE_PLAYING) {     
          playAudioTrack.play();
       }
   } catch (InterruptedException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
   }       
  }
 }
}

沒有留言:

張貼留言