AudioQueueBuffers 之间的爆裂噪音

Posted

技术标签:

【中文标题】AudioQueueBuffers 之间的爆裂噪音【英文标题】:Popping noise between AudioQueueBuffers 【发布时间】:2016-07-21 16:43:41 【问题描述】:

我正在尝试使用 Core Audio AudioQueue (Swift 3) 播放纯正弦波音调。

它播放得很好,但每次调用我的 AudioQueueOutputCallback 以用音频数据填充新缓冲区时,我都会听到爆裂声。

我的 Audiostreamer 类如下所示:

let kNumberBuffers = 3

protocol AudioStreamerDelegate 
    func requestAudioData() -> [Float]


let sampleRate = 48000.0
let bufferSize = Int(sampleRate) / 50
let bufferByteSize = UInt32(bufferSize * sizeof(Float)) // 20 mili sec of audio

class AudioStreamer 
    var delegate: AudioStreamerDelegate

    var outputQueue: AudioQueueRef?

    var buffers = [AudioQueueBufferRef?](repeatElement(nil, count: kNumberBuffers))

    var streamBasicDescription = AudioStreamBasicDescription(
        mSampleRate: sampleRate,
        mFormatID: kAudioFormatLinearPCM,
        mFormatFlags: kAudioFormatFlagsNativeFloatPacked | kAudioFormatFlagIsNonInterleaved,
        mBytesPerPacket: UInt32(sizeof(Float)),
        mFramesPerPacket: 1,
        mBytesPerFrame: UInt32(sizeof(Float)),
        mChannelsPerFrame: 1,
        mBitsPerChannel: UInt32(8 * sizeof(Float)),
        mReserved: 0
    )

    init(delegate: AudioStreamerDelegate) 
        // create new output audio queue
        self.delegate = delegate
    

    func play() 
        let queue = DispatchQueue.main

        queue.async(execute: 
            let selfPointer = unsafeBitCast(self, to: UnsafeMutablePointer<Void>.self)
            AudioQueueNewOutput(
                &self.streamBasicDescription,
                AudioStreamerOuputCallback,
                selfPointer,
                nil,
                nil,
                0,
                &self.outputQueue
            )

            // allocate buffers
            for i in 0 ..< kNumberBuffers 
                AudioQueueAllocateBuffer(
                    self.outputQueue!,
                    bufferByteSize,
                    &self.buffers[i]
                )

                if let bufferRef = self.buffers[i] 
                    // configure audio buffer
                    let selfPointer = unsafeBitCast(self, to: UnsafeMutablePointer<Void>.self)
                    bufferRef.pointee.mUserData = selfPointer
                    bufferRef.pointee.mAudioDataByteSize = bufferByteSize
                
            

            AudioQueuePrime(self.outputQueue!, 0, nil)
            for bufferRef in self.buffers 
                AudioStreamerOuputCallback(userData: unsafeBitCast(self, to: UnsafeMutablePointer<Void>.self), queueRef: self.outputQueue!, buffer: bufferRef!)
            
            AudioQueueStart(self.outputQueue!, nil)
        )
    


func AudioStreamerOuputCallback(userData: Optional<UnsafeMutablePointer<Void>>, queueRef: AudioQueueRef, buffer: AudioQueueBufferRef) 
    let this = Unmanaged<AudioStreamer>.fromOpaque(OpaquePointer(userData!)).takeUnretainedValue()
    let audioData = this.delegate.requestAudioData()

    memcpy(buffer.pointee.mAudioData, unsafeBitCast(audioData, to: UnsafeMutablePointer<Void>.self), Int(bufferByteSize))
    AudioQueueEnqueueBuffer(queueRef, buffer, 0, nil)

仅带有“播放”按钮的 ViewController 类的音频数据生成器方法(theta 是该 ViewController 上的存储属性):

func generateAudioData(frequency: Double) 
    semaphore.wait()

    let amplitude: Double = 0.25

    let theta_increment: Double = 2.0 * M_PI * frequency / sampleRate

    for j in 0 ..< Int(bufferSize) 
        audioData[j] = Float(sin(theta) * amplitude)
        theta += theta_increment

        if theta > 2.0 * M_PI 
            theta -= 2.0 * M_PI
        
    

问题看起来与this question 上的类似,但没有人回答。

任何帮助将不胜感激。

【问题讨论】:

【参考方案1】:

在您的输出回调中,您没有生成一组新的音频数据,其中新缓冲区的第一个样本的相位是前一个缓冲区的最后一个样本的增量。

【讨论】:

我认为这可能是问题所在,但此日志显示了 las 缓冲区的最后 4 个样本和当前缓冲区的前 4 个样本:956 - -0.051978 - 957 - -0.039109 958 - -0.026132 959 - -0.013084 0 - 0.000000 1 - 0.013084 2 - 0.026132 3 - 0.039109。如您所见,相位是正确的。

以上是关于AudioQueueBuffers 之间的爆裂噪音的主要内容,如果未能解决你的问题,请参考以下文章

如何在所有浏览器上播放声音?

雷电爆裂之力

颈六椎爆裂性骨折,该怎么办?

AVAudioPlayer 爆裂声和爆裂声

《爆裂鼓手》影评

IOS AudioUnit播放爆裂问题(swift)