Search code examples
javascriptapispeechspeech-synthesis

SpeechSynthesis, Web Speech API, remove the delay after speaking has finished and the onend property firing?


I'm displaying an animated graphic whilst SpeechSynthesisUtterance is speaking. I'm using the onend property to detect when speaking has finished to remove the animated graphic. However there is a significant delay between the speaking finishing and the onend event firing, which means the animated graphic carries on playing for approximately 1 second even though the speaking has finished. Is it possible to remove this delay? The below code is a simple demonstration of the problem.

let utterance = new SpeechSynthesisUtterance("Approximately a second delay after utterance has finished and the onend event firing");
speechSynthesis.speak(utterance);
utterance.onend = function () {
console.log("There is a delay before this message appears?");

}


Solution

  • Rather than using the end event, here is an example of how you can use the boundary event to remove something from the DOM based on the evt.charIndex of the utterance being spoken.

    This removes the graphic after the penultimate word finishes speaking:

    function getPenultimateWordEndingIndex(text) {
      const words = text.split(' ').filter(Boolean)
    
      // Can use words.slice(-1, -1)[0] for better browser support
      return text.lastIndexOf(words.at(-1))
    }
    
    const text = 'This image should be removed after hearing the word "event" spoken.'
    const index = getPenultimateWordEndingIndex(text)
    const graphic = document.getElementById('graphic')
    const utter = new SpeechSynthesisUtterance(text)
    
    utter.addEventListener('boundary', evt => {
      if (evt.charIndex >= index) {
        graphic.remove()
      }
    })
    
    document.getElementById('speak').addEventListener('click', () => {
      window.speechSynthesis.speak(utter)
    })
    <img src="https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png" width="100" id="graphic" />
    <p>This image should be removed after hearing the word "event" spoken. (accept chrome/android which doesn't fire boundary events)</p>
    <button id="speak">speak</button>