【问题标题】:Audio being played over a stream is jittering/stuttering通过流播放的音频抖动/卡顿
【发布时间】:2017-03-29 15:49:47
【问题描述】:

我将简要介绍一下我的应用程序的所有元素:

我有一个将音频录制到 AVAudioPCMBuffer 的应用程序。然后将此缓冲区转换为 NSData,然后再转换为 [UInt8]。然后通过 OutputStream 流式传输。在另一台设备上,使用 InputStream 接收此数据。然后将其转换为 NSData,并返回到 AVAudioPCMBuffer。然后播放此缓冲区。

问题在于音频非常紧张,您无法辨认出声音,只是音频会根据对方是否在说话而变得更大或更安静。


调度缓冲区时:

self.peerAudioPlayer.scheduleBuffer(audioBuffer, completionHandler: nil)

我已延迟播放此音频几秒钟,然后播放,希望这会使音频更清晰,但它没有帮助。我最好的猜测是我正在创建的缓冲区以某种方式切断了一些音频。因此,我将向您展示我的相关代码:

这是我录制音频的方式:

    localInput?.installTap(onBus: 1, bufferSize: 4096, format: localInputFormat) {
        (buffer, when) -> Void in

        let data = self.audioBufferToNSData(PCMBuffer: buffer)
        let output = self.outputStream!.write(data.bytes.assumingMemoryBound(to: UInt8.self), maxLength: data.length)
    }

audioBufferToNSData 只是一种将 AVAudioPCMBuffer 转换为 NSData 的方法,这里是:

func audioBufferToNSData(PCMBuffer: AVAudioPCMBuffer) -> NSData {
    let channelCount = 1  // given PCMBuffer channel count is 1
    let channels = UnsafeBufferPointer(start: PCMBuffer.floatChannelData, count: channelCount)
    let data = NSData(bytes: channels[0], length:Int(PCMBuffer.frameCapacity * PCMBuffer.format.streamDescription.pointee.mBytesPerFrame))

    return data
}

我想知道问题是否出在上述方法上。可能当我计算 NSData 对象的长度时,我可能会切断部分音频。


在接收端我有这个:

    case Stream.Event.hasBytesAvailable:
        DispatchQueue.global().async {
            var tempBuffer: [UInt8] = .init(repeating: 0, count: 17640)
            let length = self.inputStream!.read(&tempBuffer, maxLength: tempBuffer.count)

            self.testBufferCount += length
            self.testBuffer.append(contentsOf: tempBuffer)

            if (self.testBufferCount >= 17640) {

                let data = NSData.init(bytes: &self.testBuffer, length: self.testBufferCount)
                let audioBuffer = self.dataToPCMBuffer(data: data)

                self.peerAudioPlayer.scheduleBuffer(audioBuffer, completionHandler: nil)

                self.testBuffer.removeAll()
                self.testBufferCount = 0
            }
        }

我检查 17640 的原因是因为正在发送的数据正好是 17640 字节,所以我需要在播放之前获取所有这些数据。

此外,dataToPCMBuffer 方法只是将 NSData 转换为 AVAudioPCMBuffer 以便可以播放。这是那个方法:

func dataToPCMBuffer(data: NSData) -> AVAudioPCMBuffer {
    let audioFormat = AVAudioFormat(commonFormat: .pcmFormatFloat32, sampleRate: 44100, channels: 1, interleaved: false)  // given NSData audio format
    let audioBuffer = AVAudioPCMBuffer(pcmFormat: audioFormat, frameCapacity: UInt32(data.length) / audioFormat.streamDescription.pointee.mBytesPerFrame)
    audioBuffer.frameLength = audioBuffer.frameCapacity
    let channels = UnsafeBufferPointer(start: audioBuffer.floatChannelData, count: Int(audioBuffer.format.channelCount))
    data.getBytes(UnsafeMutableRawPointer(channels[0]) , length: data.length)
    return audioBuffer
}

提前谢谢你!

【问题讨论】:

    标签: ios swift stream avaudioplayer


    【解决方案1】:

    我认为在 audioBufferToNSData 中你应该使用 frame​Length 而不是 frameCapacity。

    let data = NSData(bytes: channels[0], length:Int(PCMBuffer.<strong>frame​Length</strong> * PCMBuffer.format.streamDescription.pointee.mBytesPerFrame))

    PCMBuffer.frameCapacity -> 可以存储多少 PCMBuffer.frame​Length -> PCMBuffer.frameCapacity 有多少是实际有效数据

    【讨论】:

    • 我会试试这个看看它是否有效,但是,我之前已经打印出这些值并且它们是相同的(都是 4410)。另外,我实际上做了一个测试项目,它基本上记录音频,将 AVAudioPCMBuffer 转换为 NSData,然后将 NSData 转换回 AVAudioPCMBuffer 并播放音频。我这样做是为了测试我的转换,并且音频播放正常。
    • 所以我试过这个,不幸的是它不起作用。但感谢您帮助调查此问题。
    猜你喜欢
    • 2019-05-05
    • 1970-01-01
    • 1970-01-01
    • 2012-06-13
    • 1970-01-01
    • 2017-11-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多