StreamFlow — Estado 16/06/2026  (v3)
=====================================

⚠️ ANTES DE DESPLEGAR ESTE CÓDIGO EN TU SERVIDOR — placeholders a rellenar:

  1. admin.php
     ADMIN_PASS = 'CAMBIA_ESTO'
     → pon una contraseña real para el panel de administración.

  2. stream_common.php
     KILLALL_TOKEN = 'GENERA_UN_TOKEN_ALEATORIO_AQUI'
     → genera uno con: php -r "echo bin2hex(random_bytes(16));"

     FFMPEG = '/ruta/a/tu/ffmpeg'
     → ruta real de ffmpeg en tu hosting (compruébala con `which ffmpeg`
       o `whereis ffmpeg` por SSH, o mira el panel de tu hosting).

  3. Crontab (ver sección "CRONTAB DE SEGURIDAD" más abajo)
     → sustituye /ruta/a/tu/proyecto por la ruta real de tu cuenta.

  Sin estos 3 cambios el sitio no arrancará correctamente (ffmpeg no se
  encontrará) y el panel de admin y el botón de emergencia "matar
  procesos" quedarán con credenciales de ejemplo, no reales.

ARCHIVOS:
  index.html             — Estudio de mezcla (canvas multi-fuente)
  frameserver.php        — Backend PHP+ffmpeg v3 (grabación + HLS + Modo Mundial)
  frameserver-client.js  — Cliente JS v3 (batching, offscreen canvas)
  watch.php              — Visor HLS en vivo
  watch-mjpeg.php        — Visor "artesanal" (Modo Mundial, sin FIFO) + chat
  chat.php               — Chat en directo (público/privado) entre anfitrión y espectadores
  admin.php              — Panel de administración de sesiones
  stream_common.php      — Config y helpers compartidos (frameserver.php + worker)
  ffmpeg_worker.php      — Procesado ffmpeg por cron (único archivo con shell_exec)
  kill_zombies.php       — Mata procesos ffmpeg huérfanos (solo invocable internamente)

CARPETAS (deben existir en el servidor):
  sessions/              — Sesiones de grabación temporales
  recordings/            — MP4/WebM finales
  hls/                   — Segmentos HLS en vivo
  jobs/                  — Cola de trabajos para ffmpeg_worker.php

FFMPEG:
  Ruta: definida en stream_common.php → constante FFMPEG (ver placeholders arriba)

CRONTAB (añadir, sustituyendo la ruta por la tuya):
  */2 * * * * find /ruta/a/tu/proyecto/sessions -name "*.jpg" -mmin +3 -delete 2>/dev/null
  */2 * * * * find /ruta/a/tu/proyecto/sessions -name "*.pcm" -mmin +3 -delete 2>/dev/null
  * * * * *   /usr/bin/php /ruta/a/tu/proyecto/ffmpeg_worker.php >> /ruta/a/tu/proyecto/worker.log 2>&1

CAMBIOS v3 (16/06/2026):
  ✅ frameserver-client.js
     - Calidad JPEG: 0.82 → 0.55  (~100-150 KB/frame vs ~1.8 MB)
     - Resolución de envío: offscreen canvas 640×360 (independiente del canvas UI)
     - BATCHING: agrupa hasta 4 frames en un solo POST multipart
       → reduce peticiones HTTP en ~4x (1 batch cada ~500ms a 8fps)
     - Back-pressure: MAX_PENDING=2 POSTs en vuelo máximo
     - FPS recomendado para servidor: 8 (seleccionado por defecto)
     - Stats: muestra fps_real calculado con ventana deslizante

  ✅ frameserver.php
     - Nuevo endpoint ?action=batch: recibe N frames en 1 POST multipart
       → compatible con cliente v2 (action=frame sigue funcionando)
     - Contadores atómicos con flock() en meta.json
       → elimina race condition
     - GD: reescalado servidor si el cliente manda frames demasiado grandes
     - HLS: fopen() con polling de 3s para esperar a ffmpeg antes de fallar
     - HLS hls_frame: escritura en chunks de 64KB, descarte no-bloqueante
     - hls_time reducido: 4s → 2s (latencia HLS más baja)
     - hls_list_size: 10 → 6 (menos segmentos en memoria)
     - Modo Mundial (?action=start/frame/audio/live_publish/live_stop):
       HLS sin FIFO, vía frames-archivo — evita concurrencia de lectura/
       escritura simultánea. Genera host_token de sesión para el chat.
     - Sin shell_exec/exec/proc_open/popen en ningún momento — toda
       ejecución de ffmpeg vive únicamente en ffmpeg_worker.php (cron,
       nunca accesible por HTTP). Ver stream_common.php para el porqué.

  ✅ index.html
     - Selector FPS: 8fps marcado como recomendado para servidor
     - fsStart: pasa captureW=640, captureH=360, quality=0.55
     - hlsStart: usa offscreen canvas 640×360, quality=0.55, fps≤8
     - Stats panel: muestra fps_real y número de batches enviados
     - Modo Mundial: panel de chat flotante (anfitrión) — feed público +
       hilos privados por espectador, respuesta privada con un clic

  ✅ chat.php / watch-mjpeg.php (nuevo)
     - Chat de texto en vivo, público o privado (espectador ↔ anfitrión)
     - Autenticación del anfitrión vía host_token (nunca expuesto a
       espectadores), comparación en tiempo constante (hash_equals)
     - sessions/.htaccess bloquea el acceso HTTP directo a meta.json
       y chat.jsonl

FUNCIONA:
  ✅ Canvas multi-fuente (webcam, pantalla, vídeo, color, imagen, texto)
  ✅ Grabación en servidor → MP4 descargable (con batching)
  ✅ Color picker para fuente color sólido
  ✅ Modal de ayuda
  ✅ Admin panel con limpieza de sesiones
  ✅ Preview MJPEG
  ✅ Modo Mundial (HLS sin FIFO) con audio y chat en directo

PENDIENTE:
  ⏳ Transferencia de archivos en el chat (descartada por ahora, ver
     comentarios en chat.php)
  ⏳ Alternativa PaaS (Railway.app) para HLS si el hosting no tiene posix_mkfifo

DIAGNÓSTICO RÁPIDO:
  1. Abre /frameserver.php?action=status en el navegador
  2. Comprueba que ffmpeg: true y posix_mkfifo: true
  3. Si posix_mkfifo: false → el hosting no permite FIFOs → usar Railway para HLS
