title: AudioConverterRef sample rate conversion (iOS)
body: <p>I write a voip app that uses "novocaine" library for recording and playback of sound. I set sample rate as 8kHz. This sample rate is set in novocaine  in AudioStreamBasicDescription of audio unit and as audio session property kAudioSessionProperty_PreferredHardwareSampleRate. I understand that setting preferred hardware sample rate has no guarantee that actual hardware sample rate will be changed but it worked for all devices except iPhone6s and iPhone6s+ (when route is changed to speaker). With iPhone6s(+) and speaker route I receive 48kHz sound from microphone. So I need to somehow convert this 48 kHz sound to 8kHz. In documentation I found that AudioConverterRef can be used in this case but I have troubles with using it.</p>
  
  <p>I use AudioConverterFillComplexBuffer for sample rate conversion but it always returns -50 OSStatus (one or more parameters passed to the function were not valid). This is how I use audio converter:</p>
  
  <pre><code>// Setup AudioStreamBasicDescription for input
  inputFormat.mSampleRate = 48000.0;
  inputFormat.mFormatID = kAudioFormatLinearPCM;
  inputFormat.mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked;
  inputFormat.mChannelsPerFrame = 1;
  inputFormat.mBitsPerChannel = 8 * sizeof(float);
  inputFormat.mFramesPerPacket = 1;
  inputFormat.mBytesPerFrame = sizeof(float) * inputFormat.mChannelsPerFrame;
  inputFormat.mBytesPerPacket = inputFormat.mBytesPerFrame * inputFormat.mFramesPerPacket;
  
  // Setup AudioStreamBasicDescription for output
  outputFormat.mSampleRate = 8000.0;
  outputFormat.mFormatID = kAudioFormatLinearPCM;
  outputFormat.mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked;
  outputFormat.mChannelsPerFrame = 1;
  outputFormat.mBitsPerChannel = 8 * sizeof(float);
  outputFormat.mFramesPerPacket = 1;
  outputFormat.mBytesPerFrame = sizeof(float) * outputFormat.mChannelsPerFrame;
  outputFormat.mBytesPerPacket = outputFormat.mBytesPerFrame * outputFormat.mFramesPerPacket;
  
  
  // Create new instance of audio converter
  AudioConverterNew(&amp;inputFormat, &amp;outputFormat, &amp;converter);
  
  // Set conversion quality
  UInt32 tmp = kAudioConverterQuality_Medium;
  AudioConverterSetProperty( converter, kAudioConverterCodecQuality,
                            sizeof( tmp ), &amp;tmp );
  AudioConverterSetProperty( converter, kAudioConverterSampleRateConverterQuality, sizeof( tmp ), &amp;tmp );
  
  // Get the size of the IO buffer(s)
  UInt32 bufferSizeFrames = 0;
  size = sizeof(UInt32);
  AudioUnitGetProperty(self.inputUnit,
                                   kAudioDevicePropertyBufferFrameSize,
                                   kAudioUnitScope_Global,
                                   0,
                                   &amp;bufferSizeFrames,
                                   &amp;size);
  UInt32 bufferSizeBytes = bufferSizeFrames * sizeof(Float32);
  
  // Allocate an AudioBufferList plus enough space for array of AudioBuffers
  UInt32 propsize = offsetof(AudioBufferList, mBuffers[0]) + (sizeof(AudioBuffer) * outputFormat.mChannelsPerFrame);
  
  // Malloc buffer lists
  convertedInputBuffer = (AudioBufferList *)malloc(propsize);
  convertedInputBuffer-&gt;mNumberBuffers = 1;
  
  // Pre-malloc buffers for AudioBufferLists
  convertedInputBuffer-&gt;mBuffers[0].mNumberChannels = outputFormat.mChannelsPerFrame;
  convertedInputBuffer-&gt;mBuffers[0].mDataByteSize = bufferSizeBytes;
  convertedInputBuffer-&gt;mBuffers[0].mData = malloc(bufferSizeBytes);
  memset(convertedInputBuffer-&gt;mBuffers[0].mData, 0, bufferSizeBytes);
  
  // Setup callback for converter
  static OSStatus inputProcPtr(AudioConverterRef               inAudioConverter,
                                   UInt32*                         ioNumberDataPackets,
                                   AudioBufferList*                ioData,
                                   AudioStreamPacketDescription* __nullable* __nullable  outDataPacketDescription,
                                   void* __nullable                inUserData)
  {
      // Read data from buffer
  }
  
  // Perform actual sample rate conversion
  AudioConverterFillComplexBuffer(converter, inputProcPtr, NULL, &amp;numberOfFrames, convertedInputBuffer,  NULL)
  </code></pre>
  
  <p>inputProcPtr callback is never called. I tried to set different number of frames but still receive OSStatus -50.</p>
  
  <p>1) Is using AudioConverterRef is correct way to make sample rate conversion or it could be done in different way?</p>
  
  <p>2) What is wrong with my conversion implementation?</p>
  
  <p>Thank you all in advance</p>