Aside from the (fairly arduous but better covered by Apple's example code) setup process of RemoteIO itself, the key points of insight were:
- Using the same
AudioStreamBasicDescription
(*audioFormat
) that I used to set up the stream in the first place. I don't know how long I spent trying to set up a new one with slightly different parameters, based on other questions and posts. Just referencing the stream attributes from my ivar was sufficient.
- Set an "isRecording" bool so that you can turn on and off write-to-file without having to tear down and re-set-up your RemoteIO session
- It is ok to write to a file in the
recordingCallback
, um, callback, but do it asynchronously. Lots of info talks about doing it in the playbackCallback or setting up some third audioFileWriteCallback. This resulted in silent files or 4KB (i.e. empty) files. Don't do it.
- Also, be sure to use a copy of the ioData that got passed into the callback
in recordingCallback
after AudioUnitRender
into bufferList
:
AudioDeviceManager* THIS = (__bridge AudioDeviceManager *)inRefCon;
if (THIS->isRecording) {
ExtAudioFileWriteAsync(THIS->extAudioFileRef, inNumberFrames, bufferList);
}
- Start and stop recording functions, for reference:
-(void)startRecording {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *destinationFilePath = [documentsDirectory stringByAppendingPathComponent:kAudioFileName];
CFURLRef destinationURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, (CFStringRef)destinationFilePath, kCFURLPOSIXPathStyle, false);
OSStatus status;
// create the capture file
status = ExtAudioFileCreateWithURL(destinationURL, kAudioFileWAVEType, &audioFormat, NULL, kAudioFileFlags_EraseFile, &extAudioFileRef);
if (status) NSLog(@"Error creating file with URL: %ld", status);
// use the same "audioFormat" AudioStreamBasicDescription we used to set up RemoteIO in the first place
status = ExtAudioFileSetProperty(extAudioFileRef, kExtAudioFileProperty_ClientDataFormat, sizeof(AudioStreamBasicDescription), &audioFormat);
ExtAudioFileSeek(extAudioFileRef, 0);
ExtAudioFileWrite(extAudioFileRef, 0, NULL);
isRecording = YES;
}
- (void)stopRecording {
isRecording = NO;
OSStatus status = ExtAudioFileDispose(extAudioFileRef);
if (status) printf("ExtAudioFileDispose %ld \n", status);
}
That's it!