i have a Problem ;)
i want to record Audio from the Mic and Write it to the Filesystem with Extended Audio File Services and also play the recorded Stuff. if i only use the remoteIO with two callbacks one for read one for write it works.
For the Volumen Control i want to use the MultiChannelMixer and the AUGraph. is it possible that you realize playback and recording with the same mixer and the RemoteIO?
i think it must look like this:
RemotIO Input -> -> Write Callback
Mixer
RemoteIO Output <- <- Read Callback
i create two AUNodes (RemoteIO and MultiChannelMixer), how must i set the Callbacks and the Connections that one Callback deliver the AudioData from the mic and an other reads the Data from a File and both paths go through the mixer?
The reading and writing is not the Problem, only the configuration of the Nodes!
…and the output of CAShow:
AudioUnitGraph 0x8AEE000:
Member Nodes:
node 1: 'aumx' 'mcmx' 'appl', instance 0x865a510 O I
node 2: 'auou' 'rioc' 'appl', instance 0x865d0a0 O I
Connections:
node 1 bus 0 => node 2 bus 0 [ 2 ch, 44100 Hz, 'lpcm' (0x0000000C) 16-bit little-endian signed integer]
node 2 bus 1 => node 1 bus 1 [ 2 ch, 44100 Hz, 'lpcm' (0x0000000C) 16-bit little-endian signed integer]
Input Callbacks:
{0x4150, 0x7573340} => node 2 bus 1 [2 ch, 44100 Hz]
{0x4330, 0x7573340} => node 1 bus 0 [2 ch, 44100 Hz]
CurrentState:
mLastUpdateError=0, eventsToProcess=F, isRunning=F
here is the setup code:
OSStatus setupErr = noErr;
AudioComponentDescription mixerDescription;
AudioComponentDescription ioDescription;
// the AUNodes
AUNode mixerNode;
AUNode ioNode;
// the graph
setupErr = NewAUGraph(&_graph);
NSAssert(setupErr == noErr, @"Couldn't create graph");
// the mixer
mixerDescription.componentFlags = 0;
mixerDescription.componentFlagsMask = 0;
mixerDescription.componentType = kAudioUnitType_Mixer;
mixerDescription.componentSubType = kAudioUnitSubType_MultiChannelMixer;
mixerDescription.componentManufacturer = kAudioUnitManufacturer_Apple;
// the io
ioDescription.componentFlags = 0;
ioDescription.componentFlagsMask = 0;
ioDescription.componentType = kAudioUnitType_Output;
ioDescription.componentSubType = kAudioUnitSubType_RemoteIO;
ioDescription.componentManufacturer = kAudioUnitManufacturer_Apple;
// add mixer Node
setupErr = AUGraphAddNode(self.graph, &mixerDescription, &mixerNode);
NSAssert(setupErr == noErr, @"Couldn't create master mixer");
// add io Node
setupErr = AUGraphAddNode(self.graph, &ioDescription, &ioNode);
NSAssert(setupErr == noErr, @"Couldn't create io node");
// open Graph
setupErr = AUGraphOpen(self.graph);
NSAssert(setupErr == noErr, @"Couldn't open graph");
// get the mixer info
setupErr = AUGraphNodeInfo(self.graph, mixerNode, &mixerDescription, &_mixer);
NSAssert(setupErr == noErr, @"Couldn't get master mixer info");
// get the io info
setupErr = AUGraphNodeInfo(self.graph, ioNode, &ioDescription, &_io);
NSAssert(setupErr == noErr, @"Couldn't get io Node info");
// enable io input
UInt32 enableFlag = 1;
setupErr = AudioUnitSetProperty(self.io, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, kInputBus, &enableFlag, sizeof(enableFlag));
NSAssert(setupErr == noErr, @"Couldn't enable io input");
// set up the mixers input callbacks
AURenderCallbackStruct outputCallbackStruct;
outputCallbackStruct.inputProc = outputCallback;
outputCallbackStruct.inputProcRefCon = self;
AURenderCallbackStruct inputCallbackStruct;
inputCallbackStruct.inputProc = inputCallback;
inputCallbackStruct.inputProcRefCon = self;
setupErr = AUGraphConnectNodeInput(self.graph, mixerNode, 0, ioNode, 0);
NSAssert(setupErr == noErr, @"Couldn't connect mixer output to io output");
setupErr = AUGraphConnectNodeInput(self.graph, ioNode, 1, mixerNode, 1);
NSAssert(setupErr == noErr, @"Couldn't connect io input to mixer input");
// set output Callback
setupErr = AUGraphSetNodeInputCallback(self.graph, ioNode, 1, &outputCallbackStruct);
NSAssert(setupErr == noErr, @"Error setting io output callback");
// set input Callback
setupErr = AUGraphSetNodeInputCallback(self.graph, mixerNode, 0, &inputCallbackStruct);
NSAssert(setupErr == noErr, @"Error setting mixer input callback");
// describe format
AudioStreamBasicDescription audioFormat = {0};
audioFormat.mSampleRate = 44100.00;
audioFormat.mFormatID = kAudioFormatLinearPCM;
audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
audioFormat.mFramesPerPacket = 1;
audioFormat.mChannelsPerFrame = 2;
audioFormat.mBitsPerChannel = 16;
audioFormat.mBytesPerPacket = 4;
audioFormat.mBytesPerFrame = 4;
// set the rio input properties
setupErr = AudioUnitSetProperty(self.io, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, kOutputBus, &audioFormat, sizeof(audioFormat));
NSAssert(setupErr == noErr, @"Error setting RIO input property");
// set the rio output properties
setupErr = AudioUnitSetProperty(self.io, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, kInputBus, &audioFormat, sizeof(audioFormat));
NSAssert(setupErr == noErr, @"Error setting RIO output property");
// set the master fader output properties
setupErr = AudioUnitSetProperty(self.mixer, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Global, kOutputBus, &audioFormat, sizeof(audioFormat));
NSAssert(setupErr == noErr, @"Error setting master output property");
// set the master fader input properties
setupErr = AudioUnitSetProperty(self.mixer, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Global, kOutputBus, &audioFormat, sizeof(audioFormat));
NSAssert(setupErr == noErr, @"Error setting master input1 property");
// initialize Graph
setupErr = AUGraphInitialize(self.graph);
NSAssert(setupErr == noErr, @"Error initializing graph - error code");
CAShow(self.graph);
// start Graph
setupErr = AUGraphStart(self.graph);
NSAssert(setupErr == noErr, @"Error starting graph. - error code");
i hope you understand my problem :) Thanks..
Update: Some more Stuff to describe my Problem!
Recording: RemoteIO InputScope Bus 0 -> Mixer Input Bus 0 -> Mixer Output Bus 0 -> Write Callback -> File Playback: File -> Read Callback -> Mixer Input Bus 1 -> Mixer Output Bus 0 -> RemoteIO OutputScope Bus 1
You need create AUGraph with three nodes (units):
Connect them like this:
AUGraphConnectNodeInput(m_graph, m_player, 0, m_mixerNode, 0); // player -> mixer
AUGraphConnectNodeInput(m_graph, m_mixerNode, 0, m_rioNode, 0); // mixer -> output
AUGraphConnectNodeInput(m_graph, m_rioNode, 1, m_mixerNode, 1); // input -> mixer
Enable input on RIO:
UInt32 enable = 1;
AudioUnitSetProperty(m_rioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enable, sizeof(UInt32));
Get mixer output format and set it as client format for Extended Audio File:
AudioStreamBasicDescription mixerASBD;
UInt32 prop = sizeof(mixerASBD);
AudioUnitGetProperty(m_mixerUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &mixerASBD, &prop);
ExtAudioFileSetProperty(extAudioFile, kExtAudioFileProperty_ClientDataFormat, sizeof(mixerASBD), &mixerASBD);
Define render callback:
static OSStatus mixerCallBack(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp * inTimeStamp, UInt32 inBusNumber,UInt32 inNumberFrames, AudioBufferList *ioData) {
if ((*ioActionFlags) & kAudioUnitRenderAction_PostRender)
return (ExtAudioFileWrite(extAudioFile, inNumberFrames, ioData));
return noErr;
}
Add callback for output data from mixer:
AudioUnitAddRenderNotify(m_mixerUnit, mixerCallBack, NULL);
That's all. You need to schedule audio files to FilePlayer unit to play.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With