Question

I'm trying to do a recording from RemoteIO using AudioUnitAddRenderNotify like this. Basically, I'm not able to get the samples from bus1, which is my input bus. The recordingCallback does not go past this :

   if (*ioActionFlags & kAudioUnitRenderAction_PostRender || inBusNumber != 1) {
    return noErr;
}

But I was told that the recordingCallback should be called for each bus every round. ie. called with inBusNumber ==0, then inBusNumber ==1, which are the output (remoteIO out) and input (recording bus) respectively.

What can I do to get recordingCallback to be called on my input bus so that I can record? Thanks.

Pier.

Here's the callback.

static OSStatus recordingCallback(void *inRefCon,
                              AudioUnitRenderActionFlags *ioActionFlags,
                              const AudioTimeStamp *inTimeStamp,
                              UInt32 inBusNumber,
                              UInt32 inNumberFrames,
                              AudioBufferList *ioData) {
NSLog(@"Entered recording callback");

// Only do pre render on bus 1
if (*ioActionFlags & kAudioUnitRenderAction_PostRender || inBusNumber != 1) {
    return noErr;
}

RIO *rio = (RIO*)inRefCon;
AudioUnit rioUnit = rio->theAudioUnit;
//ExtAudioFileRef eaf = rio->outEAF;
AudioBufferList abl = rio->audioBufferList;

SInt32 samples[NUMBER_OF_SAMPLES]; // A large enough size to not have to worry about buffer overrun
abl.mNumberBuffers = 1;
abl.mBuffers[0].mData = &samples;
abl.mBuffers[0].mNumberChannels = 1;
abl.mBuffers[0].mDataByteSize = inNumberFrames  * sizeof(SInt16);

OSStatus result;
result = AudioUnitRender(rioUnit,
                         ioActionFlags,
                         inTimeStamp,
                         inBusNumber, 
                         inNumberFrames,
                         &abl);

if (noErr != result) { NSLog(@"Obtain recorded samples error! Error : %ld", result); }

NSLog(@"Bus %ld", inBusNumber); 

// React to a recording flag, if recording, save the abl into own buffer, else ignore
if (rio->recording)
{
    TPCircularBufferProduceBytes(&rio->buffer, abl.mBuffers[0].mData, inNumberFrames  * sizeof(SInt16));
    //rio->timeIncurred += (('p'float)inNumberFrames) / 44100.0;
    //NSLog(@"Self-calculated time incurred: %f", rio->timeIncurred);
}

return noErr;

}

Here's the code which calls the callback.

- (void)setupAudioUnitRemoteIO {

UInt32 framesPerSlice = 0;
UInt32 framesPerSlicePropertySize = sizeof (framesPerSlice);
UInt32 sampleRatePropertySize = sizeof (_graphSampleRate);

// Describe audio component
AudioComponentDescription desc;
desc.componentType = kAudioUnitType_Output;
desc.componentSubType = kAudioUnitSubType_RemoteIO;
desc.componentFlags = 0;
desc.componentFlagsMask = 0;
desc.componentManufacturer = kAudioUnitManufacturer_Apple;

// Get component
AudioComponent inputComponent = AudioComponentFindNext(NULL, &desc);

// Get audio units
status = AudioComponentInstanceNew(inputComponent, &_remoteIOUnit);

if (noErr != status) { NSLog(@"Get audio units error"); return; }

// Enable IO for recording
UInt32 flag = 1;
status = AudioUnitSetProperty(_remoteIOUnit,
                              kAudioOutputUnitProperty_EnableIO, 
                              kAudioUnitScope_Input, 
                              kInputBus,
                              &flag, 
                              sizeof(flag));
if (noErr != status) { NSLog(@"Enable IO for recording error"); return; }

// Enable IO for playback
status = AudioUnitSetProperty(_remoteIOUnit, 
                              kAudioOutputUnitProperty_EnableIO, 
                              kAudioUnitScope_Output, 
                              kOutputBus,
                              &flag, 
                              sizeof(flag));

if (noErr != status) { NSLog(@"Enable IO for playback error"); return; }

// Obtain the value of the maximum-frames-per-slice from the I/O unit.
status =    AudioUnitGetProperty (
                                  _remoteIOUnit,
                                  kAudioUnitProperty_MaximumFramesPerSlice,
                                  kAudioUnitScope_Global,
                                  0,
                                  &framesPerSlice,
                                  &framesPerSlicePropertySize
                                  );

// Describe format

audioFormat.mSampleRate         = 44100.00;
audioFormat.mFormatID           = kAudioFormatLinearPCM;
audioFormat.mFormatFlags        = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
audioFormat.mFramesPerPacket    = 1;
audioFormat.mChannelsPerFrame   = 1;
audioFormat.mBitsPerChannel     = 16;
audioFormat.mBytesPerPacket     = 2;
audioFormat.mBytesPerFrame      = 2;

// Apply format
status = AudioUnitSetProperty(_remoteIOUnit, 
                              kAudioUnitProperty_StreamFormat, 
                              kAudioUnitScope_Output, 
                              kInputBus, 
                              &audioFormat, 
                              sizeof(audioFormat));

if (noErr != status) { NSLog(@"Apply format to input bus error"); return; }

status = AudioUnitSetProperty(_remoteIOUnit, 
                              kAudioUnitProperty_StreamFormat, 
                              kAudioUnitScope_Input, 
                              kOutputBus, 
                              &audioFormat, 
                              sizeof(audioFormat));
if (noErr != status) { NSLog(@"Apply format to output bus error"); return; }




rio.theAudioUnit = _remoteIOUnit; // Need this, as used in callbacks to refer to remoteIO

AURenderCallbackStruct callbackStruct;
callbackStruct.inputProc = recordingCallback;
callbackStruct.inputProcRefCon = &rio;
status = AudioUnitAddRenderNotify(_remoteIOUnit, callbackStruct.inputProc,  callbackStruct.inputProcRefCon);

NSAssert (status == noErr, @"Problem adding recordingCallback to RemoteIO. Error code: %d '%.4s'", (int) status, (const char *)&status);
Was it helpful?

Solution

I managed to resolve this by not using AudioUnitAddRenderNotify, and by using the following code.

AURenderCallbackStruct callbackStruct;
callbackStruct.inputProc = recordingCallback;
callbackStruct.inputProcRefCon = &rio;
status = AudioUnitSetProperty(_remoteIOUnit, 
                              kAudioOutputUnitProperty_SetInputCallback, 
                              kAudioUnitScope_Global, 
                              kInputBus, 
                              &callbackStruct, 
                              sizeof(callbackStruct));
if (noErr != status) { NSLog(@"Set input callback error"); return; }

on the input bus instead

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top