title: Objective-C - Passing Streamed Data to Audio Queue
body: <p>I am currently developing an app on iOS that reads IMA-ADPCM audio data in over through a TCP socket and converts it to PCM and then plays the stream. At this stage, I have completed the class that pulls (or should I say reacts to pushes) in the data from the stream and decoded it to PCM. I have also setup the Audio Queue class and have it playing a test tone. Where I need assistance is the best way to pass the data into the Audio Queue.</p>
  
  <p>The audio data comes out of the ADPCM decoder as 8 Khz 16bit LPCM at 640 bytes a chunk. (it originates as 160 bytes of ADPCM data but decompresses to 640). It comes into the function as uint_8t array and passes out an NSData object. The stream is a 'push' stream, so everytime the audio is sent it will create/flush the object.</p>
  
  <pre><code>-(NSData*)convertADPCM:(uint8_t[]) adpcmdata {
  </code></pre>
  
  <p>The Audio Queue callback of course is a pull function that goes looking for data on each pass of the run loop, on each pass it runs:</p>
  
  <pre><code>-(OSStatus) fillBuffer: (AudioQueueBufferRef) buffer {
  </code></pre>
  
  <p>I've been working on this for a few days and the PCM conversion was quite taxing and I am having a little bit of trouble assembling in my head the best way to bridge the data between the two. It's not like I am creating the data, then I could simply incorporate data creation into the fillbuffer routine, rather the data is being pushed.</p>
  
  <p>I did setup a circular buffer, of 0.5 seconds in a uint16_t[] ~ but I think I have worn my brain out and couldn't work out a neat way to push and pull from the buffer, so I ended up with snap crackle pop.</p>
  
  <p>I have completed the project mostly on Android, but found AudioTrack a very different beast to Core-Audio Queues.</p>
  
  <p>At this stage I will also say I picked up a copy of Learning Core Audio by Adamson and Avila and found this an excellent resource for anyone looking to demystify core audio.</p>
  
  <p><strong>UPDATE:</strong>
  Here is the buffer management code:</p>
  
  <pre><code>-(OSStatus) fillBuffer: (AudioQueueBufferRef) buffer {
  
      int frame = 0;
      double frameCount = bufferSize / self.streamFormat.mBytesPerFrame; 
      // buffersize = framecount = 8000 / 2 = 4000
      //    
  
      // incoming buffer uint16_t[] convAudio holds 64400 bytes (big I know - 100 x 644 bytes)
      // playedHead is set by the function to say where in the buffer the
      // next starting point should be
  
      if (playHead &gt; 99) {
          playHead = 0;
      }
  
      // Playstep factors playhead to get starting position   
      int playStep = playHead * 644;
  
      // filling the buffer
      for (frame = 0; frame &lt; frameCount; ++frame) 
          // framecount = 4000
         {
          // pointer to buffer
          SInt16 *data = (SInt16*)buffer-&gt;mAudioData;
          // load data from uint16_t[] convAudio array into frame
          (data)[frame] = convAudio[(frame + playStep)];
      }
  
      // set buffersize
      buffer-&gt;mAudioDataByteSize = bufferSize;
  
      // return no Error - Osstatus will return an error otherwise if there is one. (I think)
      return noErr;
  }
  </code></pre>
  
  <p>As I said, my brain was fuzzy when I wrote this, and there's probably something glaringly obvious I am missing.</p>
  
  <p>Above code is called by the callback:</p>
  
  <pre><code>static void MyAQOutputCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inCompleteAQBuffer) 
  {
      soundHandler *sHandler = (__bridge soundHandler*)inUserData;
  
      CheckError([sHandler fillBuffer: inCompleteAQBuffer],
                 "can't refill buffer",
                 "buffer refilled");
      CheckError(AudioQueueEnqueueBuffer(inAQ,
                                         inCompleteAQBuffer,
                                         0,
                                         NULL),
                 "Couldn't enqueue buffer (refill)",
                 "buffer enqued (refill)");
  
  }
  </code></pre>
  
  <p>On the convAudio array side of things I have dumped the it to log and it is getting filled and refilled in a circular fashion, so I know at least that bit is working.</p>