docs: update README + docs site for public readiness
apple / swift (push) Successful in 56s
ci / rust (push) Successful in 1m37s
ci / web (push) Successful in 31s
ci / docs-site (push) Successful in 40s
android / android (push) Successful in 3m19s
deb / build-publish (push) Failing after 1m9s
decky / build-publish (push) Successful in 22s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 5s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 4s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 3s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 2m21s
ci / bench (push) Successful in 4m45s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 26s
rpm / build-publish (fedora-44, punktfunk-fedora44-rpm) (push) Failing after 3m22s
docker / deploy-docs (push) Successful in 18s
rpm / build-publish (bazzite, punktfunk-fedora-rpm) (push) Successful in 10m25s
apple / swift (push) Successful in 56s
ci / rust (push) Successful in 1m37s
ci / web (push) Successful in 31s
ci / docs-site (push) Successful in 40s
android / android (push) Successful in 3m19s
deb / build-publish (push) Failing after 1m9s
decky / build-publish (push) Successful in 22s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 5s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 4s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 3s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 2m21s
ci / bench (push) Successful in 4m45s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 26s
rpm / build-publish (fedora-44, punktfunk-fedora44-rpm) (push) Failing after 3m22s
docker / deploy-docs (push) Successful in 18s
rpm / build-publish (bazzite, punktfunk-fedora-rpm) (push) Successful in 10m25s
Refresh the README and documentation for public visitors: - README: public-facing rewrite with accurate status for all four native clients (macOS, Linux, Windows, Android) and the Windows host. - docs site: fix stale client status (Android is a full client, not a scaffold; Windows client is stage-1 complete + signed MSIX), add the missing Android client section, correct "which client" guidance. - Windows host: corrected from "deferred/scoped" to implemented & shipping (NVIDIA-only, x64-only) across windows-host, roadmap, status, requirements, running-as-a-service, and the README. - Remove internal infrastructure from public docs (box names, private IPs, SSH/token commands, deploy topology); rewrite status.md as a public project-status page; sanitize ci.md and implementation-plan.md. - Update clients/android and clients/apple READMEs to current state. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,11 +1,12 @@
|
||||
---
|
||||
title: "Status & Progress"
|
||||
description: "Where the work stands, what's live on each box, and a running progress log."
|
||||
description: "Where the work stands across the core, the host, and the native clients."
|
||||
---
|
||||
|
||||
The living progress tracker. Milestone-level status lives in [`CLAUDE.md`](https://github.com)
|
||||
and the design in the [Implementation Plan](/docs/implementation-plan); this page is the
|
||||
**current state + a dated log** of what landed, kept up to date as work happens. Newest first.
|
||||
A high-level view of where punktfunk stands. The full design lives in the
|
||||
[Implementation Plan](/docs/implementation-plan), the ordered plan of work in the
|
||||
[Roadmap](/docs/roadmap), and milestone-level detail in
|
||||
[`CLAUDE.md`](https://git.unom.io/unom/punktfunk/src/branch/main/CLAUDE.md).
|
||||
|
||||
## Milestones at a glance
|
||||
|
||||
@@ -13,92 +14,105 @@ and the design in the [Implementation Plan](/docs/implementation-plan); this pag
|
||||
|---|---|
|
||||
| **Core** — `punktfunk-core` + C ABI (protocol · FEC · crypto) | ✅ complete & hardened |
|
||||
| **GameStream host** (Moonlight-compatible) | ✅ working end-to-end; HDR/surround-audio polish open |
|
||||
| **Native protocol** — `punktfunk/1` (QUIC control + UDP data) | ✅ full session planes, validated live |
|
||||
| **Native clients** — decode + present (Apple first) | 🟡 macOS stage 1 live; stage-2 presenter built + decode-tested (opt-in, present needs live validation). **Linux GTK client stage 1 live** (2026-06-12) |
|
||||
| **Native protocol** — `punktfunk/1` (QUIC control + UDP data, GF(2¹⁶) Leopard FEC + AES-GCM) | ✅ full session planes, validated live |
|
||||
| **Windows host** (NVIDIA, x64) | 🟡 implemented & shipping as a signed installer; NVIDIA-only, newer than the Linux host |
|
||||
| **macOS / iOS / iPadOS / tvOS client** | ✅ full client; on-glass stage-2 presenter behind an opt-in flag, becoming the default |
|
||||
| **Linux client** (`punktfunk-client`, GTK4/libadwaita) | ✅ full client; VAAPI zero-copy decode + software fallback |
|
||||
| **Windows client** (`punktfunk-client`, WinUI 3) | ✅ stage 1 complete; ships as signed MSIX; on-glass hardware validation pending |
|
||||
| **Android client** (phone + Android TV) | ✅ full client; hardware HEVC decode + HDR10 |
|
||||
| **Web console** (over the management API) | ✅ status · devices · pairing |
|
||||
|
||||
## Live on the boxes
|
||||
## What works today
|
||||
|
||||
| Box | Role | Compositor | Notes |
|
||||
|---|---|---|---|
|
||||
| **home-worker-2** (dev) | KDE/KWin appliance | kwin (headless Plasma) | QEMU VM, passthrough RTX 5070 Ti; `serve --native` user unit |
|
||||
| **home-worker-3** (GNOME) | GNOME/Mutter appliance | mutter (RecordVirtual) | RTX 4090; autologin GNOME Wayland; `serve --native` user unit. See [Ubuntu — GNOME](/docs/ubuntu-gnome) |
|
||||
| **home-bazzite-1** | SteamOS-like host | gamescope | host-managed Steam session at client mode. See [Bazzite Setup](/docs/bazzite) |
|
||||
punktfunk is a low-latency desktop and game streaming **host** — Linux-first (Linux + NVIDIA, NVENC),
|
||||
with a newer **NVIDIA-only Windows host** too — and native **clients** on macOS, iOS/iPadOS/tvOS,
|
||||
Linux, Windows, and Android.
|
||||
|
||||
All three appliances advertise over mDNS (`_punktfunk._udp`) and require PIN pairing by default.
|
||||
- **Two protocols.** The host speaks the **GameStream** protocol, so any **Moonlight**
|
||||
client works out of the box, plus its own lower-latency **`punktfunk/1`** protocol
|
||||
(QUIC control plane + UDP data plane with GF(2¹⁶) Leopard FEC and AES-GCM).
|
||||
- **Native resolution, no scaling.** Every session gets a virtual display at the client's
|
||||
exact resolution and refresh rate, via per-compositor backends for **KWin**,
|
||||
**gamescope**, **Mutter**, and **Sway/wlroots**.
|
||||
- **Zero-copy GPU pipeline.** Captured frames stay on the GPU (dmabuf → CUDA → NVENC) with
|
||||
automatic split-encode at very high resolutions. Stable 240 fps at 5120×1440 has been
|
||||
measured.
|
||||
- **Secure by default.** A **SPAKE2 PIN pairing** ceremony establishes trust (the host
|
||||
shows a 4-digit PIN; an attacker gets a single online guess, no offline dictionary
|
||||
attack). Trust-on-first-use (TOFU) remains an explicit opt-in for fully trusted LANs.
|
||||
- **LAN auto-discovery.** Hosts advertise over mDNS (`_punktfunk._udp`); clients browse and
|
||||
list them automatically.
|
||||
- **Full input.** Mouse, keyboard, and gamepads (including DualSense touchpad, motion,
|
||||
rumble, lightbar, player LEDs, and adaptive triggers) in both directions.
|
||||
- **Audio both ways.** Opus desktop audio host → client, plus an opt-in, paired-only client
|
||||
microphone uplink.
|
||||
- **Management surface.** A REST management API with a checked-in OpenAPI document, plus a
|
||||
web console for status, paired devices, and pairing.
|
||||
|
||||
## Progress log
|
||||
### Native clients
|
||||
|
||||
### 2026-06-12
|
||||
- **Native Linux client — stage 1, first light** (`clients/linux`, binary
|
||||
`punktfunk-client`). GTK4/libadwaita app on the **Option A** architecture picked after a
|
||||
six-angle research pass (toolkits / hw decode / Wayland presentation / input capture /
|
||||
prior art / codebase): links `punktfunk-core` directly as a crate (no C ABI;
|
||||
`NativeClient` is `Sync` now), mDNS host list, TOFU + SPAKE2 PIN pairing dialogs
|
||||
(identity shared with `client-rs`), FFmpeg software HEVC decode (`LOW_DELAY` + slice
|
||||
threads) into a `GtkGraphicsOffload`-wrapped picture, PipeWire playback with the host
|
||||
mic-player's jitter ring inverted, SDL3 gamepad capture + rumble/lightbar feedback,
|
||||
layout-independent keyboard (exact inverse of the host's VK table), absolute mouse +
|
||||
WHEEL_DELTA scroll, compositor-shortcut inhibition, fullscreen, stats overlay.
|
||||
**Validated live** against this box's `serve --native`: 1080p60 at a locked 60 fps,
|
||||
capture→decoded **p50 ≈ 6.4 ms** (software decode, debug build). Next: VAAPI dmabuf →
|
||||
`GdkDmabufTexture` (Tier-1 zero-copy on Intel/AMD clients), DualSense
|
||||
touchpad/motion/trigger replay over SDL3, then the stage-2 raw-Wayland presenter
|
||||
(wp_presentation feedback, tearing-control, Vulkan Video for NVIDIA clients).
|
||||
- **Delegated pairing approval (§8b-1)** — an unpaired device that tries to connect to a
|
||||
pairing-required host now shows up as a **pending request** in the web console's Pairing page;
|
||||
one click approves it (optionally relabeling) and pairs its certificate fingerprint — no PIN
|
||||
fetched out of band. New mgmt endpoints (`/native/pending` + approve/deny), an in-memory pending
|
||||
queue in `NativePairing` (fp-deduped, capped, 10-min expiry), and an optional **device name** in
|
||||
the `Hello` (back-compat trailing field; `client-rs --name` sends it). End-to-end tested.
|
||||
§8b-2 (approve from a paired device's own app) is the client-side follow-up.
|
||||
- **CI + deployment landed** (see the [CI & Docker](/docs/ci) guide). Gitea Actions, three
|
||||
workflows: Rust workspace checks inside the new `punktfunk-rust-ci` builder image (Ubuntu 26.04,
|
||||
full link-dep stack incl. a libcuda stub — 141/141 tests green in-container), web + docs-site
|
||||
build/typecheck, `docker.yml` building+pushing `punktfunk-web`/`punktfunk-docs`/`punktfunk-rust-ci`
|
||||
to the registry, and `apple.yml` (xcframework → `swift build`/`swift test`) on a new **host-mode
|
||||
macOS runner** (`home-mac-mini-1`, provisioned by `scripts/ci/setup-macos-runner.sh`; macOS
|
||||
Local-Network privacy forces it to run as a root LaunchDaemon). Host and native clients stay
|
||||
un-dockerized by design. **This site now deploys automatically**: `deploy-docs` ships it to
|
||||
unom-1:3220, Caddy serves <https://docs.punktfunk.unom.io> — live and verified.
|
||||
- **Concurrent sessions** — the host no longer serves one client at a time. The accept loop spawns
|
||||
each session (`JoinSet`), bounded by `--max-concurrent` (default 4, a NVENC bound; overflow waits
|
||||
in the accept queue). Each session keeps its own virtual output + encoder; they share the
|
||||
host-lifetime input/audio/mic services — i.e. **multiple devices viewing/controlling the same
|
||||
desktop** on kwin/mutter/wlroots. Validated live on the GNOME box: two clients connected at once
|
||||
→ **two independent Mutter virtual outputs (1280×720 + 1920×1080) streaming simultaneously**
|
||||
(39 MB + 48 MB). gamescope's *independent-desktops* (multi-user) isolation — per-session
|
||||
input/audio — is a follow-up.
|
||||
- **Apple client latency HUD** — `PunktfunkConnection.clockOffsetNs` (from the C-ABI getter) +
|
||||
`LatencyMeter` surface a skew-corrected **capture→client-receipt** p50/p95 in the macOS HUD: the
|
||||
first cross-machine latency the real Apple client reports. (Stage-1 `AVSampleBufferDisplayLayer`
|
||||
has no present callback, so decode→present is excluded — that needs the stage-2 presenter.)
|
||||
Needs an `xcframework` rebuild + `swift test` on the Mac to validate.
|
||||
- **Skew handshake in the connector + C ABI** — `quic::clock_sync` is now a shared core helper used
|
||||
by both the reference client and `NativeClient`; the connector runs it at connect and exposes the
|
||||
host clock offset over the C ABI (`punktfunk_connection_clock_offset_ns`). This is the substrate
|
||||
the Apple client needs for the decode→present (glass-to-glass) term.
|
||||
- **Wall-clock skew handshake** (`ClockProbe`/`ClockEcho`, 8 NTP rounds after `Start`) — makes the
|
||||
client's capture→reassembled latency valid **cross-machine**. Validated GNOME box → dev box:
|
||||
offset −1.57 ms removed, **p50 1.30 ms** skew-corrected. (`05bc9ab`)
|
||||
- **Native LAN auto-discovery** — host advertises `_punktfunk._udp` (TXT: fingerprint, pairing,
|
||||
proto); `punktfunk-probe --discover` lists hosts. Validated cross-LAN. (`4fff464`)
|
||||
- **Third test box stood up** — home-worker-3 (Ubuntu 26.04, RTX 4090, GNOME 50): first GNOME/Mutter
|
||||
zero-copy streaming on a real desktop; **1 Gbps probe clean** (625 MB/5 s, `send_dropped=0`).
|
||||
Two physical-NVIDIA gotchas documented in [Ubuntu — GNOME](/docs/ubuntu-gnome).
|
||||
- **Encode|send thread split** validated on real NIC (`send_dropped=0` at 720p60 / 1080p120). (`b295a5b`)
|
||||
| Client | Highlights |
|
||||
|---|---|
|
||||
| **macOS / iOS / iPadOS / tvOS** | VideoToolbox HEVC decode, GameController capture, full DualSense feedback, mDNS discovery, PIN pairing + TOFU, network speed test, latency HUD. Stage-2 presenter (`VTDecompressionSession` → `CAMetalLayer`, ~11 ms p50 capture→present) is built and validated on glass behind an opt-in flag, becoming the default. Ships as one universal TestFlight build / App Store listing. |
|
||||
| **Linux** (`punktfunk-client`) | GTK4/libadwaita. FFmpeg decode with VAAPI → DRM-PRIME dmabuf zero-copy (Intel/AMD; software fallback on NVIDIA), PipeWire audio + mic, SDL3 gamepads incl. DualSense, mDNS discovery, PIN pairing + TOFU, speed test. Ships as Flatpak, apt, rpm, and Arch packages. |
|
||||
| **Windows** (`punktfunk-client`) | WinUI 3. D3D11VA zero-copy decode, HDR10, WASAPI audio + mic, SDL3 gamepads incl. DualSense, mDNS discovery, and the full PIN/TOFU trust surface are all implemented. Ships as a signed MSIX (x86_64 + ARM64). **Stage 1 complete; D3D11VA decode, HDR present, and the GUI are pending on-glass validation on real GPU hardware.** |
|
||||
| **Android** (phone + Android TV) | Kotlin app with a Rust core over JNI. NDK `AMediaCodec` hardware HEVC decode + HDR10 (Main10/BT.2020 PQ), Opus/Oboe audio + mic, gamepad input with rumble/HID feedback, NsdManager mDNS discovery, PIN pairing + TOFU (Keystore identity), live stats HUD, and D-pad/controller focus navigation for TV. Ships to the Google Play Internal Testing track. |
|
||||
|
||||
### Earlier (see roadmap + git log)
|
||||
- **1 Gbps data plane**: batched `sendmmsg`/`recvmmsg` + microburst-cap paced send thread.
|
||||
- **Boot appliance**: headless KDE session + host systemd units (no login).
|
||||
- **Speed test + settable bitrate**: negotiation + bandwidth probe (host side).
|
||||
- **DualSense** UHID + haptics; gamepads live; mic uplink; AV1 + surround (unit/live-capture tested).
|
||||
`punktfunk-probe` is a headless reference and measurement client (for testing and
|
||||
benchmarking, not everyday use).
|
||||
|
||||
## Validated live on
|
||||
|
||||
The stack has been validated live on a range of hosts and clients:
|
||||
|
||||
- **Hosts:** Ubuntu (GNOME / KDE), Fedora KDE, and Bazzite (gamescope) on machines with
|
||||
RTX-class NVIDIA GPUs, across the KWin, gamescope, Mutter, and Sway/wlroots backends.
|
||||
- **Clients:** native macOS, Linux, and Android clients against live hosts, plus stock
|
||||
Moonlight clients over the GameStream path.
|
||||
- **Cross-machine latency** is measured and skew-corrected (a wall-clock handshake removes
|
||||
the inter-machine clock offset), so capture-to-present numbers are valid across the LAN.
|
||||
|
||||
## Highlights
|
||||
|
||||
Notable capabilities that have landed, newest first:
|
||||
|
||||
- **Native Linux client (stage 1).** GTK4/libadwaita app that links `punktfunk-core`
|
||||
directly: mDNS host list, TOFU + SPAKE2 PIN pairing, FFmpeg HEVC decode, PipeWire audio
|
||||
with mic uplink, SDL3 gamepad capture with rumble/lightbar feedback, layout-independent
|
||||
keyboard, absolute mouse, fullscreen, and a stats overlay. VAAPI → `GdkDmabufTexture`
|
||||
zero-copy decode on Intel/AMD with a proven software fallback.
|
||||
- **Delegated pairing approval.** An unpaired device that knocks on a pairing-required host
|
||||
appears as a pending request in the web console's Pairing page; one click approves and
|
||||
pins its certificate — no PIN fetched out of band.
|
||||
- **Concurrent sessions.** The host serves multiple clients at once (bounded by an NVENC
|
||||
limit), each with its own virtual output and encoder — e.g. stream the same desktop to a
|
||||
laptop and a TV simultaneously.
|
||||
- **Cross-machine latency HUD + wall-clock skew handshake.** A short NTP-style handshake
|
||||
aligns client and host clocks, making capture-to-reassembled latency valid across
|
||||
machines; the Apple client surfaces a skew-corrected capture-to-receipt p50/p95 in its
|
||||
HUD.
|
||||
- **Native LAN auto-discovery.** Hosts advertise `_punktfunk._udp` over mDNS (with TXT
|
||||
records carrying the protocol, cert fingerprint, and pairing requirement); clients
|
||||
discover and list them automatically.
|
||||
- **1 Gbps data plane.** Batched `sendmmsg`/`recvmmsg`, a microburst-capped paced send
|
||||
thread, and larger socket buffers, exploiting the GF(2¹⁶) Leopard FEC that breaks the
|
||||
classic ~1 Gbps GameStream ceiling.
|
||||
- **Boot appliance.** A headless compositor session plus host systemd units, so a host can
|
||||
come up and stream with no interactive login.
|
||||
- **Network speed test + settable bitrate.** Bitrate negotiation and an in-band bandwidth
|
||||
probe inform the client's bitrate picker instead of guesswork.
|
||||
- **Rich DualSense.** A full UHID DualSense backend on the host (gamepad, motion, touchpad,
|
||||
lightbar, player LEDs, adaptive triggers) with feedback carried back to the clients.
|
||||
- **AV1 + surround audio** are implemented and unit/live-capture tested.
|
||||
|
||||
## In flight / next
|
||||
|
||||
See the [Roadmap](/docs/roadmap) for the ordered list. Near-term:
|
||||
- **True glass-to-glass**: Apple client present-stamp (decode→present) + host render→capture term.
|
||||
- **Apple stage-2 presenter** (`VTDecompressionSession` → `CAMetalLayer`) — built + decode-unit-tested + live-validated on glass behind the `punktfunk.presenter` flag (capture→present ~11 ms p50); make it the default after a few resolution/HDR checks.
|
||||
- **Mandatory PIN pairing + delegated pairing approval** (an already-paired device approves a new one).
|
||||
- **gamescope multi-user isolation** — per-session input/audio so concurrent sessions are independent
|
||||
desktops (the shared-desktop multi-view case landed).
|
||||
- **bazzite** kept up to date (currently offline; one rebuild behind).
|
||||
|
||||
- **True glass-to-glass latency** — combine the client present-stamp (decode → present)
|
||||
with the host render → capture term for a complete end-to-end number.
|
||||
- **Make the Apple stage-2 presenter the default** after a few more resolution/HDR checks.
|
||||
- **On-glass validation of the Windows client** (D3D11VA decode, HDR present, GUI) on real
|
||||
GPU hardware.
|
||||
- **gamescope multi-user isolation** — per-session input/audio so concurrent sessions can
|
||||
be fully independent desktops (the shared-desktop multi-view case already works).
|
||||
|
||||
Reference in New Issue
Block a user