diff --git a/modules/turnero/views/display_global.php b/modules/turnero/views/display_global.php index aaa65f7..a3eb8fa 100644 --- a/modules/turnero/views/display_global.php +++ b/modules/turnero/views/display_global.php @@ -663,26 +663,30 @@ function anunciarTurno(codigo, destino, paciente, onFin) { let avisado = false; const avisar = () => { if (!avisado) { avisado = true; onFin(); } }; - const decir = (voz, esReintento) => { + const decir = (esReintento) => { const utt = new SpeechSynthesisUtterance(texto); utt.lang = 'es-CO'; - if (voz) utt.voice = voz; utt.rate = 0.95; utt.pitch = 1.05; utt.volume = 1; let arranco = false; utt.addEventListener('start', () => { arranco = true; }); utt.addEventListener('end', avisar); - utt.addEventListener('error', () => esReintento ? avisar() : decir(null, true)); + utt.addEventListener('error', () => esReintento ? avisar() : decir(true)); // Que speak() no lance nada no significa que vaya a sonar: si el // navegador bloquea el audio, o la voz no sirve, no pasa absolutamente // nada y 'error' tampoco llega. Solo se nota porque 'start' no ocurre. - const margen = (esReintento ? 0 : BEEP_MS) + 1200; + const margen = (esReintento ? 0 : BEEP_MS) + 2500; setTimeout(() => { if (arranco) return; + // Antes de darla por fallida hay que preguntarle al sintetizador: + // una voz remota tarda en arrancar porque se baja de internet, y + // cancelarla aquí era cortarle la frase y repetirla con otra voz. + // De ahí que a veces se oyera media frase y luego otra distinta. + if (window.speechSynthesis.speaking || window.speechSynthesis.pending) return; if (esReintento) { avisar(); return; } window.speechSynthesis.cancel(); - decir(null, true); // segunda oportunidad, con la voz del navegador + decir(true); // segunda oportunidad, con la voz del navegador }, margen); // Solo cuando hay algo en curso hace falta cancelar: Chrome ignora un @@ -690,10 +694,21 @@ function anunciarTurno(codigo, destino, paciente, onFin) { if (window.speechSynthesis.speaking || window.speechSynthesis.pending) { window.speechSynthesis.cancel(); } - setTimeout(() => window.speechSynthesis.speak(utt), esReintento ? 0 : BEEP_MS); + setTimeout(() => { + // La voz se elige aquí y no al crear el anuncio: el navegador carga + // la lista de forma asíncrona, y en los primeros llamados tras abrir + // la página todavía venía vacía. Entonces no se asignaba voz y + // hablaba la del navegador —de ahí que a veces sonara un hombre y a + // veces una mujer—. A esta altura ya está cargada. + if (!esReintento) { + const voz = getVozES(); + if (voz) utt.voice = voz; + } + window.speechSynthesis.speak(utt); + }, esReintento ? 0 : BEEP_MS); }; - decir(getVozES(), false); + decir(false); return true; }