Изменить AudioQueueBuffer mAudioData - PullRequest
2 голосов
/ 06 марта 2020

Мне нужно установить mAudioData для AudioQueueBufferRef. Я пытался с 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)
    }

Из apple do c: https://developer.apple.com/documentation/audiotoolbox/audioqueuebuffer?language=objc

mAudioData:

Аудиоданные принадлежали аудио-очереди буфера. Адрес буфера не может быть изменен.

Так что я думаю, что решение было бы установить новое значение для того же адреса. Кто-нибудь, кто знает, как это сделать?

ОБНОВЛЕНИЕ :

Входящий аудиоформат - это сигнал pcm (Little Endian), дискретизированный с частотой 48 кГц. Вот мои настройки:

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]()

1 Ответ

3 голосов
/ 06 марта 2020

Вы близки!

Попробуйте:

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)

 }

Кроме того, проверьте, можете ли вы получить некоторые базовые c данные PCM для воспроизведения через аудио-очередь, прежде чем пытаться ввести данные на стороне сервера.

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

}
...