我正在尝试使用音频单元混合来自几个音频源的音频。结构非常简单,我有两个输入,一个混音器音频单元和一个通用输出。问题是输出
AudioUnit
的缓冲区仅填充了零。
AURenderCallbackStruct
直接提供给混音器。kAudioUnitSubType_MultiChannelMixer
。kAudioUnitSubType_GenericOutput
,手动拉出混合音频而不播放它。输出通过 AudioUnitConnection
连接以避免弃用 AUGraph
。 AVAudioSession
也不能用于 ReplayKit
兼容性。我删除了所有
OSStatus
检查以提供较短版本的代码;但是,所有音频单元方法都会返回 noErr
。设置方法是:
private func setupAudioUnits() {
// Setting up mixer unit
var mixerComponentDescription = AudioComponentDescription(
componentType: kAudioUnitType_Mixer,
componentSubType: kAudioUnitSubType_MultiChannelMixer,
componentManufacturer: kAudioUnitManufacturer_Apple,
componentFlags: 0,
componentFlagsMask: 0)
let mixerComponent = AudioComponentFindNext(nil, &mixerComponentDescription)
AudioComponentInstanceNew(mixerComponent!, &mixerAudioUnit)
guard let mixerAudioUnit else { fatalError() }
var streamFormat = outputFormat.streamDescription.pointee
AudioUnitSetProperty(mixerAudioUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output,
0,
&streamFormat,
UInt32(MemoryLayout<AudioStreamBasicDescription>.size))
AudioUnitInitialize(mixerAudioUnit)
var busCount = UInt32(inputs)
AudioUnitSetProperty(mixerAudioUnit,
kAudioUnitProperty_ElementCount,
kAudioUnitScope_Input,
0,
&busCount,
UInt32(MemoryLayout<UInt32>.size))
// Setting up mixer's inputs
for input in 0..<inputs {
var callbackStruct = AURenderCallbackStruct(inputProc: inputRenderCallback,
inputProcRefCon: Unmanaged.passUnretained(self).toOpaque())
AudioUnitSetProperty(mixerAudioUnit,
kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Input,
UInt32(input),
&callbackStruct,
UInt32(MemoryLayout<AURenderCallbackStruct>.size))
}
// Setting up output unit
var outputDescription = AudioComponentDescription(
componentType: kAudioUnitType_Output,
componentSubType: kAudioUnitSubType_GenericOutput,
componentManufacturer: kAudioUnitManufacturer_Apple,
componentFlags: 0,
componentFlagsMask: 0)
let outputComponent = AudioComponentFindNext(nil, &outputDescription)
AudioComponentInstanceNew(outputComponent!, &outputAudioUnit)
guard let outputAudioUnit else { fatalError() }
AudioUnitSetProperty(outputAudioUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input,
0,
&streamFormat,
UInt32(MemoryLayout<AudioStreamBasicDescription>.size))
AudioUnitInitialize(outputAudioUnit)
// Setting up a connection between the mixer and output units
var connection = AudioUnitConnection(sourceAudioUnit: mixerAudioUnit,
sourceOutputNumber: 0,
destInputNumber: 0)
AudioUnitSetProperty(outputAudioUnit,
kAudioUnitProperty_MakeConnection,
kAudioUnitScope_Input,
0,
&connection,
UInt32(MemoryLayout<AudioUnitConnection>.size))
AudioOutputUnitStart(outputAudioUnit)
}
这里是启动渲染的部分。我为
nil
提供 mData
以使用音频单元的内部缓冲区。
private func render(numberOfFrames: AVAudioFrameCount) {
timeStamp.mFlags = .sampleTimeValid
timeStamp.mSampleTime = Float64(sampleTime)
let channelCount = outputFormat.channelCount
let audioBufferList = AudioBufferList.allocate(maximumBuffers: Int(channelCount))
for i in 0..<Int(channelCount) {
audioBufferList[i] = AudioBuffer(mNumberChannels: 1,
mDataByteSize: outputFormat.streamDescription.pointee.mBytesPerFrame,
mData: nil)
}
// always returns noErr
AudioUnitRender(outputAudioUnit,
nil,
&timeStamp,
0,
numberOfFrames,
audioBufferList.unsafeMutablePointer)
for channel in 0..<Int(channelCount) {
let outputBufferData = audioBufferList[channel].mData?.assumingMemoryBound(to: Float.self)
// Inspecting the data
// Audio buffer has only zeros
}
sampleTime += Int64(numberOfFrames)
}
AudioUnitRender
始终返回 noErr
并且缓冲区具有基于提供的 AVAudioFormat
的正确大小。正在调用输入回调并且 ioData
已填充数据:
但是,输出缓冲区始终填充零:
我的输出音频单元设置或连接有问题吗?或者混合器可能没有向前传递数据?如有任何帮助,我们将不胜感激。
所以主要问题是
kAudioUnitSubType_MultiChannelMixer
在 macOS 上总是产生空缓冲区。不确定这是否是一个错误,但用 kAudioUnitSubType_StereoMixer
替换子类型解决了问题:
let mixerSubType: OSType
#if os(macOS)
mixerSubType = kAudioUnitSubType_StereoMixer
#else
mixerSubType = kAudioUnitSubType_MultiChannelMixer
#endif
还有一些其他值得一提的事情:
kAudioUnitProperty_SetRenderCallback
将渲染回调设置为 output单元,则
AudioRenderUnit
始终会生成空缓冲区。kAudioUnitProperty_StreamFormat
设置正确的音频格式。