更改 AudioQueueBuffer 的 mAudioData

Change AudioQueueBuffer's mAudioData

我需要设置 AudioQueueBufferRef 的 mAudioData。我尝试使用 copyMemory:

inBuffer.pointee.copyMemory(from: lastItemOfArray, byteCount: byteCount) // byteCount is 512

但是没用。

AudioQueueNewOutput() 队列已正确设置为 Int16 pcm 格式

这是我的代码:

   class CustomObject {
       var pcmInt16DataArray = [UnsafeMutableRawPointer]() // this contains pcmInt16 data
   }
        
   let callback: AudioQueueOutputCallback = { (
       inUserData: UnsafeMutableRawPointer?,
       inAQ: AudioQueueRef,
       inBuffer: AudioQueueBufferRef) in
    
       guard let aqp: CustomObject = inUserData?.bindMemory(to: CustomObject.self, capacity: 1).pointee else { return }
       var numBytes: UInt32 = inBuffer.pointee.mAudioDataBytesCapacity
        
    
       /// Set inBuffer.pointee.mAudioData to pcmInt16DataArray.popLast()
       /// How can I set the mAudioData here??
    
       inBuffer.pointee.mAudioDataByteSize = numBytes
       AudioQueueEnqueueBuffer(inAQ, inBuffer, 0, nil)
    }

来自苹果文档:https://developer.apple.com/documentation/audiotoolbox/audioqueuebuffer?language=objc

mAudioData:

The audio data owned the audio queue buffer. The buffer address cannot be changed.

所以我想解决方案是为同一地址设置一个新值 有人知道怎么做吗?

更新:

传入的音频格式是以 48kHz 采样的“pcm”信号(小尾数法)。这是我的设置:

var dataFormat = AudioStreamBasicDescription()
dataFormat.mSampleRate = 48000;
dataFormat.mFormatID = kAudioFormatLinearPCM
dataFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsNonInterleaved;
dataFormat.mChannelsPerFrame = 1
dataFormat.mFramesPerPacket = 1
dataFormat.mBitsPerChannel = 16
dataFormat.mBytesPerFrame = 2
dataFormat.mBytesPerPacket = 2

我正在收集传入数据以

var pcmData = [UnsafeMutableRawPointer]()

你很接近!

试试这个:

inBuffer.pointee.mAudioData.copyMemory(from: lastItemOfArray, byteCount: Int(numBytes))

或者这个:

memcpy(inBuffer.pointee.mAudioData, lastItemOfArray, Int(numBytes))

Audio Queue Services 是纯 C 的时候很难使用。现在我们必须做很多桥接才能让 API 与 Swift 一起使用,这真的很痛苦.如果您有选择,请尝试 AVAudioEngine.


其他一些要检查的事项:

确保您的 AudioQueue 的格式与您在 AudioStreamBasicDescription 中定义的格式相同。

var queue: AudioQueueRef?

// assumes userData has already been initialized and configured
AudioQueueNewOutput(&dataFormat, callBack, &userData, nil, nil, 0, &queue)

确认您已分配并准备好队列的缓冲区。

let numBuffers = 3

// using forced optionals here for brevity
for _ in 0..<numBuffers {
    var buffer: AudioQueueBufferRef?
    if AudioQueueAllocateBuffer(queue!, userData.bufferByteSize, &buffer) == noErr {
        userData.mBuffers.append(buffer!)
        callBack(inUserData: &userData, inAQ: queue!, inBuffer: buffer!)
    }
}

考虑将回调设为函数。

func callBack(inUserData: UnsafeMutableRawPointer?, inAQ: AudioQueueRef, inBuffer: AudioQueueBufferRef) {

    let numBytes: UInt32 = inBuffer.pointee.mAudioDataBytesCapacity       
    memcpy(inBuffer.pointee.mAudioData, pcmData, Int(numBytes))
    inBuffer.pointee.mAudioDataByteSize = numBytes

    AudioQueueEnqueueBuffer(inAQ, inBuffer, 0, nil)

 }

此外,在尝试引入服务器端数据之前,请查看是否可以获取一些基本 PCM 数据以通过音频队列播放。

var pcmData: [Int16] = []
for i in 0..<frameCount {
    let element = Int16.random(in: Int16.min...Int16.max) // noise
    pcmData.append(Int16(element))

}