Getting the list of voices in speechSynthesis (Web Speech API)
dom-events, speech-synthesis, voice, webspeech-api
Solution
According to Web Speech API Errata (E11 2013-10-17), the voice list is loaded async to the page. An `onvoiceschanged` event is fired when they are loaded.
voiceschanged: Fired when the contents of the SpeechSynthesisVoiceList, that the getVoices method will return, have changed. Examples include: server-side synthesis where the list is determined asynchronously, or when client-side voices are installed/uninstalled.
So, the trick is to set your voice from the callback for that event listener:
// wait on voices to be loaded before fetching list
window.speechSynthesis.onvoiceschanged = function() {
window.speechSynthesis.getVoices();
...
};
Problem
Following HTML shows empty array in console on first click: ``` <!DOCTYPE html> <html> <head> <script> function test(){ console.log(window.speechSynthesis.getVoices()) } </script> </head> <body> <a href="#" onclick="test()">Test</a> </body> </html> ``` In second click you will get the expected list. If you add `onload` event to call this function (`<body onload="test()">`), then you can get correct result on first click. Note that the first call on `onload` still doesn't work properly. It returns empty on page load but works afterward. Questions: Since it might be a bug in beta version, I gave up on "Why" questions. Now, the question is if you want to access `window.speechSynthesis` on page load: - What is the best hack for this issue? - How can you make sure it will load `speechSynthesis`, on page load? Background and tests: I was testing the new features in Web Speech API, then I got to this problem in my code: ``` <script type="text/javascript"> $(document).ready(function(){ // Browser support messages. (You might need Chrome 33.0 Beta) if (!('speechSynthesis' in window)) { alert("You don't have speechSynthesis"); } var voices = window.speechSynthesis.getVoices(); console.log(voices) // [] $("#test").on('click', function(){ var voices = window.speechSynthesis.getVoices(); console.log(voices); // [SpeechSynthesisVoice, ...] }); }); </script> <a id="test" href="#">click here if 'ready()' didn't work</a> ``` My question was: why does `window.speechSynthesis.getVoices()` return empty array, after page is loaded and `onready` function is triggered? As you can see if you click on the link, same function returns an array of available voices of Chrome by `onclick` triger? It seems Chrome loads `window.speechSynthesis` after the page load! The problem is not in `ready` event. If I remove the line `var voice=...` from `ready` function, for first click it shows empty list in console. But the second click works fine. It seems `window.speechSynthesis` needs more time to load after first call. You need to call it twice! But also, you need to wait and let it load before second call on `window.speechSynthesis`. For example, following code shows two empty arrays in console if you run it for first time: ``` // First speechSynthesis call var voices = window.speechSynthesis.getVoices(); console.log(voices); // Second speechSynthesis call voices = window.speechSynthesis.getVoices(); console.log(voices); ```