我有一个AUGraph设置,其中有几个文件播放器音频单元输入到一个多声道混频器单元,然后再输入到一个远程I/O输出。这个设置工作得很好。
现在我正在努力添加一个回调函数,这样我就可以计算单个文件播放器的声音级别。
private let meteringCallback: AURenderCallback = { (
inRefCon,
ioActionFlags,
inTimeStamp,
inBusNumber,
frameCount,
ioData ) -> OSStatus in
var status = noErr
var track: AUTrack = unsafeBitCast(inRefCon, to: AUTrack.self)
status = AudioUnitRender(track.fileAU!,
ioActionFlags,
inTimeStamp,
inBusNumber,
frameCount,
ioData!);
var samples = [Float]()
let ptr = ioData!.pointee.mBuffers.mData?.assumingMemoryBound(to: Float.self)
samples.append(contentsOf: UnsafeBufferPointer(start: ptr, count: Int(frameCount)))
// ... fancy algorithm calculating DB value ...
}
AUTrack simple保存有关该特定轨迹的信息。将整个类实例传递给回调(通常在示例中这样做)在这里没有意义,因为有多个文件播放器。
现在我需要把这个回调设置在某个地方,这样我就可以捕获每个文件播放器输入混音器的值。但是当我尝试这样做的时候,我总是得到一个-10877(无效元素)错误。
我试着用这个设置计数回调。
// Set metering callback
var meteringCallbackStruct = AURenderCallbackStruct(inputProc: meteringCallback,
inputProcRefCon: &self.tracks[1])
status = AudioUnitSetProperty(self.tracks[1].fileAU!,
kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Output,
0,
&meteringCallbackStruct,
UInt32(MemoryLayout<AURenderCallbackStruct>.size))
我不太确定如何解决这个问题。
如果我不把这些样本传给搅拌机,这个回拨就不会“吃掉”这些样本吗?
最佳答案
你不应该用迅捷的方式回拨电话。渲染线程处理应该只在C/C++中完成。
您可以使用render notify:
AudioUnitAddRenderNotify(mixer, my_C_callback, nil) //my_C_callback should not reference Swift objects, or be a Swift callback.
它使用与呈现回调相同的函数签名。它被称为pre和post render,您需要处理post render。你可以从ioActionFlags中得到这些信息。
int isPostRender = ioActionFlags & kAudioUnitRenderAction_PostRender;
但是,由于使用的是多通道混频器,因此内置了输入级监视,因此不需要回调。
你先这样启用它。
//AudioUnit mixer; kAudioUnitSubType_MultiChannelMixer
//Call Before AudioUnitInitialize()
UInt32 meteringMode = 1;
AudioUnitSetProperty(mixer, kAudioUnitProperty_MeteringMode, kAudioUnitScope_Input, 0, &meteringMode, sizeof(meteringMode));
然后在处理过程中,您可以通过读取参数来获得级别。
int channel = 0;
AudioUnitParameterValue averageDecibles;
AudioUnitGetParameter(mixer, kMultiChannelMixerParam_PreAveragePower, kAudioUnitScope_Input, channel, &averageDecibles);
AudioUnitParameterValue peakHoldDecibles;
AudioUnitGetParameter(mixer, kMultiChannelMixerParam_PrePeakHoldLevel, kAudioUnitScope_Input, channel, &peakHoldDecibles);
银行代码:
var meteringMode: UInt32 = 1;
let propSize = UInt32(MemoryLayout<UInt32>.size)
AudioUnitSetProperty(mixer, kAudioUnitProperty_MeteringMode, kAudioUnitScope_Input, 0, &meteringMode, propSize);
var averageDecibles: AudioUnitParameterValue = 0
AudioUnitGetParameter(mixer, kMultiChannelMixerParam_PreAveragePower, kAudioUnitScope_Input, channel, &averageDecibles);
var peakHoldDecibles: AudioUnitParameterValue = 0
AudioUnitGetParameter(mixer, kMultiChannelMixerParam_PrePeakHoldLevel, kAudioUnitScope_Input, channel, &peakHoldDecibles);