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.
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>
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();
}