如何将AudioBufferList转换为AVAudioPCMBuffer?转换报错求助
问题解决:AudioBufferList转AVAudioPCMBuffer格式不匹配错误
错误原因
你遇到的报错the number of buffers (1) does not match the format's number of channel streams (2),核心是数据结构不匹配:
- 你通过
AudioUnitRender生成的AudioBufferList是交错(Interleaved)格式:1个AudioBuffer承载2个声道的混合数据 - 但你创建
AVAudioFormat时指定了interleaved: false,这要求格式为非交错(Non-Interleaved):每个声道对应1个独立的AudioBuffer,也就是需要2个buffer
解决方案一:修改AVAudioFormat为交错格式(推荐)
直接让音频格式和AudioBufferList的结构对齐,把interleaved参数改为true即可:
let audioFormat = AVAudioFormat( commonFormat: AVAudioCommonFormat.pcmFormatFloat64, sampleRate: recoder.sampleRate, interleaved: true, // 改为交错格式 channelLayout: AVAudioChannelLayout( layoutTag: kAudioChannelLayoutTag_Stereo )! ) guard let pcmBuffer = AVAudioPCMBuffer( pcmFormat: audioFormat, bufferListNoCopy: &bufferList ) else { return }
解决方案二:将AudioBufferList转换为非交错格式(如需非交错场景)
如果业务必须使用非交错格式,需要手动把交错数据拆分为独立的声道buffer:
// 假设AudioUnit输出的是Float64类型的交错音频数据 guard let interleavedData = bufferList.mBuffers.mData?.assumingMemoryBound(to: Float64.self) else { return } // 计算总帧数:字节数 / (单采样字节数 × 声道数) let frameCount = Int(bufferList.mBuffers.mDataByteSize) / (MemoryLayout<Float64>.stride * 2) // 创建非交错的AudioBufferList(2个buffer对应左右声道) var nonInterleavedBufferList = AudioBufferList( mNumberBuffers: 2, mBuffers: ( AudioBuffer(mNumberChannels: 1, mDataByteSize: UInt32(frameCount * MemoryLayout<Float64>.stride), mData: malloc(frameCount * MemoryLayout<Float64>.stride)), AudioBuffer(mNumberChannels: 1, mDataByteSize: UInt32(frameCount * MemoryLayout<Float64>.stride), mData: malloc(frameCount * MemoryLayout<Float64>.stride)) ) ) // 拆分交错数据到两个声道 guard let leftData = nonInterleavedBufferList.mBuffers.0.mData?.assumingMemoryBound(to: Float64.self), let rightData = nonInterleavedBufferList.mBuffers.1.mData?.assumingMemoryBound(to: Float64.self) else { // 失败时释放内存避免泄漏 free(nonInterleavedBufferList.mBuffers.0.mData) free(nonInterleavedBufferList.mBuffers.1.mData) return } for i in 0..<frameCount { leftData[i] = interleavedData[i * 2] // 左声道数据:偶数索引 rightData[i] = interleavedData[i * 2 + 1] // 右声道数据:奇数索引 } // 创建非交错的AVAudioPCMBuffer let audioFormat = AVAudioFormat( commonFormat: AVAudioCommonFormat.pcmFormatFloat64, sampleRate: recoder.sampleRate, interleaved: false, channelLayout: AVAudioChannelLayout(layoutTag: kAudioChannelLayoutTag_Stereo)! ) guard let pcmBuffer = AVAudioPCMBuffer(pcmFormat: audioFormat, bufferListNoCopy: &nonInterleavedBufferList) else { free(nonInterleavedBufferList.mBuffers.0.mData) free(nonInterleavedBufferList.mBuffers.1.mData) return } // 注意:使用bufferListNoCopy时,需保证数据内存的生命周期不短于AVAudioPCMBuffer,避免野指针
内容的提问来源于stack exchange,提问作者water or sapphire
相关产品推荐
相关产品推荐

