我正在尝试将音频缓冲区转换为不同的格式,并且我正在使用 AVAudioConverter。当您具有相同的采样率并且您不需要使用 AVAudioConverterInputBlock 时,AVAudioConverter 可以完成这项工作。
但是,如果我处理相同的采样率,我的音频数据就会出现奇怪的卡顿。我感觉我没有很好地处理输入块。输出中有重复两到三遍的单词。下面是完整的方法:
func sendAudio(audioFile: URL, completionHandler: @escaping (Bool, Bool, Data?)->Void) {
createSession(){ sessionUrl, observeURL, session in
let file = try! AVAudioFile(forReading: audioFile)
let formatOfAudio = file.processingFormat
self.engine = AVAudioEngine()
guard let input = self.engine.inputNode else {
print("no input")
return
}
//The audio in format in this case is: <AVAudioFormat 0x61800009d010: 2 ch, 44100 Hz, Float32, non-inter>
let formatIn = formatOfAudio
let formatOut = AVAudioFormat(commonFormat: .pcmFormatInt16, sampleRate: 16000, channels: 1, interleaved: true)
let mixer = AVAudioMixerNode()
self.engine.attach(mixer)
mixer.volume = 0.0
self.engine.attach(self.audioPlayerNode)
self.engine.connect(self.audioPlayerNode, to: mixer, format: formatIn)
self.engine.connect(input, to: mixer, format: input.outputFormat(forBus: 0))
self.engine.connect(mixer, to: self.engine.mainMixerNode, format: formatIn)
let audioConverter = AVAudioConverter(from: formatIn, to: formatOut)
mixer.installTap(onBus: 0, bufferSize: 32000, format: formatIn, block: {
(buffer: AVAudioPCMBuffer!, time: AVAudioTime!) -> Void in
let convertedBuffer = AVAudioPCMBuffer(pcmFormat: formatOut, frameCapacity: buffer.frameCapacity)
let inputBlock: AVAudioConverterInputBlock = { inNumPackets, outStatus in
outStatus.pointee = AVAudioConverterInputStatus.haveData
return buffer
}
var error: NSError? = nil
let status = audioConverter.convert(to: convertedBuffer, error: &error, withInputFrom: inputBlock)
let myData = convertedBuffer.toData()
completionHandler(true, false, myData)
})
self.audioPlayerNode.scheduleFile(file, at: nil){
self.delayWithSeconds(3.0){
self.engine.stop()
mixer.removeTap(onBus: 0)
completionHandler(true, true, nil)
}
}
do {
try self.engine.start()
} catch {
print(error)
}
self.audioPlayerNode.play()
}
}
有什么想法吗?我从Apple 幻灯片示例中得到了这段代码:
// Create an input block that’s called when converter needs input
let inputBlock : AVAudioConverterInputBlock = {inNumPackets, outStatus in
if (<no_data_available>) {
outStatus.memory = AVAudioConverterInputStatus.NoDataNow;
return nil;
} else if (<end_of_stream>) {
outStatus.memory = AVAudioConverterInputStatus.EndOfStream;
return nil;
} else {
..outStatus.memory = AVAudioConverterInputStatus.HaveData;
return inBuffer; // fill and return input buffer
}
}