title: OS X / iOS - Sample rate conversion for a buffer using AudioConverterFillComplexBuffer
body: <p>I'm writing a CoreAudio backend for an <a href="http://libxal.googlecode.com/" rel="noreferrer">audio library called XAL</a>. Input buffers can be of various sample rates. I'm using a single audio unit for output. Idea is to convert the buffers and mix them prior to sending them to the audio unit.</p>
  
  <p>Everything works as long as the input buffer has the same properties (sample rate, channel count, etc) as the output audio unit. Hence, the mixing part works.</p>
  
  <p>However, I'm stuck with sample rate and channel count conversion. From what I figured out, this is easiest to do with Audio Converter Services API. I've managed to construct a converter; the idea is that the output format is the same as the output unit format, but possibly adjusted for purposes of the converter.</p>
  
  <p>Audio converter is successfully constructed, but upon calling <code>AudioConverterFillComplexBuffer()</code>, I get output status error -50.</p>
  
  <p>I'd love if I could get another set of eyeballs on this code. Problem is probably somewhere below <code>AudioConverterNew()</code>. Variable <code>stream</code> contains incoming (and outgoing) buffer data, and <code>streamSize</code> contains byte-size of incoming (and outgoing) buffer data.</p>
  
  <p>What did I do wrong?</p>
  
  <pre><code>void CoreAudio_AudioManager::_convertStream(Buffer* buffer, unsigned char** stream, int *streamSize)
  {
      if (buffer-&gt;getBitsPerSample() != unitDescription.mBitsPerChannel || 
          buffer-&gt;getChannels() != unitDescription.mChannelsPerFrame || 
          buffer-&gt;getSamplingRate() != unitDescription.mSampleRate)
      {
          printf("INPUT STREAM SIZE: %d\n", *streamSize);
          // describe the input format's description
          AudioStreamBasicDescription inputDescription;
          memset(&amp;inputDescription, 0, sizeof(inputDescription));
          inputDescription.mFormatID = kAudioFormatLinearPCM;
          inputDescription.mFormatFlags = kLinearPCMFormatFlagIsPacked | kLinearPCMFormatFlagIsSignedInteger;
          inputDescription.mChannelsPerFrame = buffer-&gt;getChannels();
          inputDescription.mSampleRate = buffer-&gt;getSamplingRate();
          inputDescription.mBitsPerChannel = buffer-&gt;getBitsPerSample();
          inputDescription.mBytesPerFrame = (inputDescription.mBitsPerChannel * inputDescription.mChannelsPerFrame) / 8;
          inputDescription.mFramesPerPacket = 1; //*streamSize / inputDescription.mBytesPerFrame;
          inputDescription.mBytesPerPacket = inputDescription.mBytesPerFrame * inputDescription.mFramesPerPacket;
          printf("INPUT : %lu bytes per packet for sample rate %g, channels %d\n", inputDescription.mBytesPerPacket, inputDescription.mSampleRate, inputDescription.mChannelsPerFrame);
  
          // copy conversion output format's description from the
          // output audio unit's description.
          // then adjust framesPerPacket to match the input we'll be passing.
  
          // framecount of our input stream is based on the input bytecount.
          // output stream will have same number of frames, but different
          // number of bytes.
          AudioStreamBasicDescription outputDescription = unitDescription;
          outputDescription.mFramesPerPacket = 1; //inputDescription.mFramesPerPacket;
          outputDescription.mBytesPerPacket = outputDescription.mBytesPerFrame * outputDescription.mFramesPerPacket;
          printf("OUTPUT : %lu bytes per packet for sample rate %g, channels %d\n", outputDescription.mBytesPerPacket, outputDescription.mSampleRate, outputDescription.mChannelsPerFrame);
  
          // create an audio converter
          AudioConverterRef audioConverter;
          OSStatus acCreationResult = AudioConverterNew(&amp;inputDescription, &amp;outputDescription, &amp;audioConverter);
          printf("Created audio converter %p (status: %d)\n", audioConverter, acCreationResult);
          if(!audioConverter)
          {
              // bail out
              free(*stream);
              *streamSize = 0;
              *stream = (unsigned char*)malloc(0);
              return;
          }
  
          // calculate number of bytes required for output of input stream.
          // allocate buffer of adequate size.
          UInt32 outputBytes = outputDescription.mBytesPerPacket * (*streamSize / inputDescription.mBytesPerFrame); // outputDescription.mFramesPerPacket * outputDescription.mBytesPerFrame;
          unsigned char *outputBuffer = (unsigned char*)malloc(outputBytes);
          memset(outputBuffer, 0, outputBytes);
          printf("OUTPUT BYTES : %d\n", outputBytes);
  
          // describe input data we'll pass into converter
          AudioBuffer inputBuffer;
          inputBuffer.mNumberChannels = inputDescription.mChannelsPerFrame;
          inputBuffer.mDataByteSize = *streamSize;
          inputBuffer.mData = *stream;
  
          // describe output data buffers into which we can receive data.
          AudioBufferList outputBufferList;
          outputBufferList.mNumberBuffers = 1;
          outputBufferList.mBuffers[0].mNumberChannels = outputDescription.mChannelsPerFrame;
          outputBufferList.mBuffers[0].mDataByteSize = outputBytes;
          outputBufferList.mBuffers[0].mData = outputBuffer;
  
          // set output data packet size
          UInt32 outputDataPacketSize = outputDescription.mBytesPerPacket;
  
          // convert
          OSStatus result = AudioConverterFillComplexBuffer(audioConverter, /* AudioConverterRef inAudioConverter */
                                                            CoreAudio_AudioManager::_converterComplexInputDataProc, /* AudioConverterComplexInputDataProc inInputDataProc */
                                                            &amp;inputBuffer, /* void *inInputDataProcUserData */
                                                            &amp;outputDataPacketSize, /* UInt32 *ioOutputDataPacketSize */
                                                            &amp;outputBufferList, /* AudioBufferList *outOutputData */
                                                            NULL /* AudioStreamPacketDescription *outPacketDescription */
                                                            );
          printf("Result: %d wheee\n", result);
  
          // change "stream" to describe our output buffer.
          // even if error occured, we'd rather have silence than unconverted audio.
          free(*stream);
          *stream = outputBuffer;
          *streamSize = outputBytes;
  
          // dispose of the audio converter
          AudioConverterDispose(audioConverter);
      }
  }
  
  
  OSStatus CoreAudio_AudioManager::_converterComplexInputDataProc(AudioConverterRef inAudioConverter,
                                                                  UInt32* ioNumberDataPackets,
                                                                  AudioBufferList* ioData,
                                                                  AudioStreamPacketDescription** ioDataPacketDescription,
                                                                  void* inUserData)
  {
      printf("Converter\n");
      if(*ioNumberDataPackets != 1)
      {
          xal::log("_converterComplexInputDataProc cannot provide input data; invalid number of packets requested");
          *ioNumberDataPackets = 0;
          ioData-&gt;mNumberBuffers = 0;
          return -50;
      }
  
      *ioNumberDataPackets = 1;
      ioData-&gt;mNumberBuffers = 1;
      ioData-&gt;mBuffers[0] = *(AudioBuffer*)inUserData;
  
      *ioDataPacketDescription = NULL;
  
      return 0;
  }
  </code></pre>