I'm trying to convert audio buffers to a different format, and I'm using AVAudioConverter. AVAudioConverter does the job when you have the same sample rate and you don't need to use the AVAudioConverterInputBlock.
But if I'm dealing with the same sample rate, I'm getting a strange stutter in my audio data. I have a feeling I'm not handling the input block well. The output has words repeating two or three times. Below is the full method:
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()
}
}
Any thoughts? I got this code from an Apple slide sample:
// 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
}
}