AVAudioEngine下采样问题

时间:2016-09-20 13:26:44

标签: swift audio core-audio swift3 avaudioengine

我遇到了从麦克风下采样音频的问题。我正在使用AVAudioEngine从麦克风中取样,其代码如下:

assert(self.engine.inputNode != nil)
let input = self.engine.inputNode!

let audioFormat = AVAudioFormat(commonFormat: .pcmFormatFloat32, sampleRate: 8000, channels: 1, interleaved: false)    
let mixer = AVAudioMixerNode()
engine.attach(mixer)
engine.connect(input, to: mixer, format: input.inputFormat(forBus: 0))

do {
    try engine.start()

    mixer.installTap(onBus: 0, bufferSize: 1024, format: audioFormat, block: {
            (buffer: AVAudioPCMBuffer!, time: AVAudioTime!) -> Void in
        //some code here
    })

} catch let error {
    print(error.localizedDescription)
}

此代码在iPhone 5s上运行良好,因为麦克风输入为8000Hz,缓冲区充满了来自麦克风的数据。

问题是我希望能够从iPhone 6s(及以上)录制16000Hz的麦克风录音。最奇怪的是,如果我将mixernode与引擎mainmixernode连接(使用以下代码):

engine.connect(mixer, to: mainMixer, format: audioFormat)

这实际上是有效的,我得到的缓冲区的格式为8000Hz,声音完全下采样,唯一的问题是声音也来自扬声器,我不想要(如果我不连接缓冲区是空的。)

有谁知道如何解决此问题?

非常感谢任何帮助,意见或建议。

3 个答案:

答案 0 :(得分:2)

我通过简单地将混音器音量更改为0来解决了这个问题。

mixer.volume = 0

这使我能够利用引擎主混音器的强大功能将任何采样率重新采样到我想要的采样率,而不是听到直接从扬声器输出的麦克风反馈回路。如果有人需要澄清这个,请告诉我。

这是我现在的代码:

assert(self.engine.inputNode != nil)
let input = self.engine.inputNode!

let audioFormat = AVAudioFormat(commonFormat: .pcmFormatFloat32, sampleRate: 8000, channels: 1, interleaved: false)    
let mixer = AVAudioMixerNode()
engine.attach(mixer)
engine.connect(input, to: mixer, format: input.inputFormat(forBus: 0))
mixer.volume = 0
engine.connect(mixer, to: mainMixer, format: audioFormat)

do {
    try engine.start()

    mixer.installTap(onBus: 0, bufferSize: 1024, format: audioFormat, block: {
        (buffer: AVAudioPCMBuffer!, time: AVAudioTime!) -> Void in
        //some code here
    })

} catch let error {
    print(error.localizedDescription)
}

答案 1 :(得分:2)

另一种方法,使用 Swift 5

中的AVAudioConverter
let engine = AVAudioEngine()


func setup() {

    let input = engine.inputNode
    let bus = 0
    let inputFormat = input.outputFormat(forBus: bus )
    guard let outputFormat = AVAudioFormat(commonFormat: .pcmFormatFloat32, sampleRate: 8000, channels: 1, interleaved: true), let converter = AVAudioConverter(from: inputFormat, to: outputFormat) else{
        return
    }

    input.installTap(onBus: bus, bufferSize: 1024, format: inputFormat) { (buffer, time) -> Void in
        var newBufferAvailable = true

        let inputCallback: AVAudioConverterInputBlock = { inNumPackets, outStatus in
            if newBufferAvailable {
                outStatus.pointee = .haveData
                newBufferAvailable = false
                return buffer
            } else {
                outStatus.pointee = .noDataNow
                return nil
            }
        }

        if 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)

            // 8kHz buffers
            print(convertedBuffer.format)
        }
    }
    do {
        try engine.start()
    } catch { print(error) }
}

答案 2 :(得分:-1)

我发现唯一可以改变采样率的东西是

AVAudioSettings.sharedInstance().setPreferredSampleRate(...)

不幸的是,尽管似乎8000、12000、16000、22050、44100都可以正常工作,但不能保证将获得所需的采样率。

以下内容无效:

  1. 通过点击engine.inputNode设置我的自定义格式。 (例外)
  2. 添加具有我的自定义格式的混音器,然后点击它。 (例外)
  3. 添加一个混音器,将其与inputNode的格式连接,使用我的自定义格式将混音器连接至主混音器,然后移除outputNode的输入,以免将音频发送到扬声器并获得即时反馈。 (有效,但全为零)
  4. 在AVAudioEngine中根本不使用我的自定义格式,而在单击时使用AVAudioConverter从硬件速率转换。 [缓冲区长度未设置,无法判断结果是否正确]