Skip to content

Instantly share code, notes, and snippets.

@shalyf
Last active May 10, 2024 20:28
Show Gist options
  • Save shalyf/229de21cd780d1f401fad1dbee54521d to your computer and use it in GitHub Desktop.
Save shalyf/229de21cd780d1f401fad1dbee54521d to your computer and use it in GitHub Desktop.
format CMSampleBuffer from/to AudioBufferList/Data
func data(from sampleBuffer: CMSampleBuffer) -> Data {
var abl = AudioBufferList()
var blockBuffer: CMBlockBuffer?
CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(sampleBuffer,
bufferListSizeNeededOut: nil,
bufferListOut: &abl,
bufferListSize: MemoryLayout<AudioBufferList>.size,
blockBufferAllocator: nil,
blockBufferMemoryAllocator: nil,
flags: 0,
blockBufferOut: &blockBuffer)
let buffers = UnsafeMutableAudioBufferListPointer(&abl)
var data = Data()
for audioBuffer in buffers {
if let frame = audioBuffer.mData?.assumingMemoryBound(to: UInt8.self) {
data.append(frame, count: Int(audioBuffer.mDataByteSize))
}
}
return data
}
func sampleBuffer(from data: Data) -> CMSampleBuffer? {
var buffer = data.bytes
var sampleBuffer: CMSampleBuffer?
var audioFormat = AudioStreamBasicDescription(mSampleRate: 44100,
mFormatID: kAudioFormatLinearPCM,
mFormatFlags: 0xe,
mBytesPerPacket: 2,
mFramesPerPacket: 1,
mBytesPerFrame: 2,
mChannelsPerFrame: 1,
mBitsPerChannel: 16,
mReserved: 0)
var format: CMAudioFormatDescription?
var status = CMAudioFormatDescriptionCreate(allocator: kCFAllocatorDefault,
asbd: &audioFormat,
layoutSize: 0,
layout: nil,
magicCookieSize: 0,
magicCookie: nil,
extensions: nil,
formatDescriptionOut: &format)
var timing = CMSampleTimingInfo(duration: CMTimeMake(value: 1, timescale: 44100),
presentationTimeStamp: .zero,
decodeTimeStamp: .invalid)
status = CMSampleBufferCreate(allocator: kCFAllocatorDefault,
dataBuffer: nil,
dataReady: false,
makeDataReadyCallback: nil,
refcon: nil,
formatDescription: format,
sampleCount: buffer.count / 2, // mBytesPerFrame = 2
sampleTimingEntryCount: 1,
sampleTimingArray: &timing,
sampleSizeEntryCount: 0,
sampleSizeArray: nil,
sampleBufferOut: &sampleBuffer)
guard status == noErr else { return nil }
var abl = AudioBufferList(mNumberBuffers: 1, mBuffers: (AudioBuffer(mNumberChannels: 1, mDataByteSize: UInt32(buffer.count), mData: &buffer)))
status = CMSampleBufferSetDataBufferFromAudioBufferList(sampleBuffer!,
blockBufferAllocator: kCFAllocatorDefault,
blockBufferMemoryAllocator: kCFAllocatorDefault,
flags: 0,
bufferList: &abl)
guard status == noErr else { return nil }
return sampleBuffer
}
@pablogeek
Copy link

what about for dual channel?

@lanephillips
Copy link

"Cannot use inout expression here; argument 'mData' must be a pointer that outlives the call to 'init(mNumberChannels:mDataByteSize:mData:)'"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment