Safari webkitSpeechRecognition continuous bug
Asked Answered
G

1

6

I am trying to use webkitSpeechRecognition with the continuous setting set to false (when the user stops speaking, webkitSpeechRecognition auto stops) but when I stop speaking and the webkitSpeechRecognition stops, when using Safari iOS and macOS still show that the microphone is still listening. If I manually start it and stop it, I don't have this problem.

In order to get Safari to recognize that the microphone is no longer listening, I have to start and manually stop webkitSpeechRecognition again.

EDIT: The microphone is actually listening and inputting text even after the .onend event occurs. Essentially Safari is not actually ending on .onspeechend - am I doing something wrong or is this a bug? It only occurs on Safari, not Chrome. Please see example, text will still be inputted even after it says stopped.

Even with Safari minimized

Real time

Am I doing something wrong? Is there a workaround to this?

    let speechrecognition;
    if ("webkitSpeechRecognition" in window) {

        // set microphone to show
        speechrecognition = new webkitSpeechRecognition();

        // stop listening after the user stops speaking or it can keep listening until the user stops
        speechrecognition.continuous = false; 

        // interim results along with the final results
        speechrecognition.interimResults = true; 
    
    
    speechrecognition.onstart = () => {
      console.log ("started");
        };


        speechrecognition.onend = () => {
            console.log ("stopped");
            
        };


        let final_transcript = "";
        speechrecognition.onresult = (event) => {
            // Create the interim transcript string locally because we don't want it to persist like final transcript
            let interim_transcript = "";

            // Loop through the results from the speech recognition object.
            for (let i = event.resultIndex; i < event.results.length; ++i) {

                if (event.results[i].isFinal) {
                    final_transcript += event.results[i][0].transcript;

                    document.getElementsByClassName("dict")[0].innerHTML = final_transcript;

                } else {
                    interim_transcript += event.results[i][0].transcript;

                    document.getElementsByClassName("dict")[0].innerHTML = interim_transcript;
                }
            }

            final_transcript = "";

        };
    }
 
 
 <div class="dict"></div>
 
 <button onclick="speechrecognition.start();">start</button>
 
  <button onclick="speechrecognition.stop();">stop</button>
Gasworks answered 19/2, 2023 at 7:29 Comment(1)
Here is my work around: recognition.onspeechend = () => { if (navigator.vendor.indexOf('Apple') > -1){ recognition.start(); recognition.stop(); } }; It seems to work but still gives an error in Safari's console. Better than nothing.Gasworks
R
2

I thought it would be worth making OP's comment on his own question into an answer, since it also worked for me. I was finding that calling recognition.stop() successfully caused the onend() callback to fire, but then the service continued listening regardless (this is on Safari for iOS 16.1.1).

The practice of redundantly calling start() right before you call stop() seems to be the key to working around this, regardless of whether it's in an onspeechend() callback or elsewhere.

function SeriouslyStopListening(recognition)
{
    if (navigator.vendor.indexOf('Apple') > -1)
    {
        try{ recognition.start(); }
        catch(err) { }
    }
    recognition.stop();
}
Rainbolt answered 3/7, 2023 at 14:50 Comment(1)
Prettay, prettay, prettay good. Pretty good.Gasworks

© 2022 - 2024 — McMap. All rights reserved.