Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift: stop speech recognition after x seconds of silence

I've looked for a solution, but all of the ones I've seen are confusing so I thought I'd create a new question.

I'm using the speech library and I want the recognition task to stop after 2 seconds without input from the user. I know I want to use a timer, but I'm having trouble figuring out where to put it and how to update it.

I start the timer when the record button is pressed and I invalidate it when the stop recording button is pressed.

But where do I check if the user added new input? I was thinking of saving the last transcription and comparing it to the next one: when they are different, reset the timer.

Here's what my code looks like:

recognitionTask = speechRecognizer.recognitionTask(with: recognitionRequest) { result, error in
    var isFinal = false

    if let result = result {
        self.textView.text = result.bestTranscription.formattedString
    // Should I compare the result here to see if it changed?
        isFinal = result.isFinal
    }

    // Or should I do it here? In what order is this code even running?

    if error != nil || isFinal {
        self.result = self.textView.text

        self.audioEngine.stop()
        inputNode.removeTap(onBus: 0)

        self.recognitionRequest = nil
        self.recognitionTask = nil

        self.recordButton.isEnabled = true
        self.recordButton.setTitle("Start Recording", for: [])
    }
}
like image 907
nuvaryan Avatar asked Jul 14 '17 20:07

nuvaryan


2 Answers

I had the same issue until now. Checked your question and I suppose the code below helps you achieve the same thing I did.

recognitionTask = speechRecognizer?.recognitionTask(with: recognitionRequest, resultHandler: { (result, error) in

        var isFinal = false

        if result != nil {

            self.inputTextView.text = result?.bestTranscription.formattedString
            isFinal = (result?.isFinal)!
        }

        if let timer = self.detectionTimer, timer.isValid {
            if isFinal {
                self.inputTextView.text = ""
                self.textViewDidChange(self.inputTextView)
                self.detectionTimer?.invalidate()
            }
        } else {
            self.detectionTimer = Timer.scheduledTimer(withTimeInterval: 1.5, repeats: false, block: { (timer) in
                self.handleSend()
                isFinal = true
                timer.invalidate()
            })
        }

    })

This checks if input wasn't received for 1.5 seconds.

like image 25
Chashmeet Avatar answered Sep 28 '22 01:09

Chashmeet


This is what ended up working for me:

func restartSpeechTimer() {
    timer?.invalidate()
    timer = Timer.scheduledTimer(withTimeInterval: 1.5, repeats: false, block: { (timer) in
        // Do whatever needs to be done when the timer expires
    })
}

And inside the recognition task:

var isFinal = false
if letresult = result {
    // do something with the result
    isFinal = result.isFinal
}
if iFinal {
    self.stopRecording()
}
else if error == nil {
    self.restartSpeechTimer()
}
like image 86
nuvaryan Avatar answered Sep 28 '22 00:09

nuvaryan