1 puntos por GN⁺ 2025-12-24 | 1 comentarios | Compartir por WhatsApp
  • Helix es una plataforma de IA que muestra a los usuarios la pantalla donde operan agentes autónomos de programación en la nube, por lo que la transmisión remota de pantalla estable es fundamental
  • Cuando el streaming basado en WebRTC falló por el bloqueo de UDP y las restricciones de firewall en redes empresariales, el equipo construyó un pipeline H.264 sobre WebSocket, pero en Wi-Fi inestable aparecieron latencias severas
  • En lugar de una estructura compleja de codificación y decodificación, descubrieron que simplemente enviar capturas JPEG periódicamente por HTTP era mucho más estable y eficiente
  • Este enfoque usa menos ancho de banda, no requiere recuperación de cuadros dañados y ajusta automáticamente la calidad y la tasa de cuadros según la calidad de la red
  • Como resultado, Helix adoptó una arquitectura híbrida: H.264 con buena conexión y sondeo de JPEG con mala conexión, completando un sistema de streaming remoto simple pero práctico

El problema de streaming y las restricciones de Helix

  • Helix es una plataforma que debe compartir en tiempo real la pantalla de agentes de IA para programación que corren en sandboxes en la nube
    • Los usuarios observan cómo la IA escribe código, como si fuera un escritorio remoto
  • Al principio usaron WebRTC, pero la conexión fallaba por el bloqueo de UDP en redes empresariales
    • Los servidores TURN, STUN/ICE y los puertos personalizados eran bloqueados por las políticas de firewall
  • Por eso implementaron directamente un pipeline de streaming H.264 sobre WebSocket usando solo HTTPS (puerto 443)
    • Codificación por hardware con GStreamer + VA-API y decodificación en el navegador con WebCodecs
    • Alcanzaron 60fps, 40Mbps y menos de 100ms de latencia

Latencia de red y degradación del rendimiento

  • En entornos de red inestables, como cafeterías, surgieron problemas donde el video se congelaba o se retrasaba decenas de segundos
    • WebSocket basado en TCP provoca que, cuando hay pérdida de paquetes, los cuadros se retrasen en secuencia y se rompa el tiempo real
  • Bajar el bitrate no resolvía la latencia; solo empeoraba la calidad de imagen
  • También probaron enviar solo keyframes, pero falló porque el protocolo Moonlight requiere P-frames

El descubrimiento del método con capturas JPEG

  • Durante la depuración, al llamar al endpoint /screenshot?format=jpeg&quality=70, se cargó de inmediato una imagen nítida
    • Un solo JPEG de 150KB se mostraba sin latencia
  • Al simplemente repetir solicitudes HTTP para actualizar la captura, lograron una actualización de pantalla fluida de alrededor de 5fps
  • Finalmente abandonaron el pipeline de video complejo y cambiaron al método de solicitudes JPEG periódicas (bucle de fetch)

Ventajas del método JPEG

  • Principales puntos de comparación frente a H.264
    • Ancho de banda: H.264 fijo en 40Mbps, JPEG variable entre 100~500Kbps
    • Gestión de estado: H.264 depende del estado, JPEG usa cuadros completamente independientes
    • Recuperación: H.264 requiere esperar un keyframe, JPEG se recupera de inmediato con el siguiente cuadro
    • Complejidad: H.264 tomó meses de desarrollo; JPEG se implementó con unas pocas líneas de bucle fetch()
  • Cuanto peor es la calidad de la red, el método simple con JPEG resulta más estable y eficiente

Estructura híbrida de conmutación

  • Helix cambia automáticamente entre ambos métodos según el RTT (tiempo de ida y vuelta)
    1. RTT < 150ms → streaming H.264
    2. RTT > 150ms → sondeo JPEG
    3. Cuando la conexión se recupera, el usuario hace clic para volver a cambiar
  • Los eventos de entrada (teclado y mouse) siguen enviándose por WebSocket, para mantener la interactividad
  • El servidor detiene la transmisión de video y cambia al modo de capturas con el mensaje {"set_video_enabled": false}

Problema de inestabilidad en la conmutación (oscillation) y solución

  • Cuando se detiene la transmisión, el tráfico de WebSocket baja, la latencia mejora y se produce un bucle infinito en el que el sistema vuelve automáticamente al modo de video
  • Solución: una vez que entra en modo de capturas, permanece fijo hasta que el usuario haga clic
    • La UI muestra el mensaje “video pausado para ahorrar ancho de banda”

Problema de soporte JPEG y proceso de compilación

  • La herramienta de capturas para Wayland grim tiene el soporte JPEG desactivado en el paquete predeterminado de Ubuntu
    • Al ejecutar grim -t jpeg aparece el error “jpeg support disabled”
  • Para resolverlo, incluyeron libjpeg-turbo8-dev en el Dockerfile y compilaron grim directamente desde el código fuente

Arquitectura final

  • Buena conexión: H.264 a 60fps, con aceleración por hardware
  • Mala conexión: sondeo JPEG de 2~10fps, con confiabilidad total
  • La calidad de las capturas se ajusta automáticamente según el tiempo de transmisión
    • Si supera 500ms, calidad -10%; si baja de 300ms, +5%; manteniendo un mínimo de 2fps

Principales aprendizajes

  1. Una solución simple supera a un sistema complejo — 2 horas de hack con JPEG fueron más prácticas que 3 meses de desarrollo con H.264
  2. La degradación elegante (graceful degradation) es clave para la experiencia del usuario
  3. WebSocket es ideal para transmitir entrada, pero no es indispensable para video
  4. Los paquetes de Ubuntu pueden venir con funciones faltantes — si hace falta, hay que compilar directamente
  5. Medir antes de optimizar es esencial — el streaming complejo no es la única solución

Publicación como open source

  • Helix se ofrece como open source, y la implementación principal incluye
    • api/cmd/screenshot-server/main.go — servidor de capturas
    • MoonlightStreamViewer.tsx — lógica adaptativa del cliente
    • websocket-stream.ts — control de conmutación de video
  • Helix se está desarrollando con el objetivo de ser una infraestructura de IA que funcione también en entornos reales

1 comentarios

 
GN⁺ 2025-12-24
Comentarios de Hacker News
  • Cuando la red es mala, que JPEG se degrade no se debe a UDP sino a la forma en que se implementa TCP
    JPEG no resuelve los problemas de buffering ni de control de congestión. Lo más probable es que se haya implementado con una estructura que minimiza la transmisión de frames
    h.264 tiene una eficiencia de codificación mayor que JPEG. Con el mismo tamaño, un frame IDR de h.264 puede ofrecer mejor calidad
    El problema de fondo es la ausencia de estimación de ancho de banda. Incluso en un entorno TCP se puede ajustar el bitrate mediante sondeo inicial de ancho de banda y detección de retraso de transmisión
    Si es posible, es mejor usar WebRTC, y para evadir firewalls conviene usar WebSocket

    • En el código de polling del artículo, la siguiente solicitud solo se enviaba cuando terminaba de descargarse el JPEG anterior. Ese tipo de loop es posible incluso sin UDP
    • Probablemente la estructura serializaba por completo los frames para pedir solo uno a la vez, o abría una conexión nueva con cada GET
    • Lo interesante es que incluso un JPEG visualmente idéntico puede reducir su tamaño hasta alrededor de 10~15%. En trabajos de optimización de rendimiento web a fines de los 2000, mejorar así la eficiencia era muy gratificante
  • Incluso dejando de lado los problemas de formato del texto o su estilo de LLM, hay muchas cosas equivocadas en el contenido
    10Mbps debería ser suficiente para una pantalla estática. El problema es que la configuración de codificación está mal o que la calidad del encoder es baja
    El enfoque de “mandar solo keyframes” es ineficiente; en su lugar, bastaría con configurar un intervalo corto de keyframes
    Al final, el problema es la estructura de empujar todo el stream por una sola conexión TCP. Ya existen soluciones como DASH pensadas para este caso

    • No entiendo por qué suben tanto los textos escritos por IA. Leer algo hecho sin cuidado me parece una pérdida de tiempo
    • En Apple no se soporta DASH. HLS puede ser una alternativa, pero sin ffmpeg es muy difícil de implementar
    • Este texto más bien casi no tiene estilo de LLM. Una crítica sin fundamento no resulta convincente
    • Como el tiempo y costo de aprender las herramientas existentes es alto, incluso una “reinvención equivocada” puede ser más eficiente según la situación
  • Sería buena idea tomar como referencia lo que VNC viene haciendo desde 1998
    Mantiene el modelo de cliente que hace polling, pero divide el framebuffer en mosaicos y solo transmite las partes modificadas
    En una pantalla de código estática puede reducir mucho el ancho de banda. Si además detecta scroll, sería aún más eficiente

    • Entre varias propuestas, esta parece el punto de partida más realista. Tomar 40Mbps como base da la impresión de que el enfoque del problema ya estaba mal desde el principio
    • El texto me dio una impresión de inexperiencia. Me pregunto si este enfoque también se puede lograr con código abierto
    • Recomiendo mirar primero el proyecto neko. Maneja mucho mejor que VNC los problemas de latencia de conexión y backpressure
    • Replicar el enfoque de VNC parece el primer intento más natural. Usar una solución de baja latencia para juegos como Moonlight sería más bien inadecuado
  • Antes trabajé con codificación de video, y 40Mbps es calidad nivel Blu-ray
    Es excesivo para hacer streaming de texto simple. Tras hablarlo con Claude, la conclusión fue que 30FPS, GOP de 2 segundos y un promedio de 1Mbps serían suficientes
    Incluso en el peor caso, con 1.2Mbps se puede mantener una calidad bastante estable

  • El problema central de este texto es que configura demasiado alto el ancho de banda mínimo de h.264
    H.264 es mucho más eficiente que JPEG. Debieron empezar en 1Mbps e ir ajustando
    Usar solo keyframes es, de hecho, ineficiente

    • En el texto se dice “lo bajé a 10Mbps y aparecieron 30 segundos de retraso”, pero eso probablemente se deba a un problema de configuración del encoder
    • Incluso con JPEG, si se arma una cola de reproducción mediante buffering, se pueden aliviar los cortes. Hoy los reproductores monitorean en tiempo real la calidad de la red
  • Yo lo habría abordado de una forma totalmente distinta
    10Mbps es excesivo, y los videos de programación en YouTube andan alrededor de 0.6Mbps incluso en 1080p. Se ven suficientemente nítidos
    Preferiría bajar a 1fps o ajustar el intervalo de keyframes

    • El estilo y la forma de argumentar del texto huelen a LLM. El código probablemente esté al mismo nivel
    • 1fps podría no ser suficiente. Haría falta una configuración que convierta todos los frames en keyframes
    • Pero para algunas personas incluso la calidad de YouTube puede ser tan molesta que resulta insoportable
  • Hacer streaming de video en tiempo real al navegador es realmente doloroso
    Si las capturas JPEG funcionan bien, mejor dejarlas así
    Stacks como gstreamer o Moonlight son un infierno de depurar si no entiendes backpressure y propagación de errores
    Una alternativa realista es la combinación de NVIDIA Video Codec SDK + WebSocket + MediaSource Extensions
    Pero si el texto fue generado por un LLM, da la impresión de que el autor no tendría intención de entender esa estructura interna

    • Cuando hay que tratar un sistema tan complejo con un propósito único, un LLM puede ser útil precisamente por eso
  • Hace tiempo usé un programa que tomaba capturas de pantalla cada 5 segundos, y el disco duro se llenó enseguida
    Me di cuenta de que la mayoría de las imágenes eran iguales, y mientras pensaba en un algoritmo que guardara solo las partes cambiadas,
    terminé dándome cuenta de que estaba reinventando la compresión de video
    Lo resolví con una sola línea de ffmpeg y ahorré 98% de espacio de almacenamiento

  • Hacer streaming a 40Mbps de un video de un LLM tecleando es un ancho de banda anormalmente excesivo

    • Además, ver a 60fps “una computadora escribiendo” también es raro. Parece un enfoque que no entiende en absoluto el dominio del problema
  • La única forma de conseguir buenas respuestas en HN es publicar algo equivocado
    Creo que este es un ejemplo perfecto de ese equilibrio: un texto incorrecto, pero lo bastante interesante como para generar discusión