title: Precise time of audio queue playback finish
body: <p>I am using Audio Queues to playback audio files. I need precise timing on the finish of last buffer.
  I need to notify a function no later than 150ms-200 ms after the last buffer is played... </p>
  
  <p>Thru callback method I know how many buffers are enqueued</p>
  
  <p>I know the buffer size, I know the how many bytes last buffer is filled with. </p>
  
  <p>First I initialize a number of buffers end fill the buffers with audio data, then enqueue them. When Audio Queue needs a buffer to be filled it calls the callback and I fill the buffer with data. </p>
  
  <p>When there is no more audio data available Audio Queue sends me the last empty buffer, so I fill it with whatever data I have: </p>
  
  <pre><code>            if (sharedCache.numberOfToTalPackets&gt;0)
              {
                  if (currentlyReadingBufferIndex==[sharedCache.baseAudioCache count]-1) {
                      inBuffer-&gt;mAudioDataByteSize = (UInt32)bytesFilled;
                      lastEnqueudBufferSize=bytesFilled;
                      err=AudioQueueEnqueueBuffer(inAQ,inBuffer,(UInt32)packetsFilled,packetDescs);
                      if (err) {
                          [self failWithErrorCode:err customError:AP_AUDIO_QUEUE_ENQUEUE_FAILED];
                      }
                      printf("if that was the last free packet description, then enqueue the buffer\n");
                      //go to the next item on keepbuffer array
                      isBufferFilled=YES;
                      [self incrementBufferUsedCount];
                      return;
                  }
              }
  </code></pre>
  
  <p>When Audio Queue asks for more data via callback and I have no more data , I start to countdown the buffers. If buffer count equals to zero, which means only one buffer left on the flight to be played, the moment playback is done I try to stop the audio queue. </p>
  
  <pre><code>-(void)decrementBufferUsedCount
  {
  
      if (buffersUsed&gt;0) {
          buffersUsed--;
          printf("buffer on the queue %i\n",buffersUsed);
          if (buffersUsed==0) {
              NSLog(@"playback is finished\n");
              // end playback
              isPlayBackDone=YES;
              double sampleRate = dataFormat.mSampleRate;
              double bufferDuration = lastEnqueudBufferSize/ sampleRate;
              double estimatedTimeNeded=bufferDuration*1;
              [self performSelector:@selector(stopPlayer) withObject:nil afterDelay:estimatedTimeNeded];
          }
      }
  }  
  
  -(void)stopPlayer
  {
      @synchronized(self)
      {
          state=AP_STOPPING;
      }
      err=AudioQueueStop(queue, TRUE);
      if (err) {
          [self failWithErrorCode:err customError:AP_AUDIO_QUEUE_STOP_FAILED];
      }
      else
      {
          @synchronized(self)
          {
              state=AP_STOPPED;
              NSLog(@"Stopped\n");
          }
  </code></pre>
  
  <p>However it seems I can't get precise timing here. Above code stops player early. </p>
  
  <p>if I do following audio cuts early too</p>
  
  <pre><code>double bufferDuration = XMAQDefaultBufSize/ sampleRate;
  double estimatedTimeNeded=bufferDuration*1;
  </code></pre>
  
  <p>if increase <code>1</code> to <code>2</code> since the buffer size is big I get some delay, seem 1.5 is the optimum value for now but I dont understand why <code>lastEnqueudBufferSize/ sampleRate</code> is not wotking</p>
  
  <p>Details of the audio file, and buffers: </p>
  
  <pre><code>Audio file has 22050 sample rate
  #define kNumberPlaybackBuffers  4
  #define kAQDefaultBufSize 16384
  it is a vbr file format with no bitrate information available
  </code></pre>