2012-11-09 42 views
7

我有一个问题剧;)AUGraph录制,RemoteIO和MultiChannelMixer

我想从麦克风录制音频,并将其写入与扩展音频文件服务的文件系统,并播放录制的东西。 如果我只使用remoteIO和两个回调函数一个读取一个写入它的工作。

对于Volumen Control我想使用MultiChannelMixer和AUGraph。 是否有可能使用相同的调音台和RemoteIO实现播放录音?

我想,一定是这样的:

RemotIO Input ->  -> Write Callback 
        Mixer 
RemoteIO Output <-  <- Read Callback 

我创建两个AUNodes(RemoteIO和MultiChannelMixer),怎么我必须设置回调和连接一个回调从麦克风和其他交付AudioData从文件中读取数据,两条路径都通过混音器?

阅读和写作不是问题,只有节点的配置!

...和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 

这里是设置代码:

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"); 

我希望你明白我的问题:) 谢谢..

更新: 还有一些东西来形容我的问题!

录音:RemoteIO InputScope总线0 - >混频器输入总线0 - >混频器输出总线0 - >写回调 - >文件 回放:文件 - >阅读回调 - >混合输入总线1 - >混频器输出总线0 - > RemoteIO OutputScope公交1

Connection Plan

回答

7

您需要使用三个节点(单位)创建AUGraph:

  1. 文件播放器(kAudioUnitSubType_AudioFilePlayer)
  2. RemoteIO
  3. 搅拌机

连接他们是这样的:

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 

上RIO使能输入:

UInt32 enable = 1; 
AudioUnitSetProperty(m_rioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enable, sizeof(UInt32)); 

获得混频器的输出格式,并设置它作为扩展音频文件的客户端格式:

AudioStreamBasicDescription mixerASBD; 
UInt32 prop = sizeof(mixerASBD); 
AudioUnitGetProperty(m_mixerUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &mixerASBD, &prop); 
ExtAudioFileSetProperty(extAudioFile, kExtAudioFileProperty_ClientDataFormat, sizeof(mixerASBD), &mixerASBD); 

定义呈现回调:从调音台输出数据

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; 
} 

添加回调:

AudioUnitAddRenderNotify(m_mixerUnit, mixerCallBack, NULL); 

这就是全部。您需要将音频文件安排到FilePlayer设备上播放。