如何在Avfoundation中正确更改采样率

我做了这个简单的程序。 它的作用是它只是同时记录和回放缓冲区。 如果采样率为44100赫兹,一切正常,但如果我将采样率改为16000或8000,它根本不会产生任何声音,或者可能是一些不可听见的白噪声。为什么会发生这种情况?

如何以不同的采样率录制?

以下代码我尝试过:

import UIKit import AVFoundation class ViewController: UIViewController { var engine = AVAudioEngine() let player = AVAudioPlayerNode() let audioSession = AVAudioSession.sharedInstance() let newSrc:UnsafeMutablePointer! = nil override func viewDidLoad() { super.viewDidLoad() let audioSession = AVAudioSession.sharedInstance() print(audioSession.sampleRate) // here it prints 44100 hz. because it still using the internal mic. do { try audioSession.setCategory(AVAudioSessionCategoryPlayAndRecord, with: .allowBluetooth) try audioSession.setMode(AVAudioSessionModeDefault) try audioSession.setActive(true) } catch { } print(audioSession.sampleRate) // here it will print 16000 hz if my bluetooth earbuds is connected, if not it will be 44100 hz. let input = engine.inputNode let bus = 0 let mixer = AVAudioMixerNode() // creating mixer as it is needed to set audio format engine.attach(mixer) engine.attach(player) engine.connect(input, to: mixer, format: input.outputFormat(forBus: 0)) let inputFormat = input.inputFormat(forBus: bus) engine.connect(player, to: engine.mainMixerNode, format: input.inputFormat(forBus: 0)) let fmt = AVAudioFormat(commonFormat: .pcmFormatFloat32, sampleRate: 44100.0, channels: 1, interleaved: false) mixer.installTap(onBus: bus, bufferSize: 1024, format: fmt) { (buffer, time) -> Void in print(buffer.format) print(buffer.floatChannelData) print(buffer.format.streamDescription.pointee.mBytesPerFrame) self.player.scheduleBuffer(buffer) if self.player.isPlaying { print("true") } } engine.prepare() do{ try! engine.start() player.play() } catch { print(error) } } } 

如此处所述 , AVAudioEngine混音器节点和分接头都不会为您进行速率转换。 事实上在你的情况下,而不是抛出或记录错误,混音器静音(得到它?)让你沉默。

由于您无法使用AVAudioMixerNode进行速率转换,因此可以使用方便的AVAudioConverter替换它,确保设置AVAudioPlayerNode的正确输出格式,因为

在播放缓冲区时,隐含的假设是缓冲区的采样率与节点的输出格式相同。

如果您不这样做,您可能会听到间隙和/或音调偏移。

像这样

 let input = engine.inputNode let bus = 0 let inputFormat = input.inputFormat(forBus: bus) engine.attach(player) let fmt = AVAudioFormat(commonFormat: .pcmFormatFloat32, sampleRate: 8000, channels: 1, interleaved: false)! engine.connect(player, to: engine.mainMixerNode, format: fmt) let converter = AVAudioConverter(from: inputFormat, to: fmt)! input.installTap(onBus: bus, bufferSize: 1024, format: inputFormat) { (buffer, time) -> Void in let inputCallback: AVAudioConverterInputBlock = { inNumPackets, outStatus in outStatus.pointee = AVAudioConverterInputStatus.haveData return buffer } let convertedBuffer = AVAudioPCMBuffer(pcmFormat: fmt, frameCapacity: AVAudioFrameCount(fmt.sampleRate) * buffer.frameLength / AVAudioFrameCount(buffer.format.sampleRate))! var error: NSError? = nil let status = converter.convert(to: convertedBuffer, error: &error, withInputFrom: inputCallback) assert(status != .error) print(convertedBuffer.format) print(convertedBuffer.floatChannelData) print(convertedBuffer.format.streamDescription.pointee.mBytesPerFrame) self.player.scheduleBuffer(convertedBuffer) }