Pantalla TV: el llamado por voz salía entrecortado y con retraso
El troceo lo causaba el keepalive del sintetizador: corría cada 10 segundos sin verificar si estaba hablando, y pause() a mitad de frase la corta. Como un anuncio con nombre y destino supera los 10 segundos, lo alcanzaba siempre. Ahora solo actúa con el sintetizador en reposo, que es para lo que existe: evitar que Chrome lo suspenda tras un rato sin uso. El cartel se cerraba a los 5 segundos aunque la voz siguiera sonando, y al cerrarse pasaba al siguiente de la cola, que cancelaba el anuncio en curso. Si dos pacientes se llamaban seguido, el primero quedaba a media frase. Ahora se cierra cuando terminó de hablar y se cumplió el mínimo visual, con una red de seguridad por si el navegador no emite el evento de fin. Sobre la demora: se quita la espera fija de 300 ms antes de hablar —solo se mantiene, y reducida, cuando de verdad hay que cancelar algo en curso— y el sondeo baja de 2 s a 1 s. El retraso desde el clic pasa de 0,3–2,3 s a 0–1 s. La velocidad sube de 0.85 a 0.95: acorta el anuncio sin perder claridad. Validado con una simulación del reloj y del sintetizador: reproduce el corte con el código anterior y no ocurre con el nuevo. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
c00faa2b06
commit
4bc22bd00c
@@ -558,8 +558,12 @@ function getVozES() {
|
||||
}
|
||||
if ('speechSynthesis' in window) {
|
||||
window.speechSynthesis.onvoiceschanged = () => { _vozES = null; getVozES(); };
|
||||
// Keepalive: Chrome pausa speechSynthesis tras ~15 min — correr siempre, no solo cuando !speaking
|
||||
// Keepalive: Chrome suspende speechSynthesis tras un rato sin uso.
|
||||
// Solo debe correr con el sintetizador en reposo: pause() a mitad de una
|
||||
// frase la corta, y como el anuncio dura más de 10 segundos, antes lo
|
||||
// troceaba siempre.
|
||||
setInterval(() => {
|
||||
if (window.speechSynthesis.speaking || window.speechSynthesis.pending) return;
|
||||
window.speechSynthesis.pause();
|
||||
window.speechSynthesis.resume();
|
||||
}, 10000);
|
||||
@@ -582,8 +586,17 @@ function anunciarTurno(codigo, destino, paciente) {
|
||||
utt.lang = 'es-CO';
|
||||
const voz = getVozES();
|
||||
if (voz) utt.voice = voz;
|
||||
utt.rate = 0.85; utt.pitch = 1.05; utt.volume = 1;
|
||||
setTimeout(() => { window.speechSynthesis.cancel(); window.speechSynthesis.speak(utt); }, 300);
|
||||
utt.rate = 0.95; utt.pitch = 1.05; utt.volume = 1;
|
||||
|
||||
// Con el sintetizador libre se habla de inmediato. Solo cuando hay algo en
|
||||
// curso hace falta cancelar y esperar un instante: Chrome ignora un speak()
|
||||
// encadenado a un cancel() en el mismo ciclo.
|
||||
if (window.speechSynthesis.speaking || window.speechSynthesis.pending) {
|
||||
window.speechSynthesis.cancel();
|
||||
setTimeout(() => window.speechSynthesis.speak(utt), 80);
|
||||
} else {
|
||||
window.speechSynthesis.speak(utt);
|
||||
}
|
||||
return utt;
|
||||
}
|
||||
|
||||
@@ -645,9 +658,24 @@ function showAnnouncement({ codigo, destino, paciente, color }) {
|
||||
ov.classList.remove('visible');
|
||||
setTimeout(processQueue, 370);
|
||||
}
|
||||
// Cierra al terminar el TTS; mínimo 5s visual
|
||||
if (utt) utt.addEventListener('end', () => setTimeout(dismiss, 500));
|
||||
setTimeout(dismiss, 5000);
|
||||
|
||||
// El cartel se cierra cuando terminó de hablar Y se cumplió el mínimo
|
||||
// visual. Cerrar a los 5 s sin esperar la voz hacía que el siguiente
|
||||
// llamado cancelara al anterior a media frase.
|
||||
const MIN_VISIBLE = 5000;
|
||||
const abiertoEn = Date.now();
|
||||
const cerrarCuandoToque = () => {
|
||||
setTimeout(dismiss, Math.max(0, MIN_VISIBLE - (Date.now() - abiertoEn)));
|
||||
};
|
||||
|
||||
if (utt) {
|
||||
utt.addEventListener('end', () => setTimeout(cerrarCuandoToque, 400));
|
||||
utt.addEventListener('error', cerrarCuandoToque);
|
||||
// Red de seguridad: Chrome a veces no emite 'end' y el cartel quedaría fijo
|
||||
setTimeout(dismiss, 25000);
|
||||
} else {
|
||||
setTimeout(dismiss, MIN_VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
/* ── State ── */
|
||||
@@ -797,7 +825,8 @@ async function cargarSnapshot() {
|
||||
}
|
||||
|
||||
cargarSnapshot();
|
||||
setInterval(cargarSnapshot, 2000);
|
||||
// 1 s en vez de 2: el llamado salía con hasta 2 s de retraso desde el clic
|
||||
setInterval(cargarSnapshot, 1000);
|
||||
|
||||
document.addEventListener('visibilitychange', () => { if (!document.hidden) cargarSnapshot(); });
|
||||
window.addEventListener('focus', cargarSnapshot);
|
||||
|
||||
Reference in New Issue
Block a user