Obtenir la liste des voix dans la synthèse des discours de Chrome (API de discours Web))
le HTML suivant affiche le tableau vide dans la console au premier clic:
<!DOCTYPE html>
<html>
<head>
<script>
function test(){
console.log(window.speechSynthesis.getVoices())
}
</script>
</head>
<body>
<a href="#" onclick="test()">Test</a>
</body>
</html>
en second clic vous obtiendrez la liste attendue.
Si vous ajoutez onload
événement pour appeler cette fonction (<body onload="test()">
), alors vous pouvez obtenir le résultat correct sur le premier clic. Notez que le premier appel sur onload
ne fonctionne toujours pas correctement. Il retourne vide sur la page de chargement mais fonctionne après.
Questions:
Puisqu'il pourrait être un bug en version beta, j'ai abandonné les questions "Pourquoi".
maintenant, la question Est si vous voulez accéder à window.speechSynthesis
au chargement de la page:
- Quel est le meilleur hack pour cette question?
- Comment pouvez-vous vous assurer qu'il va charger
speechSynthesis
, au chargement de la page?
arrière-plan et tests:
j'ai testé les nouvelles fonctionnalités de L'API de discours Web, puis j'ai eu ce problème dans mon 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>
mon la question était: pourquoi ne window.speechSynthesis.getVoices()
retourner tableau vide, après la page est chargée et onready
la fonction est activée? Comme vous pouvez le voir si vous cliquez sur le lien, la même fonction renvoie un tableau des voix de Chrome disponibles par onclick
triger?
Il semble Chrome charges window.speechSynthesis
après le chargement de la page!
Le problème n'est pas dans ready
événement. Si je supprime la ligne var voice=...
ready
fonction, pour le premier clic il affiche la liste vide dans la console. Mais le deuxième clic fonctionne fin.
il semble window.speechSynthesis
besoin de plus de temps pour charger après le premier appel. Vous avez besoin de l'appeler deux fois! Mais aussi, vous devez attendre et le charger avant le deuxième appel sur window.speechSynthesis
. Par exemple, le code suivant affiche deux tableaux vides dans la console si vous l'exécutez pour la première fois:
// First speechSynthesis call
var voices = window.speechSynthesis.getVoices();
console.log(voices);
// Second speechSynthesis call
voices = window.speechSynthesis.getVoices();
console.log(voices);
8 réponses
Selon Web Speech API Errata (E11 2013-10-17), la liste vocale est chargée async à la page. onvoiceschanged
événement est déclenché lorsqu'ils sont chargés.
voiceschanged: Fired quand le contenu de la SpeechSynthesisVoiceList, que la méthode getVoices va revenir, ont changé. Exemples: synthèse côté serveur où la liste est déterminée de manière asynchrone, ou lorsque les voix côté client sont installées/désinstallées.
Donc, la truc est de mettre votre voix à partir de la fonction de rappel pour que l'écouteur d'événement:
// wait on voices to be loaded before fetching list
window.speechSynthesis.onvoiceschanged = function() {
window.speechSynthesis.getVoices();
...
};
Vous pouvez utiliser un setInterval pour attendre que les voix soient chargées avant de les utiliser comme vous en avez besoin et ensuite effacer le setInterval:
var timer = setInterval(function() {
var voices = speechSynthesis.getVoices();
console.log(voices);
if (voices.length !== 0) {
var msg = new SpeechSynthesisUtterance(/*some string here*/);
msg.voice = voices[/*some number here to choose from array*/];
speechSynthesis.speak(msg);
clearInterval(timer);
}
}, 200);
$("#test").on('click', timer);
Au début j'ai utilisé onvoiceschanged, mais il a continué à tirer même après que les voix aient été chargées, donc mon but était d'éviter onvoiceschanged à tout prix.
c'est Ce que je suis venu avec. Il semble fonctionner jusqu'à présent, sera mis à jour si elle casse.
loadVoicesWhenAvailable();
function loadVoicesWhenAvailable() {
voices = synth.getVoices();
if (voices.length !== 0) {
console.log("start loading voices");
LoadVoices();
}
else {
setTimeout(function () { loadVoicesWhenAvailable(); }, 10)
}
}
tout d'Abord, merci beaucoup pour cette réponse. Deuxièmement, voici un JSBin utile si quelqu'un tombe sur cette question/réponse à nouveau: http://jsbin.com/gosaqihi/9/edit?js, console
une autre façon de s'assurer que les voix sont chargées avant que vous en ayez besoin est de lier leur état de chargement à une promesse, puis d'envoyer vos commandes vocales à partir d'un then
:
const awaitVoices = new Promise(done => speechSynthesis.onvoiceschanged = done);
function listVoices() {
awaitVoices.then(()=> {
let voices = speechSynthesis.getVoices();
console.log(voices);
});
}
quand vous appelez listVoices
, il attendra que les voix se chargent en premier, ou envoyer votre opération sur le prochain TIC.
consultez https://jsfiddle.net/exrx8e1y/
function myFunction() {
dtlarea=document.getElementById("details");
//dtlarea.style.display="none";
dtltxt="";
var mytimer = setInterval(function() {
var voices = speechSynthesis.getVoices();
//console.log(voices);
if (voices.length !== 0) {
var msg = new SpeechSynthesisUtterance();
msg.rate = document.getElementById("rate").value; // 0.1 to 10
msg.pitch = document.getElementById("pitch").value; //0 to 2
msg.volume = document.getElementById("volume").value; // 0 to 1
msg.text = document.getElementById("sampletext").value;
msg.lang = document.getElementById("lang").value; //'hi-IN';
for(var i=0;i<voices.length;i++){
dtltxt+=voices[i].lang+' '+voices[i].name+'\n';
if(voices[i].lang==msg.lang) {
msg.voice = voices[i]; // Note: some voices don't support altering params
msg.voiceURI = voices[i].voiceURI;
// break;
}
}
msg.onend = function(e) {
console.log('Finished in ' + event.elapsedTime + ' seconds.');
dtlarea.value=dtltxt;
};
speechSynthesis.speak(msg);
clearInterval(mytimer);
}
}, 1000);
}
cela fonctionne très bien sur Chrome pour MAC, Linux (Ubuntu), Windows et Android
Android a un en_GB non standard tandis que d'autres ont un en-GB comme code de langue Vous verrez aussi que la même langue (lang) a plusieurs noms
sur Mac Chrome vous obtenez en-GB Daniel en plus en-GB Google UK Anglais féminin et n-GB Google anglais (royaume-UNI Hommes
FR-GB Daniel (Mac et iOS) en-GB Google UK Anglais Féminin en-GB Google UK Anglais masculin en_GB Anglais Royaume-Uni hi-in Google en Chine hi-IN Lekha (Mac et iOS)) hi_IN Hindi en Inde
heres la réponse
function synthVoice(text) {
const awaitVoices = new Promise(resolve=>
window.speechSynthesis.onvoiceschanged = resolve)
.then(()=> {
const synth = window.speechSynthesis;
var voices = synth.getVoices();
console.log(voices)
const utterance = new SpeechSynthesisUtterance();
utterance.voice = voices[3];
utterance.text = text;
synth.speak(utterance);
});
}
j'ai dû faire ma propre recherche pour cela afin de m'assurer que je l'ai bien compris, donc juste partager (n'hésitez pas à éditer).
Mon but est de:
- Obtenir une liste des voix disponibles sur mon appareil
- peupler un élément select avec ces voix (après qu'une page particulière se charge)
- utiliser un code facile à comprendre
la fonctionnalité de base est démontrée danslive officiel démo de:
https://github.com/mdn/web-speech-api/tree/master/speak-easy-synthesis
mais je voulais mieux le comprendre.
pour décomposer le sujet...
SpeechSynthesis
SpeechSynthesis
interface API de discours Web est le contrôleur interface pour le service de la parole; cela peut être utilisé pour récupérer informations sur les voix de synthèse disponible sur l'appareil, démarrer et pause discours, et d'autres commandes en plus.
onvoiceschanged
onvoiceschanged
propriété de l'SpeechSynthesis
interface représente un gestionnaire d'événements qui s'exécute lorsque la listeSpeechSynthesisVoice
objets qui seraient renvoyées par leSpeechSynthesis.getVoices()
la méthode a changé (lorsque lavoiceschanged
événement feu.)
Exemple
Si ma demande a simplement:
var synth = window.speechSynthesis;
console.log(synth);
console.log(synth.onvoiceschanged);
outils de développement Chrome console affiche:
Exemple B
si je change le code en:
var synth = window.speechSynthesis;
console.log("BEFORE");
console.log(synth);
console.log(synth.onvoiceschanged);
console.log("AFTER");
var voices = synth.getVoices();
console.log(voices);
console.log(synth);
console.log(synth.onvoiceschanged);
les états avant et après sont les mêmes, et voices
est un tableau vide.
Solution
Bien que je ne suis pas confiant la mise en œuvre de Promesses, le suivant a fonctionné pour moi:
Définition de la fonction
var synth = window.speechSynthesis;
// declare so that values are accessible globally
var voices = [];
function set_up_speech() {
return new Promise(function(resolve, reject) {
// get the voices
var voices = synth.getVoices();
// get reference to select element
var $select_topic_speaking_voice = $("#select_topic_speaking_voice");
// for each voice, generate select option html and append to select
for (var i = 0; i < voices.length; i++) {
var option = $("<option></option>");
var suffix = "";
// if it is the default voice, add suffix text
if (voices[i].default) {
suffix = " -- DEFAULT";
}
// create the option text
var option_text = voices[i].name + " (" + voices[i].lang + suffix + ")";
// add the option text
option.text(option_text);
// add option attributes
option.attr("data-lang", voices[i].lang);
option.attr("data-name", voices[i].name);
// append option to select element
$select_topic_speaking_voice.append(option);
}
// resolve the voices value
resolve(voices)
});
}
Appel de la fonction
// in your handler, populate the select element
if (page_title === "something") {
set_up_speech()
}