import AVFoundation import Foundation final class AudioCodecBuffer { enum Error: Swift.Error { case isReady case noBlockBuffer } static let numSamples = 1024 let input: UnsafeMutableAudioBufferListPointer var isReady: Bool { numSamples == index } var maxLength: Int { numSamples * bytesPerFrame * numberChannels * maximumBuffers } let listSize: Int private var index = 0 private var buffers: [Data] private var numSamples: Int private let bytesPerFrame: Int private let maximumBuffers: Int private let numberChannels: Int private let bufferList: UnsafeMutableAudioBufferListPointer private(set) var presentationTimeStamp: CMTime = .invalid deinit { input.unsafeMutablePointer.deallocate() bufferList.unsafeMutablePointer.deallocate() } init(_ inSourceFormat: AudioStreamBasicDescription, numSamples: Int = AudioCodecBuffer.numSamples) { self.numSamples = numSamples let nonInterleaved = inSourceFormat.mFormatFlags & kAudioFormatFlagIsNonInterleaved != 0 bytesPerFrame = Int(inSourceFormat.mBytesPerFrame) maximumBuffers = nonInterleaved ? Int(inSourceFormat.mChannelsPerFrame) : 1 listSize = AudioBufferList.sizeInBytes(maximumBuffers: maximumBuffers) input = AudioBufferList.allocate(maximumBuffers: maximumBuffers) bufferList = AudioBufferList.allocate(maximumBuffers: maximumBuffers) numberChannels = nonInterleaved ? 1 : Int(inSourceFormat.mChannelsPerFrame) let dataByteSize = numSamples * bytesPerFrame buffers = .init(repeating: .init(repeating: 0, count: numSamples * bytesPerFrame), count: maximumBuffers) input.unsafeMutablePointer.pointee.mNumberBuffers = UInt32(maximumBuffers) for i in 0.. Int { guard !isReady else { throw Error.isReady } if presentationTimeStamp == .invalid { let offsetTimeStamp: CMTime = offset == 0 ? .zero : CMTime(value: CMTimeValue(offset), timescale: sampleBuffer.presentationTimeStamp.timescale) presentationTimeStamp = CMTimeAdd(sampleBuffer.presentationTimeStamp, offsetTimeStamp) } var blockBuffer: CMBlockBuffer? CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer( sampleBuffer, bufferListSizeNeededOut: nil, bufferListOut: bufferList.unsafeMutablePointer, bufferListSize: listSize, blockBufferAllocator: kCFAllocatorDefault, blockBufferMemoryAllocator: kCFAllocatorDefault, flags: 0, blockBufferOut: &blockBuffer ) guard blockBuffer != nil else { throw Error.noBlockBuffer } let numSamples = min(self.numSamples - index, sampleBuffer.numSamples - offset) for i in 0..