title: CoreAudio: change sample rate of microphone and get data in a callback?
body: <p>This is my first attempt at using CoreAudio, but my goal is to capture microphone data, resample it to a new sample rate, and then capture the raw 16-bit PCM data.</p>
  
  <p>My strategy for this is to make an AUGraph with the microphone --> a sample rate converter, and then have a callback that gets data from the output of the converter (which I'm hoping is mic output at the new sample rate?).</p>
  
  <p>Right now my callback just fires with a null AudioBufferList*, which obviously isn't correct. How should I set this up and what am I doing wrong?</p>
  
  <p>Code follows:</p>
  
  <pre><code>  CheckError(NewAUGraph(&amp;audioGraph), @"Creating graph");
    CheckError(AUGraphOpen(audioGraph), @"Opening graph");
  
    AUNode micNode, converterNode;
    AudioUnit micUnit, converterUnit;
  
    makeMic(&amp;audioGraph, &amp;micNode, &amp;micUnit);
  
    // get the Input/inputBus's stream description
    UInt32 sizeASBD = sizeof(AudioStreamBasicDescription);
    AudioStreamBasicDescription hwASBDin;
    AudioUnitGetProperty(micUnit,
                         kAudioUnitProperty_StreamFormat,
                         kAudioUnitScope_Input,
                         kInputBus,
                         &amp;hwASBDin,
                         &amp;sizeASBD);
    makeConverter(&amp;audioGraph, &amp;converterNode, &amp;converterUnit, hwASBDin);
  
    // connect mic output to converterNode
    CheckError(AUGraphConnectNodeInput(audioGraph, micNode, 1, converterNode, 0),
               @"Connecting mic to converter");
  
    // set callback on the output? maybe?
    AURenderCallbackStruct callbackStruct;
    callbackStruct.inputProc = audioCallback;
    callbackStruct.inputProcRefCon = (__bridge void*)self;
    CheckError(AudioUnitSetProperty(micUnit,
                                  kAudioOutputUnitProperty_SetInputCallback,
                                  kAudioUnitScope_Global,
                                  kInputBus,
                                  &amp;callbackStruct,
                                  sizeof(callbackStruct)),
               @"Setting callback");
  
    CheckError(AUGraphInitialize(audioGraph), @"AUGraphInitialize");
  
    // activate audio session
    NSError *err = nil;
    AVAudioSession *audioSession = [AVAudioSession sharedInstance];
    if (![audioSession setActive:YES error:&amp;err]){
      [self error:[NSString stringWithFormat:@"Couldn't activate audio session: %@", err]];
    }
    CheckError(AUGraphStart(audioGraph), @"AUGraphStart");
  </code></pre>
  
  <p>and:</p>
  
  <pre><code>void makeMic(AUGraph *graph, AUNode *micNode, AudioUnit *micUnit) {
    AudioComponentDescription inputDesc;
    inputDesc.componentType = kAudioUnitType_Output;
    inputDesc.componentSubType = kAudioUnitSubType_VoiceProcessingIO;
    inputDesc.componentFlags = 0;
    inputDesc.componentFlagsMask = 0;
    inputDesc.componentManufacturer = kAudioUnitManufacturer_Apple;
  
    CheckError(AUGraphAddNode(*graph, &amp;inputDesc, micNode),
               @"Adding mic node");
  
    CheckError(AUGraphNodeInfo(*graph, *micNode, 0, micUnit),
               @"Getting mic unit");
  
    // enable microphone for recording
    UInt32 flagOn = 1; // enable value
    CheckError(AudioUnitSetProperty(*micUnit,
                                    kAudioOutputUnitProperty_EnableIO,
                                    kAudioUnitScope_Input,
                                    kInputBus,
                                    &amp;flagOn,
                                    sizeof(flagOn)),
               @"Enabling microphone");
  }
  </code></pre>
  
  <p>and:</p>
  
  <pre><code>void makeConverter(AUGraph *graph, AUNode *converterNode, AudioUnit *converterUnit, AudioStreamBasicDescription inFormat) {
    AudioComponentDescription sampleConverterDesc;
    sampleConverterDesc.componentType = kAudioUnitType_FormatConverter;
    sampleConverterDesc.componentSubType = kAudioUnitSubType_AUConverter;
    sampleConverterDesc.componentFlags = 0;
    sampleConverterDesc.componentFlagsMask = 0;
    sampleConverterDesc.componentManufacturer = kAudioUnitManufacturer_Apple;
  
    CheckError(AUGraphAddNode(*graph, &amp;sampleConverterDesc, converterNode),
               @"Adding converter node");
    CheckError(AUGraphNodeInfo(*graph, *converterNode, 0, converterUnit),
               @"Getting converter unit");
  
    // describe desired output format
    AudioStreamBasicDescription convertedFormat;
    convertedFormat.mSampleRate           = 16000.0;
    convertedFormat.mFormatID         = kAudioFormatLinearPCM;
    convertedFormat.mFormatFlags      = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
    convertedFormat.mFramesPerPacket  = 1;
    convertedFormat.mChannelsPerFrame = 1;
    convertedFormat.mBitsPerChannel       = 16;
    convertedFormat.mBytesPerPacket       = 2;
    convertedFormat.mBytesPerFrame        = 2;
  
    // set format descriptions
    CheckError(AudioUnitSetProperty(*converterUnit,
                                    kAudioUnitProperty_StreamFormat,
                                    kAudioUnitScope_Input,
                                    0, // should be the only bus #
                                    &amp;inFormat,
                                    sizeof(inFormat)),
               @"Setting format of converter input");
    CheckError(AudioUnitSetProperty(*converterUnit,
                                    kAudioUnitProperty_StreamFormat,
                                    kAudioUnitScope_Output,
                                    0, // should be the only bus #
                                    &amp;convertedFormat,
                                    sizeof(convertedFormat)),
               @"Setting format of converter output");
  }
  </code></pre>