I'm using the Speech framework to perform recognition on live audio. When I open a recording/recognition session two times in a row, I get the following error:
*** Terminating app due to uncaught exception 'com.apple.coreaudio.avfaudio', reason: 'required condition is false: _recordingTap == nil'
Let's assume that I have user permission and that the speech recognizer is available (both are true at the time of the crash). The method I invoke is:
private func listen() throws {
if let recognitionTask = self.recognitionTask {
recognitionTask.cancel()
self.recognitionTask = nil
}
self.recognitionRequest = SFSpeechAudioBufferRecognitionRequest()
guard let recognitionRequest = self.recognitionRequest else { fatalError("Unable to created a SFSpeechAudioBufferRecognitionRequest object") }
guard let inputNode = audioEngine.inputNode else { fatalError("Audio engine has no input node") }
recognitionRequest.shouldReportPartialResults = true
self.recognitionTask = speechRecognizer?.recognitionTaskWithRequest(recognitionRequest, resultHandler: { (result, error) in
// Code here in which I look for certain phrases - irrelevant
})
let recordingFormat = inputNode.outputFormatForBus(0)
inputNode.installTapOnBus(0, bufferSize: 2048, format: recordingFormat, block: { (buffer: AVAudioPCMBuffer, when: AVAudioTime) in
recognitionRequest.appendAudioPCMBuffer(buffer)
})
self.audioEngine.prepare()
try self.audioEngine.start()
}
Most of these variables are declared or defined outside of the method body:
private let audioEngine = AVAudioEngine()
private var speechRecognizer: SFSpeechRecognizer?
private var recognitionRequest: SFSpeechAudioBufferRecognitionRequest?
private var recognitionTask: SFSpeechRecognitionTask?
And, before the method is invoked, I call the following method to close the recording and recognition session. This method is invoked much before (let's say a minute or so) I call listen() again.
func stopListening()
self.audioEngine.stop()
self.recognitionRequest?.endAudio()
self.recognitionTask?.cancel()
self.recognitionTask = nil
}
In stopListening(), anything that I zero out is later reinitialized in listen().
Just to reiterate, this crash happens on a second invoke of listen() only after I invoke stopListening(), with these methods being called minutes apart.