- Helix adalah platform AI yang menampilkan kepada pengguna layar tempat agen coding otonom berjalan di cloud, sehingga transmisi layar jarak jauh yang stabil menjadi hal yang krusial
- Ketika streaming berbasis WebRTC gagal karena pemblokiran UDP dan batasan firewall di jaringan perusahaan, tim membangun pipeline H.264 berbasis WebSocket, tetapi latensi menjadi sangat parah di lingkungan Wi-Fi yang tidak stabil
- Alih-alih struktur encoding·decoding yang kompleks, mereka menemukan bahwa pendekatan sederhana berupa mengirim screenshot JPEG secara berkala lewat HTTP jauh lebih stabil dan efisien
- Pendekatan ini menggunakan bandwidth lebih sedikit, tidak memerlukan pemulihan frame yang rusak, dan secara otomatis menyesuaikan kualitas gambar serta frame rate sesuai kondisi jaringan
- Pada akhirnya, Helix mengadopsi arsitektur hibrida yang memakai H.264 saat koneksi bagus dan beralih ke polling JPEG saat koneksi buruk, sehingga menghasilkan sistem streaming jarak jauh yang sederhana namun praktis
Masalah dan batasan streaming di Helix
- Helix adalah platform yang harus membagikan layar agen AI untuk coding yang berjalan di sandbox cloud secara real-time
- Pengguna menonton proses AI menulis kode layaknya remote desktop
- Awalnya mereka memakai WebRTC, tetapi koneksi gagal karena UDP diblokir di jaringan perusahaan
- Server TURN, STUN/ICE, dan port kustom semuanya diblokir oleh kebijakan firewall
- Karena itu mereka langsung mengimplementasikan pipeline streaming H.264 berbasis WebSocket yang hanya memakai HTTPS (port 443)
- Hardware encoding dengan GStreamer + VA-API, decoding di browser dengan WebCodecs
- Mencapai 60fps, 40Mbps, dan latensi di bawah 100ms
Latensi jaringan dan penurunan performa
- Di lingkungan jaringan yang tidak stabil seperti kedai kopi, muncul masalah video berhenti atau tertunda hingga puluhan detik
- WebSocket berbasis TCP membuat frame tertunda secara berurutan saat terjadi packet loss, sehingga sifat real-time runtuh
- Menurunkan bitrate tidak menyelesaikan latensi dan hanya menurunkan kualitas gambar
- Mereka juga mencoba mengirim hanya keyframe, tetapi gagal karena protokol Moonlight memerlukan P-frame
Penemuan pendekatan screenshot JPEG
- Saat debugging, mereka memanggil endpoint
/screenshot?format=jpeg&quality=70dan gambar yang tajam langsung dimuat- Satu JPEG berukuran 150KB tampil tanpa latensi
- Dengan sekadar mengulang request HTTP untuk memperbarui screenshot, mereka bisa mendapatkan pembaruan layar yang mulus di kisaran 5fps
- Pada akhirnya, mereka beralih dari pipeline video yang kompleks ke pendekatan request JPEG berkala (fetch loop)
Kelebihan pendekatan JPEG
- Poin perbandingan utama terhadap H.264
- Bandwidth: H.264 tetap di 40Mbps, JPEG bervariasi antara 100~500Kbps
- Manajemen status: H.264 bergantung pada status, JPEG adalah frame independen sepenuhnya
- Kemampuan pemulihan: H.264 perlu menunggu keyframe, JPEG langsung pulih di frame berikutnya
- Kompleksitas: H.264 butuh pengembangan berbulan-bulan, JPEG cukup diimplementasikan dengan beberapa baris loop
fetch()
- Semakin buruk kualitas jaringan, pendekatan JPEG yang sederhana justru lebih stabil dan efisien
Struktur perpindahan hibrida
- Helix secara otomatis berpindah antara dua metode ini berdasarkan RTT (round-trip time)
- RTT < 150ms → streaming H.264
- RTT > 150ms → polling JPEG
- Saat koneksi pulih, pengguna dapat mengklik untuk beralih kembali
- Event input (keyboard·mouse) tetap dikirim lewat WebSocket sehingga interaktivitas tetap terjaga
- Server menghentikan pengiriman video dan beralih ke mode screenshot dengan pesan
{"set_video_enabled": false}
Masalah ketidakstabilan perpindahan (oscillation) dan solusinya
- Ketika trafik WebSocket berkurang setelah pengiriman dihentikan, latensi ikut turun dan menyebabkan loop tak berujung yang otomatis kembali ke mode video
- Solusinya: setelah masuk ke mode screenshot, sistem tetap dipertahankan sampai pengguna mengklik
- UI menampilkan pesan “video dijeda untuk menghemat bandwidth”
Masalah dukungan JPEG dan proses build
- Tool screenshot untuk Wayland, grim, di paket bawaan Ubuntu menonaktifkan dukungan JPEG
- Saat menjalankan
grim -t jpeg, muncul error “jpeg support disabled”
- Saat menjalankan
- Untuk mengatasinya, mereka membangun grim langsung dari source di Dockerfile dengan menyertakan libjpeg-turbo8-dev
Arsitektur akhir
- Koneksi bagus: H.264 60fps, hardware acceleration
- Koneksi buruk: polling JPEG 2~10fps, sepenuhnya andal
- Kualitas screenshot disesuaikan otomatis berdasarkan waktu transmisi
- Jika melebihi 500ms, kualitas -10%; jika di bawah 300ms, +5%; minimum 2fps dipertahankan
Pelajaran utama
- Solusi sederhana bisa lebih baik daripada sistem yang kompleks — 3 bulan pengembangan H.264 kalah praktis dibanding 2 jam hacking JPEG
- Graceful degradation adalah inti dari pengalaman pengguna
- WebSocket optimal untuk pengiriman input, tetapi tidak wajib untuk pengiriman video
- Paket Ubuntu bisa saja kehilangan fitur — bila perlu, build sendiri
- Pengukuran wajib dilakukan sebelum optimasi — streaming kompleks bukan satu-satunya solusi
Rilis open source
- Helix tersedia sebagai open source, dan implementasi intinya adalah sebagai berikut
api/cmd/screenshot-server/main.go— server screenshotMoonlightStreamViewer.tsx— logika klien adaptifwebsocket-stream.ts— kontrol perpindahan video
- Helix sedang dikembangkan dengan tujuan membangun infrastruktur AI yang juga berfungsi di lingkungan nyata
1 komentar
Komentar Hacker News
Saat jaringan buruk, penurunan performa JPEG itu bukan karena UDP, melainkan karena cara implementasi TCP
JPEG tidak menyelesaikan masalah buffering atau kontrol kemacetan. Kemungkinan besar implementasinya dibuat dengan struktur yang meminimalkan pengiriman frame
h.264 memiliki efisiensi encoding yang lebih tinggi daripada JPEG. Dengan ukuran yang sama, frame IDR h.264 bisa menghasilkan kualitas yang lebih baik
Masalah mendasarnya adalah tidak adanya estimasi bandwidth. Bahkan di lingkungan TCP, bitrate bisa disesuaikan melalui probe bandwidth awal dan deteksi latensi transmisi
Jika memungkinkan, lebih baik memakai WebRTC, dan untuk menghindari firewall, WebSocket adalah pilihan yang baik
Terlepas dari masalah format tulisan atau gaya LLM, banyak bagian dari isinya yang keliru
10Mbps seharusnya cukup untuk layar statis. Masalahnya adalah pengaturan encoding yang salah atau kualitas encoder yang rendah
Pendekatan “kirim keyframe saja” itu tidak efisien; sebagai gantinya, cukup atur interval keyframe yang pendek
Pada akhirnya, masalahnya adalah struktur yang mendorong seluruh stream lewat satu koneksi TCP tunggal. Solusi seperti DASH untuk situasi seperti ini sudah ada
Mungkin ada baiknya melihat cara yang sudah dipakai VNC sejak 1998
Dengan tetap memakai model pull di sisi klien, framebuffer dibagi ke dalam unit tile, lalu hanya bagian yang berubah yang dikirim
Pada layar coding yang statis, ini bisa sangat mengurangi bandwidth. Jika ditambah deteksi scroll, hasilnya akan lebih efisien lagi
Saya pernah menangani video encoding sebelumnya, dan 40Mbps itu sudah setara kualitas Blu-ray
Untuk streaming teks sederhana, itu berlebihan. Setelah berdiskusi dengan Claude, kesimpulannya adalah 30FPS, GOP 2 detik, dan rata-rata sekitar 1Mbps sudah cukup
Bahkan dalam kasus terburuk, 1.2Mbps sudah cukup untuk menjaga kualitas yang stabil
Masalah inti tulisan ini adalah bandwidth minimum h.264 diatur terlalu tinggi
H.264 jauh lebih efisien daripada JPEG. Seharusnya mulai dari 1Mbps lalu disesuaikan
Menggunakan keyframe saja justru tidak efisien
Kalau saya, saya akan mengambil pendekatan yang sepenuhnya berbeda
10Mbps itu berlebihan, dan video coding di YouTube pada 1080p saja ada yang hanya sekitar 0.6Mbps. Tetap cukup tajam
Saya justru merasa lebih baik menurunkan ke 1fps atau menyesuaikan interval keyframe
Melakukan streaming video real-time ke browser memang benar-benar menyiksa
Jika screenshot JPEG bekerja dengan baik, lebih baik biarkan saja begitu
Stack seperti gstreamer atau Moonlight akan menjadi neraka untuk di-debug jika Anda tidak memahami backpressure dan propagasi error
Kombinasi NVIDIA Video Codec SDK + WebSocket + MediaSource Extensions adalah alternatif yang realistis
Tetapi jika tulisan itu memang hasil LLM, penulisnya tampaknya tidak akan punya niat untuk memahami struktur internal seperti ini
Dulu saya pernah memakai program yang mengambil screenshot setiap 5 detik, dan hard disk cepat penuh
Setelah sadar bahwa sebagian besar gambar itu sama, saya mulai memikirkan algoritma yang hanya menyimpan bagian yang berubah
Lalu saya sadar bahwa saya sedang menciptakan ulang kompresi video
Satu baris ffmpeg menyelesaikan semuanya, dan menghemat 98% ruang penyimpanan
Men-streaming video LLM yang sedang mengetik pada 40Mbps itu bandwidth yang sangat berlebihan dan tidak normal
Satu-satunya cara mendapatkan jawaban bagus di HN adalah mengunggah tulisan yang salah
Menurut saya, tulisan yang salah tapi menarik justru contoh keseimbangan sempurna untuk memancing diskusi