1 Punkte von GN⁺ 2025-12-24 | Noch keine Kommentare. | Auf WhatsApp teilen
  • Helix ist eine AI-Plattform, die Nutzern den Bildschirm autonomer Coding-Agenten in der Cloud zeigt; stabile Remote-Bildübertragung ist dabei entscheidend
  • Als WebRTC-basiertes Streaming an UDP-Sperren und Firewall-Beschränkungen in Unternehmensnetzwerken scheiterte, baute das Team eine WebSocket-basierte H.264-Pipeline auf, doch in instabilen WLAN-Umgebungen kam es zu massiver Latenz
  • Statt einer komplexen Encoding-/Decoding-Struktur stellte sich heraus, dass das einfache periodische Übertragen von JPEG-Screenshots per HTTP deutlich stabiler und effizienter war
  • Dieser Ansatz verbraucht weniger Bandbreite, benötigt keine Wiederherstellung beschädigter Frames und passt Bildqualität und Framerate automatisch an die Netzwerkqualität an
  • Helix entschied sich schließlich für eine hybride Architektur: bei guten Verbindungen H.264, bei schlechten Verbindungen JPEG-Polling – ein simples, aber praxisnahes Remote-Streaming-System

Die Streaming-Probleme und Einschränkungen von Helix

  • Helix ist eine Plattform, die den Bildschirm eines AI-Coding-Agenten, der in einer Cloud-Sandbox läuft, in Echtzeit teilen muss
    • Nutzer verfolgen dabei wie bei einem Remote-Desktop, wie die AI Code schreibt
  • Anfangs wurde WebRTC verwendet, doch Verbindungen scheiterten an der UDP-Blockierung in Unternehmensnetzwerken
    • TURN-Server, STUN/ICE und benutzerdefinierte Ports wurden allesamt von Firewall-Richtlinien blockiert
  • Deshalb wurde eine WebSocket-basierte H.264-Streaming-Pipeline, die ausschließlich HTTPS (Port 443) nutzt, direkt selbst implementiert
    • Hardware-Encoding mit GStreamer + VA-API, Browser-Decoding mit WebCodecs
    • Erreicht wurden 60fps, 40Mbps und weniger als 100ms Latenz

Netzwerklatenz und Leistungsabfall

  • In instabilen Netzwerkumgebungen wie Cafés kam es dazu, dass das Bild stehen blieb oder um mehrere Dutzend Sekunden verzögert war
    • Das TCP-basierte WebSocket führt bei Paketverlust dazu, dass sich Frames der Reihe nach verzögern und dadurch die Echtzeitfähigkeit zusammenbricht
  • Auch eine niedrigere Bitrate löste das Latenzproblem nicht, sondern verschlechterte nur die Bildqualität
  • Es wurde auch versucht, nur Keyframes zu senden, doch das scheiterte, weil das Moonlight-Protokoll P-Frames voraussetzt

Entdeckung des JPEG-Screenshot-Ansatzes

  • Beim Debugging wurde der Endpunkt /screenshot?format=jpeg&quality=70 aufgerufen, woraufhin sofort ein scharfes Bild geladen wurde
    • Ein einzelnes JPEG mit 150KB wurde ohne Verzögerung angezeigt
  • Durch einfaches wiederholtes Senden von HTTP-Anfragen zur Aktualisierung des Screenshots war eine flüssige Bildschirmaktualisierung auf dem Niveau von 5fps möglich
  • Am Ende wurde die komplexe Video-Pipeline durch einen periodischen JPEG-Request-Ansatz (fetch loop) ersetzt

Vorteile des JPEG-Ansatzes

  • Wichtige Vergleichspunkte gegenüber H.264
    • Bandbreite: H.264 konstant 40Mbps, JPEG variabel zwischen 100~500Kbps
    • Zustandsverwaltung: H.264 ist zustandsabhängig, JPEG sind vollständig unabhängige Frames
    • Wiederherstellbarkeit: H.264 muss auf Keyframes warten, JPEG erholt sich sofort mit dem nächsten Frame
    • Komplexität: H.264 erforderte monatelange Entwicklung, JPEG ließ sich mit ein paar Zeilen fetch()-Loop implementieren
  • Je schlechter die Netzwerkqualität, desto stabiler und effizienter erwies sich der einfache JPEG-Ansatz

Hybride Umschaltarchitektur

  • Helix schaltet die beiden Verfahren automatisch anhand der RTT (Round-Trip Time) um
    1. RTT < 150ms → H.264-Streaming
    2. RTT > 150ms → JPEG-Polling
    3. Bei wiederhergestellter Verbindung kann der Nutzer per Klick zurückwechseln
  • Eingabeereignisse (Tastatur/Maus) werden weiterhin per WebSocket übertragen, sodass die Interaktivität erhalten bleibt
  • Der Server stoppt die Videoübertragung mit der Nachricht {"set_video_enabled": false} und wechselt in den Screenshot-Modus

Problem mit instabilem Umschalten (Oscillation) und Lösung

  • Wenn nach dem Stoppen der Übertragung der WebSocket-Traffic sinkt, fällt auch die Latenz – dadurch entstand eine Endlosschleife, in der automatisch wieder in den Videomodus gewechselt wurde
  • Lösung: Nach dem Wechsel in den Screenshot-Modus bleibt dieser fix bestehen, bis der Nutzer klickt
    • In der UI wird die Meldung „Video pausiert, um Bandbreite zu sparen“ angezeigt

Probleme mit JPEG-Unterstützung und Build-Prozess

  • Beim Wayland-Screenshot-Tool grim ist in den Standardpaketen von Ubuntu die JPEG-Unterstützung deaktiviert
    • Beim Ausführen von grim -t jpeg erscheint der Fehler „jpeg support disabled“
  • Zur Behebung wurde grim im Dockerfile direkt aus dem Quellcode gebaut, inklusive libjpeg-turbo8-dev

Endgültige Architektur

  • Gute Verbindung: 60fps H.264, hardwarebeschleunigt
  • Schlechte Verbindung: 2~10fps JPEG-Polling, vollständig zuverlässig
  • Die Screenshot-Qualität wird abhängig von der Übertragungszeit automatisch angepasst
    • Über 500ms: Qualität -10%, unter 300ms: +5%, mindestens 2fps

Zentrale Erkenntnisse

  1. Eine einfache Lösung ist besser als ein komplexes System — 2 Stunden JPEG-Hacking waren praxisnäher als 3 Monate H.264-Entwicklung
  2. Graceful Degradation ist entscheidend für die User Experience
  3. WebSocket eignet sich optimal für die Übertragung von Eingaben, ist für Videoübertragung aber nicht zwingend nötig
  4. Ubuntu-Pakete können Funktionen weglassen — bei Bedarf selbst bauen
  5. Vor der Optimierung erst messen — komplexes Streaming ist nicht zwangsläufig die einzige Lösung

Open-Source-Veröffentlichung

  • Helix wird als Open Source bereitgestellt; die Kernimplementierung umfasst unter anderem
    • api/cmd/screenshot-server/main.go — Screenshot-Server
    • MoonlightStreamViewer.tsx — adaptive Client-Logik
    • websocket-stream.ts — Steuerung der Video-Umschaltung
  • Helix wird mit dem Ziel entwickelt, AI-Infrastruktur zu schaffen, die auch in realen Umgebungen funktioniert

Noch keine Kommentare.

Noch keine Kommentare.