AVAudioConverter破坏了数据

问题描述

我正在尝试将AVAudioPCMBuffer从Float32 44.1kHz转换为Int16 8kHz。我使用AVAudioConverter。但是转换后,我得到了损坏的数据。当我每100毫秒从麦克风读取一次数据时,我会破坏掉第800个样本(读取数据中的第一个样本)。损坏的样本如下所示: broken sample

这只是800个样本中的一个,但是听起来每100毫秒就会产生一次令人讨厌的点击。 这是我的一部分代码

...
    let outputFormat = AVAudioFormat(commonFormat: .pcmFormatInt16,sampleRate: 8000,channels: 1,interleaved: false)!
    let input = self.engine.inputNode
    let bus = 0
    let inputFormat = input.outputFormat(forBus: bus)
        
    let bufferSize = inputFormat.sampleRate * 0.1 // Read every 100ms
        
    input.installTap(onBus: bus,bufferSize: UInt32(bufferSize),format: inputFormat) { (buffer,time) -> Void in
                
        let convertedBuffer = self.convertBuffer(buffer: buffer,from: inputFormat,to: outputFormat)
        if self.isRecording {
            self.inFile?.seekToEndOfFile()
            let data = Data(buffer: UnsafeBufferPointer(start: convertedBuffer.int16ChannelData![0],count: Int(convertedBuffer.frameLength)))
            self.inFile?.write(data)
        }
...

func convertBuffer(buffer: AVAudioPCMBuffer,from inputFormat: AVAudioFormat,to outputFormat: AVAudioFormat) -> AVAudioPCMBuffer {
        
    let converter = AVAudioConverter(from: inputFormat,to: outputFormat)!
        
    let inputCallback: AVAudioConverterInputBlock = { inNumPackets,outStatus in
        outStatus.pointee = .haveData
        return buffer
    }
        
    let convertedBuffer = AVAudioPCMBuffer(
        pcmFormat: outputFormat,frameCapacity: AVAudioFrameCount(outputFormat.sampleRate) * buffer.frameLength / AVAudioFrameCount(buffer.format.sampleRate))!
        
    var error: NSError?
    let status = converter.convert(to: convertedBuffer,error: &error,withInputFrom: inputCallback)
    assert(status != .error)
        
    return convertedBuffer
}

当我编写缓冲区而没有任何转换时,我得到清晰的声音而没有损坏。如果我每200ms读取一次数据,则第1600个样本将被破坏。因此,这只是我得到的每个缓冲区损坏的第一个样本。

我真的不知道我的代码有什么问题,为什么它那样工作。有什么错误吗?

P.S。 我不太在意转换,我只需要从麦克风获取16位PCM 8kHz原始音频数据即可。如果有人知道怎么做,那我将非常感谢您的帮助。

解决方法

音频转换器具有内部状态。创建单个转换器而不是在每次对convertBuffer的调用中都创建一个转换器。