- Helix, bulutta otonom kodlama ajanlarının çalıştığı ekranı kullanıcıya gösteren bir AI platformu ve bunun için kararlı uzak ekran aktarımı kritik önem taşıyor
- Kurumsal ağlardaki UDP engellemesi ve güvenlik duvarı kısıtlamaları nedeniyle WebRTC tabanlı yayın başarısız olunca ekip, WebSocket tabanlı bir H.264 hattı kurdu; ancak kararsız Wi-Fi ortamlarında gecikme ciddi hale geldi
- Karmaşık kodlama/kod çözme yapısı yerine, basitçe JPEG ekran görüntülerini HTTP üzerinden periyodik olarak göndermenin çok daha kararlı ve verimli olduğunu fark ettiler
- Bu yöntem daha az bant genişliği kullanıyor, bozuk kareleri kurtarmayı gerektirmiyor ve ağ kalitesine göre görüntü kalitesini ve kare hızını otomatik olarak ayarlıyor
- Sonuç olarak Helix, iyi bağlantılarda H.264, kötü bağlantılarda ise JPEG polling'e geçen hibrit bir yapı benimsedi ve basit ama pratik bir uzak yayın sistemi oluşturdu
Helix'in yayın sorunları ve kısıtları
- Helix, bulut sandbox'larında çalışan AI kodlama ajanının ekranını gerçek zamanlı paylaşması gereken bir platform
- Kullanıcılar, tıpkı uzak masaüstünde olduğu gibi, yapay zekanın kod yazma sürecini izliyor
- Başlangıçta WebRTC kullanıldı, ancak kurumsal ağların UDP'yi engellemesi nedeniyle bağlantı kurulamıyordu
- TURN sunucuları, STUN/ICE, özel portlar gibi çözümlerin tümü güvenlik duvarı politikaları tarafından engellendi
- Bunun üzerine ekip, yalnızca HTTPS (443 portu) kullanan WebSocket tabanlı bir H.264 yayın hattını doğrudan kendisi geliştirdi
- Donanım kodlama için GStreamer + VA-API, tarayıcı tarafında kod çözme için WebCodecs kullanıldı
- 60fps, 40Mbps ve 100ms'nin altında gecikme elde edildi
Ağ gecikmesi ve performans düşüşü
- Kafeler gibi kararsız ağ ortamlarında görüntünün donması veya onlarca saniyelik gecikme sorunları yaşandı
- TCP tabanlı WebSocket'te paket kaybı olduğunda kareler sırayla geciktiği için gerçek zamanlılık bozuldu
- Bit hızı düşürülse bile gecikme çözülmedi, yalnızca görüntü kalitesi azaldı
- Yalnızca keyframe gönderme yöntemi de denendi, ancak Moonlight protokolü P-frame gerektirdiği için başarısız oldu
JPEG ekran görüntüsü yönteminin keşfi
- Hata ayıklama sırasında
/screenshot?format=jpeg&quality=70 endpoint'i çağrılınca anında net bir görüntü yüklendi
- 150KB boyutundaki tek bir JPEG, gecikme olmadan gösterildi
- Ekran görüntüsünü basitçe tekrarlanan HTTP istekleriyle yenileyince yaklaşık 5fps düzeyinde akıcı ekran güncellemesi mümkün oldu
- Sonunda karmaşık video hattı yerine, periyodik JPEG isteği (
fetch döngüsü) yaklaşımına geçildi
JPEG yönteminin avantajları
- H.264'e göre temel karşılaştırmalar
- Bant genişliği: H.264 sabit 40Mbps, JPEG ise 100~500Kbps arasında değişiyor
- Durum yönetimi: H.264 duruma bağımlı, JPEG ise tamamen bağımsız karelerden oluşuyor
- Kurtarılabilirlik: H.264'te keyframe beklemek gerekiyor, JPEG'de ise bir sonraki kareyle anında toparlanılıyor
- Karmaşıklık: H.264 aylar süren geliştirme gerektirdi, JPEG ise birkaç satırlık
fetch() döngüsüyle uygulandı
- Ağ kalitesi kötüleştikçe, basit JPEG yaklaşımı daha kararlı ve daha verimli hale geliyor
Hibrit geçiş yapısı
- Helix, iki yöntemi RTT (gidiş-dönüş gecikmesi) değerine göre otomatik değiştiriyor
- RTT < 150ms → H.264 yayını
- RTT > 150ms → JPEG polling
- Bağlantı toparlandığında, kullanıcı tıklayarak yeniden geçiş yapıyor
- Girdi olayları (klavye/fare) WebSocket üzerinden gönderilmeye devam ettiği için etkileşim korunuyor
- Sunucu,
{"set_video_enabled": false} mesajıyla video aktarımını durdurup ekran görüntüsü moduna geçiyor
Kararsız geçiş (oscillation) sorunu ve çözümü
- Aktarım durduktan sonra WebSocket trafiği azalınca gecikme düşüyor ve sistemin otomatik olarak yeniden video moduna geçmesine yol açan sonsuz döngü oluşuyordu
- Çözüm: Ekran görüntüsü moduna girildikten sonra, kullanıcı tıklayana kadar bu mod sabit tutuluyor
- Arayüzde “Bant genişliğinden tasarruf etmek için video duraklatıldı” mesajı gösteriliyor
JPEG desteği sorunu ve derleme süreci
- Wayland için ekran görüntüsü aracı grim'in Ubuntu'nun varsayılan paketinde JPEG desteği devre dışı bırakılmış
grim -t jpeg çalıştırıldığında “jpeg support disabled” hatası veriliyor
- Bunu çözmek için Dockerfile içinde libjpeg-turbo8-dev eklenerek grim doğrudan kaynaktan derlendi
Nihai mimari
- İyi bağlantı: 60fps H.264, donanım hızlandırmalı
- Kötü bağlantı: 2~10fps JPEG polling, tam güvenilirlik
- Ekran görüntüsü kalitesi, aktarım süresine göre otomatik ayarlanıyor
- 500ms'yi aşarsa kalite -10%, 300ms'nin altındaysa +5%, minimum 2fps korunuyor
Ana çıkarımlar
- Basit çözüm, karmaşık sistemden daha iyidir — 3 aylık H.264 geliştirmesinden daha pratik olan şey, 2 saatlik JPEG hack'i oldu
- Graceful degradation, kullanıcı deneyiminin anahtarıdır
- WebSocket girdi aktarımı için ideal, görüntü aktarımı içinse zorunlu değil
- Ubuntu paketlerinde özellik eksik olabilir — gerekirse doğrudan derlemek gerekir
- Optimizasyondan önce ölçüm şart — karmaşık yayın altyapısı tek çözüm olmayabilir
Açık kaynak olarak yayınlandı
- Helix açık kaynak olarak sunuluyor ve temel uygulama bileşenleri şunlar
api/cmd/screenshot-server/main.go — ekran görüntüsü sunucusu
MoonlightStreamViewer.tsx — uyarlanabilir istemci mantığı
websocket-stream.ts — video geçiş kontrolü
- Helix, gerçek ortamlarda da çalışan yapay zeka altyapısı hedefiyle geliştiriliyor
1 yorum
Hacker News görüşleri
Ağ kötü olduğunda JPEG'in daha iyi çalışması UDP yüzünden değil, TCP'nin uygulanma biçimi yüzünden
JPEG, buffering ya da congestion control sorunlarını çözmez. Muhtemelen kare iletimini en aza indiren bir yapıyla uygulanmış
h.264, JPEG'den kodlama verimliliği açısından daha iyidir. Aynı boyutta ise h.264 IDR frame daha iyi kalite verebilir
Temel sorun, bant genişliği tahmininin olmaması. TCP ortamında da başlangıç bant genişliği probing'i ve iletim gecikmesi algılamasıyla bitrate ayarlanabilir
Mümkünse WebRTC kullanmak daha iyi, firewall aşma amacıyla ise WebSocket tercih edilmeli
Yazının biçim sorunlarını ya da LLM tarzını bir kenara bıraksak bile, genel içerikte çok fazla yanlış var
10Mbps statik bir ekran için yeterli olmalı. Sorun, encoding ayarlarının yanlış olması ya da encoder kalitesinin düşük olması
“Sadece keyframe gönderelim” yaklaşımı verimsiz; bunun yerine kısa keyframe aralığı ayarlanabilir
Sonuçta sorun, tüm stream'i tek bir TCP bağlantısından iten yapı. Bu tür durumlar için DASH gibi çözümler zaten var
VNC'nin 1998'den beri yaptığı yönteme bakmak iyi olabilir
İstemci çekme modelini korurken framebuffer'ı tile bazında bölüp, sadece değişen kısımları ileten bir yapı kullanıyor
Statik kod ekranlarında bant genişliğini ciddi biçimde azaltabilir. Scroll algılama da eklenirse daha verimli olur
Daha önce video encoding ile uğraşmıştım; 40Mbps Blu-ray düzeyinde kalite demek
Basit metin akışı için aşırı fazla. Claude ile konuşunca 30FPS, 2 saniyelik GOP ve ortalama 1Mbps civarının yeterli olduğu sonucuna vardım
En kötü durumda bile 1.2Mbps yeterince istikrarlı kalite sağlayabilir
Bu yazının temel sorunu, h.264 için minimum bant genişliğini çok yüksek ayarlamış olması
H.264, JPEG'den çok daha verimli. 1Mbps'den başlayıp oradan ayarlamak gerekirdi
Sadece keyframe kullanmak ise tersine verimsizdir
Ben olsam tamamen farklı yaklaşırdım
10Mbps aşırı yüksek ve YouTube'daki kodlama videoları 1080p'de bile 0.6Mbps civarında. Gayet net görünüyor
Bunun yerine 1fps'ye düşürmek ya da keyframe aralığını ayarlamak daha mantıklı olurdu
Tarayıcıya gerçek zamanlı video stream etmek gerçekten acı verici bir iş
JPEG screenshot'lar iyi çalışıyorsa öyle bırakmak daha iyi
gstreamer ya da Moonlight gibi stack'lerde backpressure ve hata yayılımını anlamadan debug etmek cehennemdir
NVIDIA Video Codec SDK + WebSocket + MediaSource Extensions birleşimi gerçekçi bir alternatif
Ama yazı LLM üretimiyse, yazarın bu iç yapıları anlamaya niyeti yok gibi duruyor
Eskiden her 5 saniyede bir screenshot alan bir program kullanmıştım, sabit disk çok hızlı doluyordu
Görsellerin çoğunun aynı olduğunu fark edip sadece değişen kısımları kaydeden bir algoritma düşünmeye başladım
Sonra aslında video sıkıştırmayı yeniden icat ettiğimi fark ettim
ffmpeg ile tek satırda çözdüm ve depolama alanının %98'ini tasarruf ettim
LLM'nin yazı yazmasını 40Mbps ile stream etmek anormal derecede aşırı bant genişliği kullanmak demek
HN'de iyi cevap almanın tek yolu yanlış bir yazı paylaşmak
Yanlış ama ilginç bir yazı, bence tartışma çıkarmak için kusursuz dengeyi yakalayan bir örnek