iOS在渲染回调处理之前添加音频效果?

时间:2015-11-24 18:52:46

标签: ios audio callback core-audio audiounit

在我的应用中,我在渲染回调中进行音频处理(仅输入,无输出)。 以下是我初始化音频的方法:

-(void) initAudio {

OSStatus status;

NewAUGraph(&graph);

AudioComponentDescription desc;
desc.componentType          = kAudioUnitType_Output;
desc.componentSubType       = kAudioUnitSubType_RemoteIO;
desc.componentFlags         = 0;
desc.componentFlagsMask     = 0;
desc.componentManufacturer  = kAudioUnitManufacturer_Apple;

AUNode ioNode;

status = AUGraphAddNode(graph, &desc, &ioNode);
checkStatus(status, "At adding node");

AUGraphOpen(graph);

AUGraphNodeInfo(graph, ioNode, NULL, &audioUnit);

//Enable IO for recording
UInt32 enableInput = 1;
status = AudioUnitSetProperty(audioUnit,
                              kAudioOutputUnitProperty_EnableIO,
                              kAudioUnitScope_Input,
                              kInputBus,
                              &enableInput,
                              sizeof(enableInput));
checkStatus(status, "At setting property for input");

//Disable playback
UInt32 enableOutput = 0;
status = AudioUnitSetProperty(audioUnit,
                              kAudioOutputUnitProperty_EnableIO,
                              kAudioUnitScope_Output,
                              kOutputBus,
                              &enableOutput,
                              sizeof(enableOutput));
checkStatus(status, "At setting property for input");

// ASBD
AudioStreamBasicDescription audioFormatIn;
audioFormatIn.mSampleRate         = SampleRate;
audioFormatIn.mFormatID           = kAudioFormatLinearPCM;
audioFormatIn.mFormatFlags        = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
audioFormatIn.mFramesPerPacket    = 1;
audioFormatIn.mChannelsPerFrame   = 1;
audioFormatIn.mBitsPerChannel     = 16;//sizeof(AudioSampleType) * 8;
audioFormatIn.mBytesPerPacket     = 2 * audioFormatIn.mChannelsPerFrame;
audioFormatIn.mBytesPerFrame      = 2 * audioFormatIn.mChannelsPerFrame;

//Apply format
status = AudioUnitSetProperty(audioUnit,
                              kAudioUnitProperty_StreamFormat,
                              kAudioUnitScope_Output,
                              kInputBus,
                              &audioFormatIn,
                              sizeof(audioFormatIn));
checkStatus(status,"At setting property for AudioStreamBasicDescription for input");


//Set up input callback
AURenderCallbackStruct callbackStruct;
callbackStruct.inputProc = recordingCallback;
callbackStruct.inputProcRefCon = (__bridge void *)self;

status = AudioUnitSetProperty(audioUnit,
                              kAudioOutputUnitProperty_SetInputCallback,
                              kAudioUnitScope_Global,
                              kInputBus,
                              &callbackStruct,
                              sizeof(callbackStruct));
checkStatus(status,"At setting property for recording callback");

// Disable buffer allocation for the recorder
UInt32  flag = 0;
status = AudioUnitSetProperty(audioUnit,
                              kAudioUnitProperty_ShouldAllocateBuffer,
                              kAudioUnitScope_Output,
                              kInputBus,
                              &flag,
                              sizeof(flag));
checkStatus(status, "At set property should allocate buffer");

// Allocate own buffers
tempBuffer.mNumberChannels  = 1;
tempBuffer.mDataByteSize    = 1024 * 2;
tempBuffer.mData            = malloc( 1024 * 2 );

status = AUGraphInitialize(graph);
checkStatus(status,"At AUGraph Initalize");
}

现在,我想在输入音频中添加高通滤波器或带通滤波器,然后再在渲染回调中处理它。所以我想我应该添加这样的东西:

desc.componentType          = kAudioUnitType_Effect;
desc.componentSubType       = kAudioUnitSubType_BandPassFilter;
desc.componentFlags         = 0;
desc.componentFlagsMask     = 0;
desc.componentManufacturer  = kAudioUnitManufacturer_Apple;

但我没有设法正确创建/连接节点以使其工作...... 谢谢你的帮助!

1 个答案:

答案 0 :(得分:0)

当我想做类似的事情时,我发现了你的问题 - 遗憾的是没有任何解决方案:-(现在几天后设法做到了。所以这是我的工作解决方案,对于每个人都在努力解决同样的问题:< / p>

  1. 将Remote_IO的输入准备为STANDALONE音频单元,用于录制音频。
  2. 向输入添加回调。我将其称为&#34; Mic Callback&#34;。

    (注意:Apple将此称为输入回调,而实际上,这只是一个NOTIFICATION回调,告诉您的应用程序样本可用,并且您必须明确地询问输入单元#34;渲染它们......)

  3. 建立AU图:转换器单元 - &gt;过滤器 - &gt;通用输出

    (注意:通用输出可以转换,但滤波器不能转换。所以如果你想在链中输入除8.24格式以外的任何东西,那么你需要转换器。)

  4. 向转换器单元的输入添加回调。我将此称为&#34;流程回调&#34;。

  5. 现在关键点是操作系统对Mic Callback的常规调用将驱动整个处理链:

    1. 在Mic Callback中,准备一个缓冲区,该缓冲区与麦克风可用的输入样本数一样大,并且&#34;问&#34; GENERIC OUTPUT(!)用于渲染 - 相同数量的 - 样本(通过调用AudioUnitRender)。请注意,您不是要求输入单元进行渲染,而是要求输出单元位于图表的末尾!

    2. 通用输出将转发渲染请求,直到它到达转换器单元的输入回调,即进程回调。在这一个中,您将在输入参数中获得指向缓冲区的指针,您必须在其中填写所请求的样本数。此时,请求INPUT UNIT将样本准确地呈现在此缓冲区上。

    3. 中提琴,你已经完成了。你只需启动/停止麦克风单元!

      整个过程的关键是始终输出单元必须驱动整个渲染过程,因为通用输出不具有任何常规&#34;需要&#34;要获取样本,您必须手动询问它以呈现样本。这必须与麦克风的A / D转换器同步,麦克风希望以规则的时间间隔取样。

      理论上你可以链接输入单元和图表,但有两个问题:

      1. 麦克风输入单元计为输出单位,图表中不能有两个输出单位...

      2. 当单元连接在一起时,就不能在回调之间进行。如果你把它放在那里,它将永远不会被调用...所以你会把回调放在链的末尾,并期望&#34;样本可用&#34;通知我们将从麦克风单元的输出传播到通用输出的输出。但它不会。因此,您必须将流程分为麦克风输入单元和处理链。

      3. 最后注意事项:如果你想直接将麦克风的样本渲染到转换器单元中,那么你必须设置相同的流格式(最好是远程io的规范输出格式(即16位,整数)到转换器单元的输入和麦克风单元的输出(即远程io,总线1的输入范围)。