Note that there are some explanatory texts on larger screens.

plurals
  1. POHow to record sound produced by mixer unit output (iOS Core Audio & Audio Graph)
    text
    copied!<p>I'm trying to record sound produced by a mixer unit output.</p> <p>For the moment, my code is based on the <a href="http://developer.apple.com/library/ios/#samplecode/MixerHost/Introduction/Intro.html">apple MixerHost iOS app</a> demo : A <strong>mixer node</strong> is connected to a <strong>remote IO node</strong> on the audio graphe.</p> <p>And i try to set an <em>input callback</em> on the <strong>remote IO node</strong> input on the mixer output.</p> <p>I do something wrong but I can not find the error.</p> <p>Here is the code below. This is done just after the Multichannel Mixer unit Setup :</p> <pre><code>UInt32 flag = 1; // Enable IO for playback result = AudioUnitSetProperty(iOUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, // Output bus &amp;flag, sizeof(flag)); if (noErr != result) {[self printErrorMessage: @"AudioUnitSetProperty EnableIO" withStatus: result]; return;} /* can't do that because *** AudioUnitSetProperty EnableIO error: -1073752493 00000000 result = AudioUnitSetProperty(iOUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 0, // Output bus &amp;flag, sizeof(flag)); if (noErr != result) {[self printErrorMessage: @"AudioUnitSetProperty EnableIO" withStatus: result]; return;} */ </code></pre> <p>Then create a stream format :</p> <pre><code>// I/O stream format iOStreamFormat.mSampleRate = 44100.0; iOStreamFormat.mFormatID = kAudioFormatLinearPCM; iOStreamFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked; iOStreamFormat.mFramesPerPacket = 1; iOStreamFormat.mChannelsPerFrame = 1; iOStreamFormat.mBitsPerChannel = 16; iOStreamFormat.mBytesPerPacket = 2; iOStreamFormat.mBytesPerFrame = 2; [self printASBD: iOStreamFormat]; </code></pre> <p>Then affect the format and specify sample rate :</p> <pre><code>result = AudioUnitSetProperty(iOUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, // Input bus &amp;iOStreamFormat, sizeof(iOStreamFormat)); if (noErr != result) {[self printErrorMessage: @"AudioUnitSetProperty StreamFormat" withStatus: result]; return;} result = AudioUnitSetProperty(iOUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, // Output bus &amp;iOStreamFormat, sizeof(iOStreamFormat)); if (noErr != result) {[self printErrorMessage: @"AudioUnitSetProperty StreamFormat" withStatus: result]; return;} // SampleRate I/O result = AudioUnitSetProperty (iOUnit, kAudioUnitProperty_SampleRate, kAudioUnitScope_Input, 0, // Output &amp;graphSampleRate, sizeof (graphSampleRate)); if (noErr != result) {[self printErrorMessage: @"AudioUnitSetProperty (set I/O unit input stream format)" withStatus: result]; return;} </code></pre> <p>Then, i try to set the render callback.</p> <p><strong>Solution 1 >>> my recording callback is never called</strong></p> <pre><code>effectState.rioUnit = iOUnit; AURenderCallbackStruct renderCallbackStruct; renderCallbackStruct.inputProc = &amp;recordingCallback; renderCallbackStruct.inputProcRefCon = &amp;effectState; result = AudioUnitSetProperty (iOUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, // Output bus &amp;renderCallbackStruct, sizeof (renderCallbackStruct)); if (noErr != result) {[self printErrorMessage: @"AudioUnitSetProperty SetRenderCallback" withStatus: result]; return;} </code></pre> <p><strong>Solution 2 >>> my app crashes at launch on this</strong></p> <pre><code>AURenderCallbackStruct renderCallbackStruct; renderCallbackStruct.inputProc = &amp;recordingCallback; renderCallbackStruct.inputProcRefCon = &amp;effectState; result = AUGraphSetNodeInputCallback (processingGraph, iONode, 0, // Output bus &amp;renderCallbackStruct); if (noErr != result) {[self printErrorMessage: @"AUGraphSetNodeInputCallback (I/O unit input callback bus 0)" withStatus: result]; return;} </code></pre> <p>If anyone have an idea ...</p> <p><strong>EDIT Solution 3 (thanks to arlo anwser) >> There is now a format problem</strong></p> <pre><code>AudioStreamBasicDescription dstFormat = {0}; dstFormat.mSampleRate=44100.0; dstFormat.mFormatID=kAudioFormatLinearPCM; dstFormat.mFormatFlags=kAudioFormatFlagsNativeEndian|kAudioFormatFlagIsSignedInteger|kAudioFormatFlagIsPacked; dstFormat.mBytesPerPacket=4; dstFormat.mBytesPerFrame=4; dstFormat.mFramesPerPacket=1; dstFormat.mChannelsPerFrame=2; dstFormat.mBitsPerChannel=16; dstFormat.mReserved=0; result = AudioUnitSetProperty(iOUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &amp;stereoStreamFormat, sizeof(stereoStreamFormat)); if (noErr != result) {[self printErrorMessage: @"AudioUnitSetProperty" withStatus: result]; return;} result = AudioUnitSetProperty(iOUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &amp;stereoStreamFormat, sizeof(stereoStreamFormat)); if (noErr != result) {[self printErrorMessage: @"AudioUnitSetProperty" withStatus: result]; return;} AudioUnitAddRenderNotify( iOUnit, &amp;recordingCallback, &amp;effectState ); </code></pre> <p>and the file setup :</p> <pre><code>if (noErr != result) {[self printErrorMessage: @"AUGraphInitialize" withStatus: result]; return;} // On initialise le fichier audio NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentsDirectory = [paths objectAtIndex:0]; NSString *destinationFilePath = [[[NSString alloc] initWithFormat: @"%@/output.caf", documentsDirectory] autorelease]; NSLog(@"&gt;&gt;&gt; %@", destinationFilePath); CFURLRef destinationURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, (CFStringRef)destinationFilePath, kCFURLPOSIXPathStyle, false); OSStatus setupErr = ExtAudioFileCreateWithURL(destinationURL, kAudioFileWAVEType, &amp;dstFormat, NULL, kAudioFileFlags_EraseFile, &amp;effectState.audioFileRef); CFRelease(destinationURL); NSAssert(setupErr == noErr, @"Couldn't create file for writing"); setupErr = ExtAudioFileSetProperty(effectState.audioFileRef, kExtAudioFileProperty_ClientDataFormat, sizeof(AudioStreamBasicDescription), &amp;stereoStreamFormat); NSAssert(setupErr == noErr, @"Couldn't create file for format"); setupErr = ExtAudioFileWriteAsync(effectState.audioFileRef, 0, NULL); NSAssert(setupErr == noErr, @"Couldn't initialize write buffers for audio file"); </code></pre> <p>And the recording callback :</p> <pre><code>static OSStatus recordingCallback (void * inRefCon, AudioUnitRenderActionFlags * ioActionFlags, const AudioTimeStamp * inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList * ioData) { if (*ioActionFlags == kAudioUnitRenderAction_PostRender &amp;&amp; inBusNumber == 0) { EffectState *effectState = (EffectState *)inRefCon; ExtAudioFileWriteAsync(effectState-&gt;audioFileRef, inNumberFrames, ioData); } return noErr; } </code></pre> <p>There is something missing in the output file <a href="http://www.iphone.re/audio/output.caf">output.caf</a> :). I'm totally lost in formats to apply.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload