Modules¶
The repository is a Cargo workspace for the Rust side and a pnpm workspace for the web side.
crates/ core · proto · net · capture · gpu · codec · render · input · audio · secure
apps/ host-agent · client · client-ui · desktop
web/ ui · viewer · e2e
tests/ e2e (host and client through an impaired network)
fuzz/ cargo-fuzz targets
dev/ Distrobox containers for Bazzite, GPU runner setup
packaging/ AppImage, install scripts, systemd unit
How they depend on each other¶
flowchart BT
core["core"]
proto["proto"]
net["net"] --> core & proto
capture["capture"] --> core
gpu["gpu"] --> capture
codec["codec"] --> capture & gpu & core & proto
render["render"] --> codec & gpu
input["input"] --> proto
audio["audio"] --> core
secure["secure"]
host["apps/host-agent"] --> net & codec & input & audio & secure
client["apps/client"] --> net & render & input & audio & secure
desktop["apps/desktop"] --> client & host & secure
Crates¶
| Crate | What it does |
|---|---|
core |
The slot with capacity 1 (latest frame wins, buffer recycling), the monotonic clock, latency statistics per stage, hot threads (real-time where allowed, else raised priority; precise sleeps), system info for discovery |
proto |
The UDP packet format v1: video shards with stage timestamps, feedback, clock ping/pong, hello/ack with the codec set, bye, pointer, input, audio, handshake, sealed packets, pairing, discovery, monitors. The parser never panics and never allocates (protocol) |
net |
Reed-Solomon FEC (reed-solomon-simd), one group per frame up to 512 shards, balanced and interleaved beyond; recovery shards per group sized binomially from the measured loss (group failure ≤ 10⁻⁵); reassembly with keyframe requests and hard size limits; the pacer; NTP-style clock sync; UDP sockets with 4 MiB buffers; bitrate adaptation; loss simulation |
capture |
The FrameSource trait, the test pattern (NV12, a moving bar, a circling pointer), the DMA-BUF description, KMS capture at vblank with the cursor plane and monitor switching (feature kms, pure Rust) |
gpu |
The Vulkan device and DMA-BUF import without a copy (for the renderer and the encoder); RGB DMA-BUF → NV12 by a compute shader, exported to CUDA for NVENC; test images exported as DMA-BUFs |
codec |
The Encoder/Decoder traits, the synthetic codec, VAAPI encode and decode of H.264, HEVC and AV1 through FFmpeg (feature vaapi, DMA-BUF import, RGB → NV12 and scaling by scale_vaapi), NVENC/NVDEC (feature nvidia, screen through Vulkan → CUDA, decoded pictures exported from CUDA to Vulkan), hardware capability queries |
render |
The Presenter trait, overlay formatting, the Vulkan renderer (NV12 from the CPU or a DMA-BUF → RGB, letterboxing, the pointer) and the window presenter (feature window) |
shader |
WGSL to SPIR-V for the build scripts of gpu and render: the shaders compile when the crate builds, the programs carry SPIR-V and no shader compiler |
input |
Input events, the duplicate filter, uinput devices on the host (mouse, keyboard, Xbox 360 pads with rumble), DualSense pads through uhid (gyro, touchpad), gamepads on the client (SDL3, else evdev) |
clipboard |
The clipboard: a Wayland desktop's through data control (ext-data-control-v1, else wlroots' zwlr-data-control), and a text across the link in acknowledged pieces |
audio |
Capture and playback through PipeWire's PulseAudio interface, Opus (48 kHz stereo, 5 ms frames, low delay), the client's jitter buffer, a test tone; libopus and libpulse are loaded at runtime |
secure |
Device keys (X25519), the list of paired devices, pairing with SPAKE2, Noise IK sessions, the replay window (security) |
Apps¶
| App | What it does |
|---|---|
apps/host-agent |
fernsicht-host-agent: the control loop (lib.rs, its steps in dispatch.rs) and its answers (requests.rs), starting a session (start.rs) and its threads (capture.rs, encode.rs, send.rs, audio.rs), the way to the client (link.rs: our UDP protocol or a browser's WebRTC), keys and pairing (security.rs), the control socket (control.rs), the web viewer and WebRTC (web/), the monitor arrangement for input mapping (layout.rs), GPU clocks during sessions (power.rs) |
apps/client |
fernsicht-client: the network thread (network.rs), decoding and presenting (present.rs), sound (audio.rs), hosts and pairing (hosts.rs), discovery (discover.rs), the pointer (cursor.rs), the window with its keys and system-shortcut lock (window.rs, shortcuts.rs) |
web/client-ui |
The app's interface (React 19, TanStack Router and Query, Tailwind, shadcn-style components); demo data in a browser, the real backend in the app |
apps/desktop |
The Tauri app around client-ui: devices, pairing, sessions through the client (backend.rs), sharing this computer from the AppImage (share.rs). Its own Cargo workspace (it needs WebKitGTK) |
Web¶
| Package | What it does |
|---|---|
web/ui |
Shared components: the session view with toolbar and menus, the latency overlay, primitives, demo data |
web/viewer |
The web viewer: connect page, WebRTC session, pointer, mouse, keyboard, gamepads, touch gestures (lib/touch.ts), on-screen keyboard (lib/textkeys.ts), fullscreen with Keyboard Lock |
web/e2e |
Playwright tests (desktop, phone, phone in landscape, accessibility with axe) and the screenshot script |
Build features¶
| Feature | Crates | |
|---|---|---|
vaapi |
codec, host-agent, client, render (GPU tests), e2e | hardware video on AMD/Intel; needs FFmpeg and libva headers |
nvidia |
codec, host-agent, client, render (GPU tests), e2e | NVENC/NVDEC; CUDA is loaded at runtime, builds without the driver |
kms |
capture, host-agent | screen capture over KMS |
window |
render, client | the Vulkan window (winit) |
vulkan |
render | the renderer without a window (tests) |
Without features the whole pipeline runs with the test pattern and the synthetic codec, so CI and machines without a GPU test transport, FEC, pacing and latency for real.