speechSynthesis.onvoiceschanged event isn't fired
Categories
(Core :: Web Speech, enhancement)
Tracking
()
People
(Reporter: donrhummy, Unassigned)
References
()
Details
User Agent: Mozilla/5.0 (X11; Linux x86_64; rv:43.0) Gecko/20100101 Firefox/43.0 Build ID: 20151223140742 Steps to reproduce: Went here: http://codepen.io/CreativePunch/pen/sLizk Actual results: Get errors and the voices never show Expected results: Should have worked like Chrome
It appears there are no voices returned from speechSynthesis.getVoices()
Comment 2•8 years ago
|
||
See example section of https://developer.mozilla.org/en-US/docs/Web/API/SpeechSynthesis/onvoiceschanged. We don't support onvoiceschanged yet.
(In reply to Makoto Kato [:m_kato] from comment #2) > See example section of > https://developer.mozilla.org/en-US/docs/Web/API/SpeechSynthesis/ > onvoiceschanged. We don't support onvoiceschanged yet. But what does that have to do with not even having any voices? getVoices() returns null.
Comment 4•8 years ago
|
||
(In reply to donrhummy from comment #3) > (In reply to Makoto Kato [:m_kato] from comment #2) > > See example section of > > https://developer.mozilla.org/en-US/docs/Web/API/SpeechSynthesis/ > > onvoiceschanged. We don't support onvoiceschanged yet. > > But what does that have to do with not even having any voices? getVoices() > returns null. At first, http://codepen.io/CreativePunch/pen/sLizk doesn't work because onvoiceschanged isn't supproted. When you run (click display) the following JS on scratchpad, does it return 0? speechSynthesis.getVoices().length If so, it depends on OS configuration. If using Windows, you need config SAPI voices via old style control panel. Our implementation is SAPI only, so we cannot use Windows Store App's voices from Windows 8+ (bug 1235745).
(In reply to Makoto Kato [:m_kato] from comment #4) > When you run (click display) the following JS on scratchpad, does it return > 0? > > speechSynthesis.getVoices().length > Actually, the following code does nothing and it's considered the minimum to implement the API: var utterance = new SpeechSynthesisUtterance('Hello Treehouse'); window.speechSynthesis.speak(utterance); It runs without error but no sound occurs.
Comment 6•8 years ago
|
||
(In reply to donrhummy from comment #5) > (In reply to Makoto Kato [:m_kato] from comment #4) > > > When you run (click display) the following JS on scratchpad, does it return > > 0? > > > > speechSynthesis.getVoices().length > > > > Actually, the following code does nothing and it's considered the minimum to > implement the API: > > var utterance = new SpeechSynthesisUtterance('Hello Treehouse'); > window.speechSynthesis.speak(utterance); > > It runs without error but no sound occurs. So I think that your system has no voice system.
Comment 7•8 years ago
|
||
Check that speechd is installed, and kill it before starting Firefox to make sure it is not in a bad state.
I guess things have changed since then, but using only system voices, the voiceschanged
event actually fires the first time the domain is loaded.
Afterward, on reload or navigation, it's not fired anymore but the getVoices()
is already populated.
Chrome does fire that event every time, after the page's DOMContentLoaded
event fired. Would matching that behavior be an option?
Comment 9•2 years ago
|
||
voiceschanged
will only be fired when new voices are available. When a page is reloaded, or another page in the same domain/process is loaded the voices are available from the start so there is no need for the event. Here is an async voice getter that handles both first and subsequent page loads. It should work in all browsers:
async function getVoices() {
let voices = speechSymthesis.getVoices();
if (voices.length) return voices;
await new Promise(r => speechSynthesis.addEventListener("voiceschanged", r, { once: true }));
return speechSymthesis.getVoices();
}
Comment 10•2 years ago
|
||
I'm not saying that the current behavior is against the specs, I'm just wondering if it's the most user-friendly one.
Honestly, having to write such a boiler plate sounds problematic. I guess the API should have made a .ready
Promise available, but I fear that ship has already sailed.
Since Chrome does apparently "fake" the acquisition of the voices to make it async at every page load (getVoices().length
will always be 0
before DOMContentLoaded and the voiceschanged event will always fire), people have since written code that assume this behavior:
For instance this quite popular StackOverflow answer does assume Chrome's behavior.
And a quick search for "onvoiceschanged" on Github reveals that a lot of scripts currently do something like
public async getVoiceList(): Promise<SpeechSynthesisVoice[]> {
if ('onvoiceschanged' in speechSynthesis) {
await new Promise((resolve, reject) => {
this.speechSynthesis.addEventListener('voiceschanged', resolve);
});
}
return this.speechSynthesis.getVoices();
(excerpt from https://github.com/MrHassanKhan/nx-angular-nestjs/blob/master/libs/chat-box/src/lib/services/text-to-speech.service.ts)
This will work only the first time in Firefox, but every time in Chrome. That makes it very hard to catch even for tested code bases.
So once again, I'm wondering if it wouldn't be in Firefox's users' interest to actually follow Chrome's behavior here, and "lie" about the voices being available before page load.
Updated•2 years ago
|
Description
•