【发布时间】:2020-03-22 03:47:35
【问题描述】:
我正在创建一个使用 UDP 发送和接收数据的跨平台 VOIP 应用程序。我正在使用音频单元进行实时录制和播放。处理原始数据时通信快速流畅,但当我涉及像 OPUS 这样的编解码器时,正在编码并从 iPhone 发送到 Android 的数据在两者之间有点击和弹出的声音。我一直在努力解决这个问题。
从 Android 到 iPhone 的编码数据可以完美播放,没有任何问题。我正在使用 TPCircularBuffer 来处理录制和播放时的数据。
这是我目前在录音回调中的内容:
var samplesForEncoder: UInt32 = 640
var targetBuffer = [opus_int16](repeating: 0, count: 1500)
_ = TPCircularBufferProduceBytes(&circularBuffer, mData, inNumberFrames * 2)
self.samplesSinceLastCall += inNumberFrames
encodingQueue.async {
if self.samplesSinceLastCall > self.samplesForEncoder {
let samplesToCopy = min(self.bytesToCopy, Int(self.availableBytes))
self.bufferTailPointer = TPCircularBufferTail(&self.circularBuffer, &self.availableBytes)
memcpy(&self.targetBuffer, self.bufferTailPointer, samplesToCopy)
self.semaphore.signal()
self.semaphore.wait()
self.opusHelper?.encodeStream(of: self.targetBuffer)
self.semaphore.signal()
self.semaphore.wait()
TPCircularBufferConsume(&self.circularBuffer, UInt32(samplesToCopy))
self.samplesSinceLastCall = 0
self.semaphore.signal()
self.semaphore.wait()
}
}
这是编码函数:
var encodedData = [UInt8](repeating: 0, count: 1500)
self.encodedLength = opus_encode(self.encoder!, samples, OpusSettings.FRAME_SIZE, &self.encodedData, 1500)
let opusSlice = Array(self.encodedData.prefix(Int(self.encodedLength!)))
self.seqNumber += 1
self.protoModel.sequenceNumber = self.seqNumber
self.protoModel.timeStamp = Date().currentTimeInMillis()
self.protoModel.payload = opusSlice.data
do {
_ = try self.udpClient?.send(data: self.protoModel)
} catch {
print(error.localizedDescription)
}
我尝试使用 DispatchGroups、DispatchSourceTimers、DispatchSemaphores、DispatchQueues 来处理另一个线程中的繁重处理> 但我就是无法得到我需要的结果。有人可以帮忙吗?
谁能指导我如何使编码独立于实时音频线程,我尝试创建一个轮询线程,但即使这样也没有用。我需要帮助在具有不同数据大小要求的 2 个线程之间传输数据。我从麦克风接收 341-342 字节,但我需要向编码器发送 640 字节,因此我将合并 2 个样本并重用剩余的字节供以后使用。
@hotpaw2 推荐这个https://stackoverflow.com/a/58947295/12020007,但我需要更多指导。
根据@hotpaw2 的回答更新了代码:
录音回调:
_ = TPCircularBufferProduceBytes(&circularBuffer, mData, inNumberFrames * 2)
self.samplesSinceLastCall += inNumberFrames
if !shouldStartSending {
startLooping()
}
更新轮询线程:
func startLooping() {
loopingQueue.async {
repeat {
if self.samplesSinceLastCall > self.samplesForEncoder {
let samplesToCopy = min(self.bytesToCopy, Int(self.availableBytes))
self.bufferTailPointer = TPCircularBufferTail(&self.circularBuffer, &self.availableBytes)
memcpy(&self.targetBuffer, self.bufferTailPointer, samplesToCopy)
self.semaphore.signal()
self.semaphore.wait()
self.opusEncodedStream = self.opusHelper?.encodeStream(of: self.targetBuffer)
self.semaphore.signal()
self.semaphore.wait()
self.send(stream: self.opusEncodedStream!)
self.semaphore.signal()
self.semaphore.wait()
TPCircularBufferConsume(&self.circularBuffer, UInt32(samplesToCopy))
self.samplesSinceLastCall = 0
}
self.shouldStartSending = true
} while true
}
}
【问题讨论】:
标签: ios swift grand-central-dispatch audiounit opus