Files
punktfunk/crates/punktfunk-host
enricobuehler ddc28de32a
ci / rust (push) Failing after 22m10s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 9m36s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 9m15s
apple / screenshots (push) Canceled after 0s
docker / build-push-arm64cross (push) Canceled after 0s
docker / deploy-docs (push) Canceled after 0s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Canceled after 10m20s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Canceled after 9m13s
windows-host / package (push) Failing after 12s
windows-host / winget-source (push) Skipped
ci / web (push) Successful in 56s
ci / docs-site (push) Successful in 1m2s
ci / bench (push) Successful in 5m41s
ci / rust-arm64 (push) Successful in 9m26s
arch / build-publish (push) Successful in 12m29s
deb / build-publish (push) Successful in 8m57s
decky / build-publish (push) Successful in 32s
apple / swift (push) Successful in 5m57s
android / android (push) Successful in 19m51s
deb / build-publish-client-arm64 (push) Successful in 7m21s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 15s
docker / build-push (ci, ci/rust-ci-noble.Dockerfile, punktfunk-rust-ci-noble) (push) Successful in 11s
deb / build-publish-host (push) Successful in 9m34s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 10s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 1m9s
fix(gamestream): tell the client when the HOST ends the session
On-glass on .173: a launched game exited, the host tore the session down
correctly — and the client froze on its last frame instead of returning to its
app list.

The host's half was right; it just never said anything. On the native plane
ending a session closes the QUIC connection with APP_EXITED, which every client
renders as "game ended". The compat plane has no such channel: `end_session`
stops the media threads, and stopping a UDP sender is silence, not a signal.
Moonlight holds the ENet control stream for the whole session, so with no word
from us it sat there until its own timeout eventually fired.

The control loop already reacted to the CLIENT disconnecting; it had no path for
the reverse. It now watches for its session being cleared out from under it and
disconnects the peer, which is what Moonlight reads as "the session is over" —
landing the player back in the app list, the same place quitting puts them.

This is the signal every host-side end needed, not just a game exiting: the
management stop and a `/cancel` racing another connection had the same silence.
2026-07-26 19:44:55 +02:00
..

punktfunk-host

The streaming host — the program you run on the machine whose desktop or games you want to stream. For each client that connects, it spins up a virtual display sized to that device, captures it on the GPU, encodes with hardware NVENC/VAAPI/AMF/QSV, and sends it out over a low-latency transport — no physical monitor, no letterboxing, no rearranging your real screens.

It speaks two protocols from one process:

  • GameStream — so any Moonlight / Artemis client works day one.
  • punktfunk/1 — punktfunk's own faster protocol (QUIC control plane, GF(2¹⁶) FEC + AES-GCM data plane) that the native clients use.

Runs on Linux (the primary, most battle-tested path) and Windows (x64). The shared protocol, FEC, and crypto live in punktfunk-core; this crate is everything platform-facing around it.

What it does

  • Per-client virtual displays at the exact WxH@Hz. Linux uses per-compositor backends — KWin, gamescope, Mutter, and Sway/wlroots; Windows uses its own all-Rust IddCx virtual display, even on the secure desktop (UAC / lock screen).
  • GPU zero-copy capture → encode. dmabuf → CUDA/Vulkan → NVENC on Linux; on Windows the host pushes frames straight into its own IDD (sealed IDD-push, no screen-scraping) → GPU encode. Encoders auto-select by GPU vendor: NVENC (NVIDIA), VAAPI (Linux AMD/Intel), AMF/QSV (Windows AMD/Intel), or software H.264 as a floor. HDR/10-bit and HEVC 4:4:4 supported.
  • Input injection. Mouse/keyboard (libei / gamescope EIS / wlr / Windows SendInput) and virtual gamepads — Xbox 360/One, DualSense, DualShock 4 — with rumble and HID feedback back-channels.
  • Audio both ways. Opus audio host→client, plus a virtual microphone the client can talk into.
  • Trust & discovery. A persistent host identity, SPAKE2 PIN pairing (default) or TOFU, and mDNS auto-advertisement so clients find the host without typing an IP.
  • Management API + web console. A REST API (mgmt.rs, OpenAPI at api/openapi.json) drives status, paired devices, and on-demand pairing; the browser UI is in web/.

Run it

punktfunk-host serve runs inside your desktop session. Bare serve is the secure native-only default (punktfunk/1 + the management API); add --gamestream on a trusted LAN to also accept stock Moonlight clients.

# Linux, from the repo root (see the repo README "Running on this box" for the headless recipe):
cargo run -rp punktfunk-host -- serve                 # native-only (secure default)
cargo run -rp punktfunk-host -- serve --gamestream    # + Moonlight compatibility

Then pair from the web console (https://<host-ip>:47992) or the client app.

Most people should install a package rather than run from source — see packaging/ (apt · rpm/COPR/bootc · Arch/sysext · Windows installer) and the per-platform guides at docs.punktfunk.unom.io/docs/install.

Subcommands

Command Purpose
serve The host (native punktfunk/1 + mgmt API; --gamestream adds Moonlight).
punktfunk1-host Standalone native-protocol listener for testing/measurement (--source virtual, --max-sessions).
openapi Print the management-API OpenAPI spec (regenerates api/openapi.json).
library Inspect the multi-store game library.
service · driver · web Windows: SCM service, driver install, bundled web console.
*-test / *-selftest / *-probe Diagnostics (input, zero-copy, HDR, compositor, gamepads).

--help lists them all.

Layout

src/
  main.rs            CLI + subcommand dispatch
  config.rs · session_plan.rs · session_tuning.rs · pipeline.rs   session setup + the frame pipeline
  vdisplay/          per-compositor virtual outputs (kwin · gamescope · mutter · wlroots)
  capture/ · capture.rs    screen/dmabuf capture (+ Windows IDD-push)
  encode/ · encode.rs      per-GPU encoders (nvenc · vaapi · ffmpeg_win (AMF/QSV) · sw)
  linux/zerocopy/    dmabuf → CUDA → NVENC bridges (EGL/GL tiled, Vulkan LINEAR)
  inject/ · inject.rs      input backends (libei · wlr · uinput gamepads · UHID DualSense/DS4)
  audio/ · audio.rs        Opus out + virtual mic (PipeWire / WASAPI)
  gamestream/        Moonlight compat: nvhttp · pairing · rtsp · control · stream · gamepad · apps
  native.rs      the native punktfunk/1 host (QUIC control + native-thread UDP data plane)
  mgmt.rs · native_pairing.rs · stats_recorder.rs   management API, pairing, perf capture
  hdr.rs · library.rs      HDR metadata; multi-store game library
  linux/ · windows/  platform-confined backends
  • punktfunk-core — the shared protocol · FEC · crypto core
  • Clients — the apps that connect (Apple · Linux · Windows · Android · probe)
  • Packaging & docs — install & operate
  • punktfunk-planning (internal planning repo) — architecture rationale and deep-dive plans