diff --git a/api/lab/get_tv_log.php b/api/lab/get_tv_log.php index da17270..0fdbbdf 100644 --- a/api/lab/get_tv_log.php +++ b/api/lab/get_tv_log.php @@ -18,7 +18,7 @@ $resumen = $pdo->query( // Últimos incidentes (lo normal —start/end— no se lista: solo lo que falló) $stmt = $pdo->query( "SELECT evento, detalle, created_at FROM turnero_tv_log - WHERE evento IN ('mudo', 'sin_start', 'error') + WHERE evento IN ('mudo', 'sin_start', 'error', 'lag') ORDER BY id DESC LIMIT 30" ); $incidentes = []; diff --git a/lab_actividad.php b/lab_actividad.php index 224f31a..8ce9bba 100644 --- a/lab_actividad.php +++ b/lab_actividad.php @@ -294,6 +294,7 @@ const VOZ_EVENTO_TXT = { mudo: ['🔇 No sonó', 'text-danger', 'El llamado salió sin voz: ni el reintento habló'], sin_start: ['⚠️ Arrancó con reintento','text-warning','La voz elegida no arrancó; habló la del navegador'], error: ['⚠️ Error del motor', 'text-warning', 'El motor de voz falló a mitad; se reintentó'], + lag: ['⏸ Pantalla congelada', 'text-warning', 'La pestaña estuvo oculta o el equipo suspendido: en ese lapso no ve llamados. En el televisor debe estar siempre visible'], }; async function cargarVozTV() { diff --git a/modules/turnero/api/log_tv.php b/modules/turnero/api/log_tv.php index 37a84e7..19b65f8 100644 --- a/modules/turnero/api/log_tv.php +++ b/modules/turnero/api/log_tv.php @@ -26,7 +26,7 @@ $d = json_decode($raw, true); if (!is_array($d)) exit; $evento = $d['e'] ?? ''; -$PERMITIDOS = ['start', 'end', 'error', 'sin_start', 'mudo']; +$PERMITIDOS = ['start', 'end', 'error', 'sin_start', 'mudo', 'lag']; if (!in_array($evento, $PERMITIDOS, true)) exit; unset($d['e'], $d['t']); // el timestamp lo pone la base, no el cliente diff --git a/modules/turnero/views/display_global.php b/modules/turnero/views/display_global.php index 4c2886b..70214c2 100644 --- a/modules/turnero/views/display_global.php +++ b/modules/turnero/views/display_global.php @@ -667,6 +667,21 @@ const _uttAncladas = new Set(); // handlers no deben hacer nada más que soltar el anclaje. let _vozGen = 0; +// Vigía de congelamiento: Chrome frena los relojes de una pestaña oculta a ~1 +// tic por minuto. En ese estado la pantalla NO VE los llamados intermedios y +// no anuncia — y desde afuera parece un fallo de la voz. Si entre dos tics +// pasan más de 10 s, se deja constancia con el tamaño del hueco. +let _ultimoTic = Date.now(); +setInterval(() => { + const ahora = Date.now(); + const hueco = ahora - _ultimoTic; + _ultimoTic = ahora; + if (hueco > 10000) vozLog('lag', { gap_s: Math.round(hueco / 1000) }); +}, 2000); +document.addEventListener('visibilitychange', () => { + if (document.hidden) vozLog('lag', { oculta: 1 }); +}); + // ── Bitácora de la voz ── // Los fallos intermitentes no se pueden depurar mirando la pantalla: hay que // registrarlos cuando ocurren. Cada evento va a un anillo local (últimos 200,