feat(client-linux): native GTK4 client — stage 1, first light at 1080p60
ci / rust (push) Failing after 29s
ci / web (push) Failing after 35s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 5s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 3s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 18s
ci / docs-site (push) Failing after 38s
apple / swift (push) Successful in 1m15s
docker / deploy-docs (push) Successful in 17s
ci / rust (push) Failing after 29s
ci / web (push) Failing after 35s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 5s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 3s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 18s
ci / docs-site (push) Failing after 38s
apple / swift (push) Successful in 1m15s
docker / deploy-docs (push) Successful in 17s
New crate crates/punktfunk-client-linux (binary punktfunk-client), the native Linux client on the Option A architecture (2026-06-12 research): - GTK4/libadwaita shell linking punktfunk-core directly (no C ABI): mDNS host list, TOFU fingerprint prompt, SPAKE2 PIN pairing dialog, preferences (mode/bitrate/gamepad/shortcut capture), stats overlay, --connect host[:port] for scripting. - Video: FFmpeg software HEVC decode (LOW_DELAY, slice threads) -> RGBA -> GdkMemoryTexture inside GtkGraphicsOffload (the dmabuf subsurface path lights up when VAAPI lands; black-background keeps fullscreen scanout-eligible). - Audio: Opus -> PipeWire playback stream, the host virtual-mic's adaptive jitter ring inverted. - Input: keyboard as the exact inverse of the host VK table (evdev keycodes, layout-independent; unit-tested), absolute mouse through the Contain-fit transform, WHEEL_DELTA(120) scroll, compositor shortcut inhibition while streaming, Ctrl+Alt+Shift+Q release chord, F11 fullscreen. SDL3 gamepad capture (single pad-0 model) + rumble and DualSense lightbar feedback on the same thread. - Session pump owns video+audio pulls; the gamepad thread owns rumble+hidout — possible because NativeClient's plane receivers are now mutexed, making it Sync (Arc-shared, compiler-verified per-plane contract instead of the ABI's manual assertion). - Linux-gated deps + a stub main keep cargo build --workspace green on macOS. Validated live against serve --native on this box: 1920x1080@60, locked 60 fps, capture->decoded p50 ~6.4 ms (software decode, debug build). Teardown keys off AdwNavigationPage::hidden — NavigationView push fires a transient unmap/map cycle that must not end the session. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -14,7 +14,7 @@ and the design in the [Implementation Plan](/docs/implementation-plan); this pag
|
||||
| **M1** — `punktfunk-core` + C ABI (protocol · FEC · crypto) | ✅ complete & hardened |
|
||||
| **M2** — GameStream host (Moonlight-compatible) | ✅ working end-to-end; HDR/surround-audio polish open |
|
||||
| **M3** — `punktfunk/1` native protocol (QUIC control + UDP data) | ✅ full session planes, validated live |
|
||||
| **M4** — native client decode + present (Apple first) | 🟡 stage 1 live; stage-2 presenter built + decode-tested (opt-in, present needs live validation) |
|
||||
| **M4** — native client 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) |
|
||||
|
||||
## Live on the boxes
|
||||
|
||||
@@ -29,6 +29,21 @@ All three appliances advertise over mDNS (`_punktfunk._udp`) and require PIN pai
|
||||
## Progress log
|
||||
|
||||
### 2026-06-12
|
||||
- **Native Linux client — stage 1, first light** (`crates/punktfunk-client-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
|
||||
|
||||
Reference in New Issue
Block a user