title: Setting up audio queue for ffmpeg rtsp stream playing
body: <p>I'm working on an rtsp streaming(AAC format) client for iOS using ffmpeg. Right now I can only say my app is workable, but the streaming sound is very noisy and even a little distorted, far worse than when it's played by vlc or mplayer. </p>
  
  <p>The stream is read by av_read_frame(), decoded by avcodec_decode_audio3(). Then I just send the decoded raw audio to Audio Queue.</p>
  
  <p>When decoding a local aac file with my app, the sound seemed not so noisy at all. I know initial encoding would dramatically affect the result. However at least I should try to have it sounded like other streaming clients... </p>
  
  <p>Many parts in my implementation/modification actually came from try and error. I believe I'm doing something wrong in setting up Audio Queue, and the callback function for filling Audio Buffer.  </p>
  
  <p>Any hints, suggestions or help are greatly appreciated.  </p>
  
  <p>// --info of test materials dumped by av_dump_format() --</p>
  
  <pre><code>Metadata:
      title           : /demo/test.3gp
    Duration: 00:00:30.11, start: 0.000000, bitrate: N/A
      Stream #0:0: Audio: aac, 32000 Hz, stereo, s16
  aac  Advanced Audio Coding 
  </code></pre>
  
  <p>// -- the Audio Queue setup procedure --</p>
  
  <pre><code>- (void) startPlayback
  {
      OSStatus err = 0;
      if(playState.playing) return;
  
      playState.started = false;
  
      if(!playState.queue) 
      {
  
          UInt32 bufferSize;
  
  
          playState.format.mSampleRate = _av-&gt;audio.sample_rate;
          playState.format.mFormatID = kAudioFormatLinearPCM;
          playState.format.mFormatFlags = kAudioFormatFlagsCanonical;
          playState.format.mChannelsPerFrame = _av-&gt;audio.channels_per_frame;
          playState.format.mBytesPerPacket = sizeof(AudioSampleType) *_av-&gt;audio.channels_per_frame;
          playState.format.mBytesPerFrame = sizeof(AudioSampleType) *_av-&gt;audio.channels_per_frame;
          playState.format.mBitsPerChannel = 8 * sizeof(AudioSampleType);
  
          playState.format.mFramesPerPacket = 1;        
          playState.format.mReserved = 0;
  
  
          pauseStart = 0;
          DeriveBufferSize(playState.format,playState.format.mBytesPerPacket,BUFFER_DURATION,&amp;bufferSize,&amp;numPacketsToRead);
          err= AudioQueueNewOutput(&amp;playState.format, aqCallback, &amp;playState, NULL, kCFRunLoopCommonModes, 0, &amp;playState.queue);
  
          if(err != 0)
          {
              printf("AQHandler.m startPlayback: Error creating new AudioQueue: %d \n", (int)err);
          }
  
          for(int i = 0 ; i &lt; NUM_BUFFERS ; i ++)
          {
              err = AudioQueueAllocateBufferWithPacketDescriptions(playState.queue, bufferSize, numPacketsToRead , &amp;playState.buffers[i]);
  
              if(err != 0)
                  printf("AQHandler.m startPlayback: Error allocating buffer %d", i);
              fillAudioBuffer(&amp;playState,playState.queue, playState.buffers[i]);
          }
  
      }
  
      startTime = mu_currentTimeInMicros();
  
      err=AudioQueueStart(playState.queue, NULL);
  
      if(err)
      {
  
          char sErr[4];
          printf("AQHandler.m startPlayback: Could not start queue %ld %s.", err, FormatError(sErr,err));
  
          playState.playing = NO;
      } 
      else
      {
          AudioSessionSetActive(true);
          playState.playing = YES;
      }           
  }
  </code></pre>
  
  <p>// -- callback for filling audio buffer --</p>
  
  <pre><code>static int ct = 0;
  static void fillAudioBuffer(void *info,AudioQueueRef queue, AudioQueueBufferRef buffer)
  {
  
      int lengthCopied = INT32_MAX;
      int dts= 0;
      int isDone = 0;
  
      buffer-&gt;mAudioDataByteSize = 0;
      buffer-&gt;mPacketDescriptionCount = 0;
  
      OSStatus err = 0;
      AudioTimeStamp bufferStartTime;
  
      AudioQueueGetCurrentTime(queue, NULL, &amp;bufferStartTime, NULL);
  
  
      PlayState *ps = (PlayState *)info;
  
      if (!ps-&gt;started)
          ps-&gt;started = true;
  
      while(buffer-&gt;mPacketDescriptionCount &lt; numPacketsToRead &amp;&amp; lengthCopied &gt; 0)
      {
          lengthCopied = getNextAudio(_av,
                          buffer-&gt;mAudioDataBytesCapacity-buffer-&gt;mAudioDataByteSize,
                          (uint8_t*)buffer-&gt;mAudioData+buffer-&gt;mAudioDataByteSize,
                          &amp;dts,&amp;isDone);
  
          ct+= lengthCopied;
  
          if(lengthCopied &lt; 0 || isDone) 
          {
              printf("nothing to read....\n\n");
              PlayState *ps = (PlayState *)info;
              ps-&gt;finished = true;
              ps-&gt;started = false;
              break;
          }
  
          if(aqStartDts &lt; 0) aqStartDts = dts;
  
          if(buffer-&gt;mPacketDescriptionCount ==0)
          {
              bufferStartTime.mFlags = kAudioTimeStampSampleTimeValid;
              bufferStartTime.mSampleTime = (Float64)(dts-aqStartDts);//* _av-&gt;audio.frame_size;
  
              if (bufferStartTime.mSampleTime &lt;0 ) 
                  bufferStartTime.mSampleTime = 0;
  
              printf("AQHandler.m fillAudioBuffer: DTS for %x: %lf time base: %lf StartDTS: %d\n", 
                      (unsigned int)buffer, 
                      bufferStartTime.mSampleTime, 
                      _av-&gt;audio.time_base, 
                      aqStartDts);
  
          }
  
          buffer-&gt;mPacketDescriptions[buffer-&gt;mPacketDescriptionCount].mStartOffset = buffer-&gt;mAudioDataByteSize;
          buffer-&gt;mPacketDescriptions[buffer-&gt;mPacketDescriptionCount].mDataByteSize = lengthCopied;
  
  
  
          buffer-&gt;mPacketDescriptions[buffer-&gt;mPacketDescriptionCount].mVariableFramesInPacket = 0;
  
          buffer-&gt;mPacketDescriptionCount++;
  
          buffer-&gt;mAudioDataByteSize += lengthCopied;
      }
  
      int audioBufferCount, audioBufferTotal,  videoBufferCount, videoBufferTotal;
      bufferCheck(_av,&amp;videoBufferCount, &amp;videoBufferTotal, &amp;audioBufferCount, &amp;audioBufferTotal);
  
      if(buffer-&gt;mAudioDataByteSize)
      {
  
          err = AudioQueueEnqueueBufferWithParameters(queue, buffer, 0, NULL, 0, 0, 0, NULL, &amp;bufferStartTime, NULL);
  
          if(err)
          {
              char sErr[10];
              printf("AQHandler.m fillAudioBuffer: Could not enqueue buffer 0x%x: %d %s.", buffer, err, FormatError(sErr, err));
  
          }
  
      }
  
  }
  
  
  
  
  int getNextAudio(video_data_t* vInst, int maxlength, uint8_t* buf, int* pts, int* isDone) 
  {
  
      struct video_context_t  *ctx = vInst-&gt;context;
      int    datalength            = 0;
  
      while(ctx-&gt;audio_ring.lock || (ctx-&gt;audio_ring.count &lt;= 0 &amp;&amp; ((ctx-&gt;play_state &amp; STATE_DIE) != STATE_DIE)))
      {
  
          if (ctx-&gt;play_state &amp; STATE_EOF) return -1;        
          usleep(100);
      }
  
      *pts = 0;
      ctx-&gt;audio_ring.lock = kLocked;
  
      if(ctx-&gt;audio_ring.count&gt;0 &amp;&amp; maxlength &gt; ctx-&gt;audio_buffer[ctx-&gt;audio_ring.read].size)
      {    
          memcpy(buf, ctx-&gt;audio_buffer[ctx-&gt;audio_ring.read].data,ctx-&gt;audio_buffer[ctx-&gt;audio_ring.read].size);
  
          *pts = ctx-&gt;audio_buffer[ctx-&gt;audio_ring.read].pts;
  
          datalength = ctx-&gt;audio_buffer[ctx-&gt;audio_ring.read].size;
  
          ctx-&gt;audio_ring.read++;        
          ctx-&gt;audio_ring.read %= ABUF_SIZE;        
          ctx-&gt;audio_ring.count--;
  
      }
      ctx-&gt;audio_ring.lock = kUnlocked;
  
      if((ctx-&gt;play_state &amp; STATE_EOF) == STATE_EOF &amp;&amp; ctx-&gt;audio_ring.count == 0) *isDone = 1;
  
      return datalength;
  }
  </code></pre>