如何正确地将 AVAudioCompressedBuffer 转换为数据并返回

How to correctly convert AVAudioCompressedBuffer into Data and back

我有一个 AVAudioCompressedBuffer 实例被我的 AVAudioEngine 正确解码和播放。

问题是,在将其转换为 Data 然后再转换回 AVAudioCompressedBuffer 后,它不再可播放并抛出一个 kAudioCodecBadDataError.

这就是我目前管理与 Data 之间的转换的方式:

// Convert AVAudioCompressedBuffer to Data
let capacity = Int(compressedBuffer.byteLength)
let compressedBufferPointer = compressedBuffer.data.bindMemory(to: UInt8.self, capacity: capacity)
var compressedBytes: [UInt8] = [UInt8].init(repeating: 0, count: capacity)
        compressedBufferPointer.withMemoryRebound(to: UInt8.self, capacity: capacity) { sourceBytes in
compressedBytes.withUnsafeMutableBufferPointer {
                [=10=].baseAddress!.initialize(from: sourceBytes, count: capacity)
           }
       }
        
let data = Data(compressedBytes)
// Convert Data to AVAudioCompressedBuffer
let compressedBuffer: AVAudioCompressedBuffer = AVAudioCompressedBuffer.init(format: format, packetCapacity: packetCapacity, maximumPacketSize: maximumPacketSize)
compressedBuffer.byteLength = byteLength
compressedBuffer.packetCount = packetCount
data.withUnsafeBytes {
            compressedBuffer.data.copyMemory(from: [=11=].baseAddress!, byteCount: byteLength)
        }
let buffer = compressedBuffer

所有缓冲区属性 (format, packetCapacity, maximumPacketSize, byteLength, packetCount, byteLength) 的值在转换的两端都是相同的。

事实证明,出于某种原因,以这种方式转换 AVAudioCompressedBuffer 无法包含缓冲区的 packetDescriptions。这些在缓冲区中存储为 AudioStreamPacketDescriptions 结构的 C-Style 数组。通过创建 Codable 结构 (PacketDescription) 并分别映射描述对象,重新组装的缓冲区按预期工作。

var packetDescriptions = [PacketDescription]()
        
for index in 0..<compressedBuffer.packetCount {
   if let packetDescription = compressedBuffer.packetDescriptions?[Int(index)] {
           packetDescriptions.append(
                        .init(mStartOffset: packetDescription.mStartOffset,
                              mVariableFramesInPacket: packetDescription.mVariableFramesInPacket,
                              mDataByteSize: packetDescription.mDataByteSize))
            }
        }
packetDescriptions?.enumerated().forEach { index, element in
       compressedBuffer.packetDescriptions?[index] = AudioStreamPacketDescription(mStartOffset: element.mStartOffset!,
                                                                                       mVariableFramesInPacket: element.mVariableFramesInPacket!,
                                                                                       mDataByteSize: element.mDataByteSize!)
        }