google-chrome - google - web speech api tutorial
Obteniendo la lista de voces en speechSynthesis of Chrome(Web Speech API) (7)
El siguiente HTML muestra una matriz vacía en la consola al hacer clic primero:
<!DOCTYPE html>
<html>
<head>
<script>
function test(){
console.log(window.speechSynthesis.getVoices())
}
</script>
</head>
<body>
<a href="#" onclick="test()">Test</a>
</body>
</html>
En un segundo clic obtendrás la lista esperada.
Si agrega el evento onload
para llamar a esta función ( <body onload="test()">
), entonces puede obtener el resultado correcto con el primer clic. Tenga en cuenta que la primera llamada de onload
todavía no funciona correctamente. Devuelve vacío en la carga de la página, pero funciona después.
Preguntas:
Dado que podría ser un error en la versión beta, abandoné las preguntas sobre "Por qué".
Ahora, la pregunta es si quieres acceder a window.speechSynthesis
en la carga de la página:
- ¿Cuál es el mejor truco para este problema?
- ¿Cómo puede asegurarse de que cargue
speechSynthesis
, en la carga de la página?
Antecedentes y pruebas:
Estaba probando las nuevas funciones en Web Speech API, luego llegué a este problema en mi código:
<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>
Mi pregunta era: ¿por qué window.speechSynthesis.getVoices()
devuelve una matriz vacía, después de que se carga la página y se onready
función de onready
? Como puede ver si hace clic en el enlace, la misma función devuelve una matriz de voces disponibles de Chrome mediante onclick
triger.
¡Parece que Chrome carga window.speechSynthesis
después de la carga de la página!
El problema no está en el evento ready
. Si elimino la línea var voice=...
de la función ready
, para el primer clic muestra la lista vacía en la consola. Pero el segundo clic funciona bien.
Parece que window.speechSynthesis
necesita más tiempo para cargarse después de la primera llamada. ¡Tienes que llamarlo dos veces! Pero también, debe esperar y dejar que se cargue antes de la segunda llamada en window.speechSynthesis
. Por ejemplo, el siguiente código muestra dos matrices vacías en la consola si la ejecuta por primera vez:
// First speechSynthesis call
var voices = window.speechSynthesis.getVoices();
console.log(voices);
// Second speechSynthesis call
voices = window.speechSynthesis.getVoices();
console.log(voices);
Al principio usé onvoiceschanged, pero siguió disparando incluso después de que las voces se cargaran, así que mi objetivo era evitar onvoiceschanged a toda costa.
Esto es lo que se me ocurrió. Parece funcionar hasta ahora, se actualizará si se rompe.
loadVoicesWhenAvailable();
function loadVoicesWhenAvailable() {
voices = synth.getVoices();
if (voices.length !== 0) {
console.log("start loading voices");
LoadVoices();
}
else {
setTimeout(function () { loadVoicesWhenAvailable(); }, 10)
}
}
De acuerdo con Web Speech API Errata (E11 2013-10-17), la lista de voz se carga de forma sincronizada a la página. Un evento onvoiceschanged
se dispara cuando se cargan.
voiceschanged: se activa cuando el contenido de SpeechSynthesisVoiceList, que devolverá el método getVoices, ha cambiado. Los ejemplos incluyen: síntesis del lado del servidor donde la lista se determina de forma asíncrona o cuando las voces del lado del cliente se instalan / desinstalan.
Entonces, el truco es configurar su voz a partir de la devolución de llamada para ese oyente de evento:
// wait on voices to be loaded before fetching list
window.speechSynthesis.onvoiceschanged = function() {
window.speechSynthesis.getVoices();
...
};
Otra forma de asegurarse de que las voces se carguen antes de que las necesite es vincular su estado de carga a una promesa, y luego enviar sus comandos de voz desde a then
:
const awaitVoices = new Promise(done => speechSynthesis.onvoiceschanged = done);
function listVoices() {
awaitVoices.then(()=> {
let voices = speechSynthesis.getVoices();
console.log(voices);
});
}
Cuando llame a listVoices
, o esperará a que las voces se carguen primero, o enviará su operación en el siguiente tic.
Primero, muchas gracias por esta respuesta. En segundo lugar, aquí hay un JSBin útil si alguien se encuentra con esta pregunta / respuesta de nuevo: http://jsbin.com/gosaqihi/9/edit?js,console
Puede usar setInterval para esperar hasta que se carguen las voces antes de usarlas como lo necesite y luego borrar el 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);
aquí está la respuesta
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);
});
}
La solución setInterval de Salman Oskooi fue perfecta
Por favor, consulte 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);
}
Esto funciona bien en Chrome para MAC, Linux (Ubuntu), Windows y Android
Android tiene en_GB no estándar wile otros tienen en-GB como código de idioma También verá que el mismo idioma (lang) tiene varios nombres
En Mac Chrome obtienes en-GB Daniel además de en-GB Google UK English Female y n-GB Google UK English Male
es-GB Daniel (Mac y iOS) en-GB Google Reino Unido Inglés Femenino es-GB Google UK English Male es_GB English United Kingdom hi-IN Google हिन्दी hi-IN Lekha (Mac y iOS) hi_IN Hindi India