0

Background

I am creating a simple SpeechSynth component that runs fine on most devices but somehow on FireFox android the SpeechSynthUtterance will dispatch the onerror event with no error property defined on the event.

Voices are loaded; it's not an issue of undefined voices. I can't get to the bottom of this since the error is simply undefined.

Reproduction

const MAX_LOAD_VOICES = 5
let loadVoiceCount = 0

const loadVoices = (callback) => {
  const speech = window.speechSynthesis
  const voices = speech.getVoices()

  if (voices.length > 0) {
    return callback({ speech, voices })
  }

  if (++loadVoiceCount > MAX_LOAD_VOICES) {
    throw new Error(`Failed to load speech synthesis voices, after ${loadVoiceCount} retries.`)
  }

  return setTimeout(() => loadVoices(callback), 100)
}

loadVoices(({ speech, voices }) => {
  const utterance = new window.SpeechSynthesisUtterance('Hello world')
  utterance.voice = voices[0] // assume this is the voice we want
  utterance.onend = function () {
    console.log('SpeechSynth successfully ended')
  }

  utterance.onerror = function (event) {
    console.log('SpeechSynth failed')
    console.debug(event)
  }
  
  speech.speak(utterance)
})

Expected

This script should run just fine (just try with your browser)

Result on Firefox Android

The utterance.onerror event will be fired with no error defined and no text spoken.

Output of the logged error event (console.debug(event)):

{
bubbles: false
cancelBubble: false
cancelable: false
charIndex: 0
charLength: null
composed: false
currentTarget: null
defaultPrevented: false
elapsedTime: 0
eventPhase: 0
explicitOriginalTarget: SpeechSynthesisUtterance { text: "Hello world", volume: 1, rate: 1, … }
isTrusted: true
name: ""
originalTarget: SpeechSynthesisUtterance { text: "Hello world", volume: 1, rate: 1, … }
returnValue: true
srcElement: SpeechSynthesisUtterance { text: "Hello world", volume: 1, rate: 1, … }
target: SpeechSynthesisUtterance { text: "Hello world", volume: 1, rate: 1, … }
timeStamp: 2591
type: "error"
utterance: SpeechSynthesisUtterance { text: "Hello world", volume: 1, rate: 1, … }
<get isTrusted()>: function isTrusted()
<prototye>: SpeechSynthesisEventPrototype { utterance: Getter, charIndex: Getter, charLength: Getter, … }
}

The browser compatibility should also be of no issue, since I am running FF Mobile 88.0.1 on Android 11

Am I missing something "special" to create the utterance?

Jankapunkt
  • 8,128
  • 4
  • 30
  • 59
  • I'm running Firefox 88.1.2. I copied your code and loaded it from an html page and it works, albeit in a South Korean voice. – Frazer May 04 '21 at 11:03
  • Firefox 88.1.2 on android? – Jankapunkt May 04 '21 at 12:21
  • Yes correct. Is your code online anywhere? – Frazer May 04 '21 at 14:45
  • That's interesting. Did you set any "flags" or settings on your FF mobile? Is it the FF nightly build? The code I used is derived from the [mdn speech synth demo](https://mdn.github.io/web-speech-api/speak-easy-synthesis/) which I used as a starting point for my dev but as you can see I did not came any further. – Jankapunkt May 05 '21 at 07:14
  • It's just normal FF, no specific settings set. 4 ideas: run speech.cancel() just before speech.speak(utterance). Use onvoiceschanged event to wait for the voices instead of your voice counts. Select a voice where lang starts with en instead of picking voices[0]. Have the utterance speak after user interaction e.g. button press. – Frazer May 05 '21 at 09:53
  • @Frazer I wonder, whether this has to do with secure context? Since am using the debug tools and access my website running on another machine I have no secure context, which makes some features like service workers unavaiable. Does this maybe affect this feature but it's just not document? – Jankapunkt Jun 03 '21 at 08:53
  • 1
    When I started using speechSynthesis I had no access to https so used plain http and it was working. – Frazer Jun 25 '21 at 08:42

0 Answers0