Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AVAudioEngine inputNode installTap crash when restarting recording

I am implementing Speech Recognition in my app. When I first present the view controller with the speech recognition logic, everything works fine. However, when I try present the view controller again, I get the following crash:

ERROR:    [0x190bf000] >avae> AVAudioNode.mm:568: CreateRecordingTap: required condition is false: IsFormatSampleRateAndChannelCountValid(format)
*** Terminating app due to uncaught exception 'com.apple.coreaudio.avfaudio', reason: 'required condition is false: IsFormatSampleRateAndChannelCountValid(format)'

Here is the code used for starting and stopping recording:

@available(iOS 10.0, *)
extension DictationViewController {

fileprivate func startRecording() throws {
    guard let recognizer = speechRecognizer else {
        debugLog(className, message: "Not supported for the device's locale")
        return
    }

    guard recognizer.isAvailable else {
        debugLog(className, message: "Recognizer is not available right now")
        return
    }

    mostRecentlyProcessedSegmentDuration = 0
    guard let node = audioEngine.inputNode else {
        debugLog(className, message: "Could not get an input node")
        return
    }

    let recordingFormat = node.outputFormat(forBus: 0)
    node.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) { [weak self] (buffer, _) in
        self?.request.append(buffer)
    }

    audioEngine.prepare()
    try audioEngine.start()

    recognitionTask = recognizer.recognitionTask(with: request, resultHandler: {/***/})
}

fileprivate func stopRecording() {
    audioEngine.stop()
    audioEngine.inputNode?.removeTap(onBus: 0)
    request.endAudio()
    recognitionTask?.cancel()
}

}

startRecording() is called in viewDidLoad once we have requested authorization. stopRecording() is called when the view controller is dismissed.

Please assist. I'm struggling to find a solution to this crash

like image 247
Appache99 Avatar asked Jan 23 '17 11:01

Appache99


3 Answers

First, a small issue. When tapping the device's microphone, you'll want to use the format of the input bus:

let recordingFormat = node.inputFormat(forBus: 0)

Second, after some digging it seems like this crash most commonly stems from your application's shared AVAudioSession category settings. Make sure you have your audio session configured like so if you're going to be performing live microphone audio processing:

private func configureAudioSession() {
    do {
        try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayAndRecord, with: .mixWithOthers)
        try AVAudioSession.sharedInstance().setActive(true)
    } catch { }
}
like image 104
WongWray Avatar answered Oct 17 '22 01:10

WongWray


There are two possible ways to solve this problem.

  1. Check inputFormat.channelCount. It may be throwing the error because the mic is in use in another application or somewhere else you yours.
if(inputNode.inputFormat(forBus: 0).channelCount == 0){
    NSLog("Not enough available inputs!")
    return
}
  1. Try to reset the audioEngine.
audioEngine.reset()
like image 15
Burgers On Brioche Avatar answered Oct 17 '22 00:10

Burgers On Brioche


You can replace this code:

let recordingFormat = node.outputFormat(forBus: 0)

with the following:

let recordingFormat = AVAudioFormat(standardFormatWithSampleRate: 44100, channels: 1)

This code fixed the problem.

like image 5
Selva Murugan Avatar answered Oct 17 '22 01:10

Selva Murugan