Skip to content

lokust-stream — streaming server

Rust binary that runs on a GPU droplet. Captures the server's X11 display, encodes via NVENC (or x264 fallback), and serves WebRTC peer connections with H.264 video.

Binary

Built from session-vm/crates/stream-server/ as target/release/lokust-stream.

Configuration (environment variables)

Var Default Purpose
LOKUST_STREAM_PORT 7800 Signaling + HTTP port
DISPLAY :1 X display to capture
LOKUST_ENCODER nvenc One of nvenc, vaapi, x264
LOKUST_STREAM_WIDTH 1920 Capture width
LOKUST_STREAM_HEIGHT 1080 Capture height
LOKUST_STREAM_FPS 60 Target framerate
LOKUST_STREAM_BITRATE_KBPS 8000 Initial bitrate target
LOKUST_STUN stun:stun.l.google.com:19302 STUN server for ICE

HTTP endpoints

GET /

Serves a minimal LOKUST-branded test client HTML page. Useful for verifying a streaming setup without building the iPad app first.

GET /health

Liveness check.

Response 200 OK

ok

GET /signal — WebSocket

WebRTC signaling endpoint. See protocol/webrtc-signaling.md for the full message format.

Pipeline

┌─────────────┐   ┌─────────────┐   ┌──────────┐   ┌──────────────────────────────┐
│ ximagesrc   │ → │ videoconv + │ → │ H.264    │ → │ appsink → broadcast channel  │
│ display=:1  │   │ videoscale  │   │ encoder  │   │                              │
└─────────────┘   └─────────────┘   └──────────┘   └──────────────────────────────┘
                                                    ┌────────────────┐
                                                    │ Each WS peer:  │
                                                    │ subscribe →    │
                                                    │ TrackLocal     │
                                                    │ StaticSample   │
                                                    │ → write_sample │
                                                    └────────────────┘

One encode, N peers. The broadcast channel is bounded at 32 buffers; slow consumers are dropped with a warning (sample broadcast lagged).

Encoder selection

Encoder When to use
nvenc Production on NVIDIA GPUs. Requires GStreamer built with NVENC SDK (not the default Ubuntu package).
vaapi Intel/AMD hardware encode.
x264 CPU fallback. Works everywhere GStreamer is installed. Zero-latency preset used.

The NVENC path expects nvcudah264enc or nvh264enc to be registered in GStreamer; the server falls back automatically if only the modern element is available, otherwise errors explicitly.

Running

# On the droplet (Ubuntu 22.04 + GStreamer + NVIDIA drivers)
DISPLAY=:1 LOKUST_ENCODER=x264 \
  ./target/release/lokust-stream

Logs use tracing (env-filter). Default is info,stream_server=debug.

2026-04-12T23:52:49  INFO  lokust_stream: gstreamer initialized
2026-04-12T23:52:49  INFO  lokust_stream: config loaded port=7800 display=:1 encoder=X264
2026-04-12T23:52:49  INFO  lokust_stream::pipeline::bridge: video pipeline started encoder=X264 width=1920 height=1080 fps=60
2026-04-12T23:52:49  INFO  lokust_stream::signaling: signaling server listening addr="0.0.0.0:7800"

Firewall requirements

On the GPU droplet:

  • TCP 7800 — signaling + HTTP (or proxy via Cloudflare Tunnel)
  • UDP 49152-65535 — WebRTC media (STUN/DTLS-SRTP)

Latency targets

On an H200 droplet in NYC2 with a consumer broadband client on the same continent:

Stage Budget
Capture (ximagesrc) <16 ms (60 fps frame interval)
Encode (NVENC) <8 ms
Packetize + network ~30 ms RTT
Decode (client Metal/GPU) <5 ms
Display <16 ms (one frame)
Total glass-to-glass ~75 ms

x264 fallback adds 5–15 ms depending on CPU.