// docs / websocket-obs

WebSocket y OBS

LiveAudio levanta un servidor WebSocket local que emite subtítulos en JSON en tiempo real. OBS es el destino integrado mediante el overlay incluido subtitulos_obs.html, pero cualquier cliente HTML o WebSocket en localhost puede conectarse y recibir la misma transmisión.

Detalles del servidor

ParámetroValor
ProtocoloWebSocket (ws://)
Host127.0.0.1 (solo localhost)
Puerto8765 por defecto, configurable con ws_port
FormatoJSON
AutenticaciónNinguna — limitado a localhost

Esquema del payload JSON

subtitle.json
{
  "id": "1760000000000-12",
  "text": "Hola a todos, bienvenidos al stream",
  "style": "default",
  "created_at": 1760000000.0,
  "processed_at": 1760000001.3,
  "queue_delay": 0.2,
  "total_delay": 1.3,
  "latency": 1.1,
  "is_replay": false,
  "catchup_interval_sec": 0.0
}
CampoTipoDescripción
idstringIdentificador estable de la frase dentro de la sesión.
textstringTexto transcrito, luego del filtro de blacklist.
stylestringEstilo visual: default, karaoke, neon, minimal, bold, rgb, typewriter.
created_atnumberTimestamp de creación del segmento de audio.
processed_atnumberTimestamp al terminar la transcripción.
queue_delaynumberSegundos que el audio esperó antes de entrar al motor ASR.
total_delaynumberAtraso total desde la captura hasta el subtítulo listo (de sub-segundo a ~1 s en un equipo típico).
latencynumberSegundos que Whisper usó para transcribir el segmento.
is_replaybooleanSi es un subtítulo de backlog / catch-up.
catchup_interval_secnumberPacing recomendado entre ítems de backlog en modo auto.

El overlay de OBS integrado solo consume text y style. Los demás campos son metadata para diagnóstico y control de backlog — útiles si construyes tu propio cliente, ignorables si no.

Estilos de subtítulos

El campo style selecciona uno de siete looks integrados, conmutables desde la pestaña Subtítulos:

EstiloAspecto
defaultTexto blanco sobre fondo negro semitransparente, fade suave de entrada/salida.
karaokeLas palabras aparecen escalonadas con animación popIn; amarillo brillante con contorno negro.
neonGlow cian, mayúsculas, espaciado amplio.
minimalSin fondo, fade sutil — para streams con diseño propio.
boldTexto grueso de alto contraste, animación rápida, presencia fuerte en pantalla.
rgbCada palabra toma un color distinto del arcoíris.
typewriterLas palabras se escriben una por una con cursor parpadeante; monoespaciado.

Política de backlog en OBS

La política de backlog controla solo lo que se muestra en vivo en OBS. Todo lo válido siempre se guarda en disco, sin importar la política.

ModoValor de configComportamiento
AutoautoEnvía subtítulos frescos más un backlog corto con pacing. Omite lo que supere el atraso máximo.
Solo en vivolive_onlyGuarda todo; solo muestra lo que está dentro de subtitle_max_live_delay_sec.
Enviar todosend_allEnvía todo a OBS aunque llegue tarde.

Seguridad

  • Solo localhost — el servidor rechaza cualquier conexión que no sea de 127.0.0.1, ::1 o localhost.
  • No requiere autenticación, porque está limitado a localhost.
  • Broadcast — múltiples clientes reciben los mismos mensajes a la vez.

Configurar el Browser Source de OBS

  • En OBS, Fuentes → + → Navegador.
  • Elige Archivo local y selecciona subtitulos_obs.html (en liveaudio/assets/). Tamaño 1920×200.
  • Pon los FPS en 30 o 60 y ubica la fuente en la parte inferior central de la escena.
  • Desactiva "Apagar la fuente cuando no esté visible" y "Actualizar el navegador cuando la escena se active" — ambas pueden cortar la conexión WebSocket.
  • Para un puerto personalizado, configura ws_port en config.json; el HTML de OBS lee ?port=XXXX de su URL (default 8765).

Comportamiento de la conexión

  • Reconexión. Un cliente que pierde la conexión reintenta cada 3 segundos aproximadamente hasta que el servidor vuelve — el overlay incluido ya lo hace por ti.
  • Broadcast. Cada cliente conectado recibe cada mensaje. Varios clientes (OBS más una pestaña de depuración) ven el mismo flujo, y un cliente lento no bloquea a los demás.
  • Sin backpressure. Con websockets ≥ 16 el servidor usa broadcast(), que reparte sin esperar a ningún cliente en particular.

Construir tu propio cliente

Cualquier cliente WebSocket en localhost puede suscribirse a la misma transmisión que lee OBS. Un cliente mínimo en navegador — ábrelo directamente, o cárgalo como Browser Source en OBS:

client.html
<!-- open this file in a browser, or load it as an OBS Browser Source -->
<div id="caption"></div>
<script>
  // ?port=XXXX overrides the default; matches ws_port in config.json
  const port = new URLSearchParams(location.search).get("port") || "8765";
  let ws;
  function connect() {
    ws = new WebSocket("ws://127.0.0.1:" + port);
    ws.onmessage = (e) => {
      const msg = JSON.parse(e.data);       // the subtitle payload
      document.getElementById("caption").textContent = msg.text;
    };
    // the server only broadcasts — reconnect every 3 s if it drops
    ws.onclose = () => setTimeout(connect, 3000);
  }
  connect();
</script>

O un cliente mínimo en Python, para imprimir cada payload a medida que llega (requiere el paquete websockets):

ws_client.py
import asyncio, websockets

async def test():
    async with websockets.connect("ws://127.0.0.1:8765") as ws:
        async for msg in ws:
            print(msg)

asyncio.run(test())

Señales de depuración

Abre el overlay en un navegador y presiona F12 → Consola. Estos mensajes indican dónde se traba un overlay que no muestra nada:

Mensaje en consolaSignificado
Conectado al motor ASRConexión exitosa — el WebSocket está activo.
Desconectado. Reintentando…No conecta: LiveAudio no está iniciado, el puerto está ocupado, o el ?port= de la URL no coincide con ws_port.
Error parseando WebSocketLlegó al overlay un mensaje que no es JSON / no es un dict — el payload no era un objeto de subtítulo válido.