我已经完成了这个简单的程序。它的作用是只记录并同时播放缓冲区。如果采样率是44100 Hz,一切正常,但是如果我将采样率更改为16000或8000,则它根本不会发出声音,或者可能会产生一些白噪声,这是不可审计的。为什么会这样?
如何记录不同的采样率?
以下我尝试过的代码:
import UIKit
import AVFoundation
class ViewController: UIViewController {
var engine = AVAudioEngine()
let player = AVAudioPlayerNode()
let audioSession = AVAudioSession.sharedInstance()
let newSrc:UnsafeMutablePointer<Float>! = 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)
}
}
}
作为discussed here,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)
}
此解决方案对我有用
let fmt = AVAudioFormat(commonFormat: .pcmFormatFloat32, sampleRate: 44100, channels: 1, interleaved: false)!
inputNode.installTap(onBus: 0, bufferSize: 1024, format: fmt) { (buffer: AVAudioPCMBuffer, when: AVAudioTime) in
self.recognitionRequest?.append(buffer)
}