Hola a todos, es mi primera vez contribuyendo, así que perdonad si no estoy utilizando el formato adecuado.
Estoy configurando un foro de Discourse para un grupo de entusiastas del automóvil y querían usar chats de vídeo en directo mediante LiveKit para salas/presentaciones más grandes.
Durante las pruebas nos encontramos constantemente con casillas negras para las transmisiones de vídeo, pero solo cuando se usaba la integración de LiveKit. Usé Claude Code para investigarlo y encontré lo que parece ser el problema y una solución. A continuación, se incluye el informe generado por Claude.
Estaré encantado de crear una solicitud de extracción (PR) con una corrección propuesta si eso fuera útil.
Resumen
En una sala de LiveKit (SFU), al pasar de la página de la sala al widget de llamada flotante, el espectador se queda con casillas negras para los demás participantes. Los otros participantes siguen viendo al espectador sin problemas. Volver a la página de la sala, o salir y volver a entrar mientras se está en el widget, restaura el vídeo. Ocurre todas las veces, porque el cierre de la página de la sala envía watching=false después de que el widget haya enviado watching=true.
Versión
- Discourse en el commit
1f09a33bffd908d6e38ef4b51697e8390e2a4c7f(la ramalatest, octubre de 2026), el complemento Live incluido como se distribuye - LiveKit Cloud como servidor multimedia (
live_livekit_room_policy = per_room) - Firefox 159 en Linux (también observado en otros navegadores y teléfonos)
Pasos
- Dos cuentas (una en una ventana privada) se unen a la misma sala habilitada para LiveKit con las cámaras activadas.
- En una ventana, haga clic en un enlace que abandone la página de la sala, de modo que la llamada se mueva al widget.
- En esa ventana, la casilla del otro participante está negra. La otra ventana los ve a ambos sin problemas.
Lo que observé
- En la ventana con la casilla negra, el elemento
<video>de la otra persona tiene un stream, no está pausado y tienereadyState4. Pero su pista tienereadyState: "live",muted: true, resolución8×8, ygetVideoPlaybackQuality().totalVideoFrameses 0. Nunca llegó ningún contenido multimedia a ella. - Pestaña de red, cambio de página única → widget: tres llamadas
POST /live/rooms/<id>/state, conwatching= true, true, false en ese orden.
Causa (al leer el código en el commit anterior)
room-page.gjs,willDestroy:next(() => liveWebrtc.setWatching(roomId, false, { keepVideo }))call-widget.gjs: el métododidInsertdel widget llama awatchWidgetRoom, que ejecutanext(() => setWatching(roomId, true))live-webrtc.js,setWatching: en salas que no son de malla, llama asetVideoSubscriptionsEnabled(watching), que cancela las suscripciones del espectador a las pistas de cámara, pantalla y audio de pantalla (livekit-session.js,#applyDesiredSubscription)
El false diferido de la página llega después del true del widget, por lo que el espectador termina en el estado “no mirando” mientras el widget está en pantalla. Ir del widget a la página de la sala funciona porque stopWatchingWidgetRoom del widget se ejecuta de forma sincrónica en el destroy y el true de la página está diferido, por lo que true gana. Una unión nueva en el widget funciona porque no hay una página anterior.
Las salas de par a par no cancelan las suscripciones de nadie (la rama SFU se omite), lo que coincide con que este problema sea específico de las salas de LiveKit.
Solución alternativa confirmada, en la consola del navegador
- Con la casilla negra,
Discourse.__container__.lookup("service:live-webrtc").setWatching(1, true)restauró el vídeo. - Este envoltorio, instalado antes de cambiar, mantuvo la casilla activa en cada cambio de página → widget:
const svc = Discourse.__container__.lookup("service:live-webrtc");
const orig = svc.setWatching.bind(svc);
svc.setWatching = (roomId, watching, options = {}) => {
if (watching) return orig(roomId, true, options);
setTimeout(() => {
const shown = document.querySelector(".live-call-widget, .live-room-page");
orig(roomId, !!shown, options);
}, 500);
};
Corrección sugerida
El cierre de la página de la sala no debería desactivar “watching” cuando el widget está a punto de mostrar la misma sala. Por ejemplo, derive el estado de “watching” de si la página o el widget están montados, en lugar de permitir que cada uno envíe su propia configuración/borrado. De esa manera, el orden no importa.
Relacionado, puede ser un tema aparte
Una llamada POST .../state en la misma sesión recibió una respuesta 429. Las fallas en estas llamadas se ignoran (.catch(() => {})), por lo que una actualización de “watching” rechazada falla silenciosamente.