title: Android AudioTrack buffering problems
body: <p>Ok so I have a frequency generator which uses AudioTrack to send PCM data to the hardware.  Here's the code I'm using for that:</p>
  
  <pre><code>private class playSoundTask extends AsyncTask&lt;Void, Void, Void&gt; {
    float frequency;
    float increment;
    float angle = 0;
    short samples[] = new short[1024];
  
    @Override
    protected void onPreExecute() {
     int minSize = AudioTrack.getMinBufferSize( 44100, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT );        
     track = new AudioTrack( AudioManager.STREAM_MUSIC, 44100, 
       AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, 
       minSize, AudioTrack.MODE_STREAM);
     track.play();
    }
  
    @Override
    protected Void doInBackground(Void... params) {
     while( Main.this.isPlaying)
     {
      for( int i = 0; i &lt; samples.length; i++ )
      {
       frequency = (float)Main.this.slider.getProgress();
       increment = (float)(2*Math.PI) * frequency / 44100;
       samples[i] = (short)((float)Math.sin( angle )*Short.MAX_VALUE);
       angle += increment;
      }
  
      track.write(samples, 0, samples.length);
     }
     return null;
    }
   }
  </code></pre>
  
  <p>The frequency is tied to a slide bar, and the correct value is being reported in the sample generation loop.  Everything is fine and dandy when I start the app.  When you drag your finger along the slide bar you get a nice sweeping sound.  But after around 10 seconds of playing around with it, the audio starts to get jumpy.  Instead of a smooth sweep, it's staggered, and only changes tone around every 1000 Hz or so.  Any ideas on what could be causing this?</p>
  
  <p>Here's all the code in case the problem lies somewhere else:</p>
  
  <pre><code>    public class Main extends Activity implements OnClickListener, OnSeekBarChangeListener {
   AudioTrack track;
   SeekBar slider;
   ImageButton playButton;
   TextView display; 
  
   boolean isPlaying=false;
  
   /** Called when the activity is first created. */
   @Override
   public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
  
    display = (TextView) findViewById(R.id.display);
    display.setText("5000 Hz");
  
    slider = (SeekBar) findViewById(R.id.slider);
    slider.setMax(20000);
    slider.setProgress(5000);
    slider.setOnSeekBarChangeListener(this);
  
  
    playButton = (ImageButton) findViewById(R.id.play);
    playButton.setOnClickListener(this);
  
   }
  
   private class playSoundTask extends AsyncTask&lt;Void, Void, Void&gt; {
    float frequency;
    float increment;
    float angle = 0;
    short samples[] = new short[1024];
  
    @Override
    protected void onPreExecute() {
     int minSize = AudioTrack.getMinBufferSize( 44100, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT );        
     track = new AudioTrack( AudioManager.STREAM_MUSIC, 44100, 
       AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, 
       minSize, AudioTrack.MODE_STREAM);
     track.play();
    }
  
    @Override
    protected Void doInBackground(Void... params) {
     while( Main.this.isPlaying)
     {
      for( int i = 0; i &lt; samples.length; i++ )
      {
       frequency = (float)Main.this.slider.getProgress();
       increment = (float)(2*Math.PI) * frequency / 44100;
       samples[i] = (short)((float)Math.sin( angle )*Short.MAX_VALUE);
       angle += increment;
      }
  
      track.write(samples, 0, samples.length);
     }
     return null;
    }
   }
  
  
  
   @Override
   public void onProgressChanged(SeekBar seekBar, int progress,
     boolean fromUser) {
    display.setText(""+progress+" Hz");
   }
  
   public void onClick(View v) {
    if (isPlaying) {
     stop();
    } else {
     start();
    }
   }
  
   public void stop() {
    isPlaying=false;
    playButton.setImageResource(R.drawable.play);
   }
  
   public void start() {
    isPlaying=true;
    playButton.setImageResource(R.drawable.stop);
    new playSoundTask().execute();
   }
  
   @Override
   protected void onResume() {
    super.onResume();
  
   }
  
   @Override
   protected void onStop() {
    super.onStop();
    //Store state
    stop();
  
   }
  
  
   @Override
   public void onStartTrackingTouch(SeekBar seekBar) {
    // TODO Auto-generated method stub
  
   }
  
  
   @Override
   public void onStopTrackingTouch(SeekBar seekBar) {
    // TODO Auto-generated method stub
  
   }
  }
  </code></pre>