e35dad529b316bb74bb56cb4f1cfd763d0f81328
11
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
e35dad529b |
fix(vdisplay/gamescope): DM-flavor-aware session takeover — stop masking Nobara's plasmalogin to death
Field report (Nobara 43 HTPC): switching the host to Steam Game Mode mid-stream permanently black-screened the box. Live-proven root cause on a Nobara repro VM: our takeover masks the box's gamescope-session-plus unit, plasmalogin's Relogin=true then fails its session Exec repeatedly and trips systemd's start limit within ~1 s — the display manager dies, and our restore verb (unmask + user start) cannot bring a seatless gamescope back. Only 'reset-failed + restart' of the DM recovers. The takeover is now display-manager-flavor-aware: - SDDM (Bazzite/SteamOS) keeps the proven mask+SIGKILL path unchanged. - plasmalogin/unknown DMs never mask: with privilege (root or an operator polkit rule scoped to the DM unit — documented) the host stops the DM for the stream and restores it with reset-failed + restart (PUNKTFUNK_RECOVER_SESSION_CMD as fallback), recorded in the persisted takeover state so a host crash still restores; without privilege the managed takeover degrades to ATTACH and mirrors the box's live Game Mode instead of destabilizing the seat. Both legs of the privileged cycle live-verified on the repro VM (headless managed session works with zero login sessions; render nodes are 0666). A loaded-but-inactive leftover instance never triggers the DM stop. Companion fixes from the same triage: - ensure_box_gamescope_mode gains the attach-only rebuild-probe guard both managed paths already had (stale post-capture-loss detection restarted the box's unit), and no longer re-modes a box that drives a physical display — attach mirrors on-glass; re-mode is the headless-box model. - Capture-loss rebuilds targeting gamescope get a 100 s budget: the 40 s budget expired inside the first 45 s Steam-cold-start launch attempt, a guaranteed single-shot failure. - A PUNKTFUNK_COMPOSITOR pin now WARNs once per capture loss when the live session no longer matches it (the pin disables session-following — the reporter's original stream-death trigger). - A managed session that took nothing over (client gamescope pin beside a live desktop) is stopped on disconnect instead of being orphaned forever. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
6617275387 |
docs(env): stop teaching the compositor pin + uid-1000 anchors in starters
ci / docs-site (push) Successful in 54s
ci / web (push) Successful in 59s
apple / swift (push) Successful in 1m21s
decky / build-publish (push) Successful in 28s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 25s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 14s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 10s
ci / bench (push) Successful in 6m23s
docker / build-push (ci, ci/rust-ci-noble.Dockerfile, punktfunk-rust-ci-noble) (push) Successful in 4m43s
apple / screenshots (push) Successful in 6m18s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 1m9s
arch / build-publish (push) Successful in 13m44s
deb / build-publish (push) Successful in 13m48s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 7m39s
deb / build-publish-host (push) Successful in 13m11s
docker / deploy-docs (push) Successful in 32s
android / android (push) Successful in 16m23s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 15m15s
ci / rust (push) Successful in 24m12s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 14m55s
Field triage (Nobara, Discord): the kde.md starter host.env told desktop users to set PUNKTFUNK_COMPOSITOR=kwin, which PINS the backend — detect() short-circuits and the capture-loss rebuild never re-detects — so a mid-stream switch to Game Mode killed the stream instead of following it. A follow-up hardcoded XDG_RUNTIME_DIR=/run/user/1000 anchor broke PipeWire for any non-1000 uid (pw audio connect: Creation failed). Revamp across every starter/example/reference: - Desktop starters (kde/gnome/hyprland/sway) shrink to PUNKTFUNK_VIDEO_SOURCE=virtual + an explicit warning that pinning disables session-following; forcing a backend is CI/appliance-only. - host.env.example: rewritten around auto-detection; anchors demoted to a commented ssh/cron-only block with the uid trap spelled out; the gamescope ATTACH/MANAGED knobs documented (previously missing); case-sensitivity called out. - packaging/bazzite/host.env + README: drop the uid-1000 anchors (a systemctl --user service inherits/derives them); README's stale PUNKTFUNK_COMPOSITOR=gamescope-era template synced to the real one. - packaging/kde/host.env: loud APPLIANCE-ONLY header (it pins on purpose). - configuration.md: session-anchors section inverted to "leave unset", compositor row states the pin consequence, case-sensitivity note. - troubleshooting.md: new "session fails right after editing host.env" section (case, wrong-uid anchors, stale pin, restart-to-apply). - gamescope.md/bazzite.md: attach/managed descriptions match current behavior (managed is the infra-detected default; attach re-modes a box-owned session to the client's resolution). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
11045a0f70 |
chore: consolidate parallel-session WIP (HOLD — do not push)
Local snapshot of intermingled in-flight work, committed to unblock the encode
refactor (a clean ffmpeg_win.rs for the vbv-dedup follow-on). These hunks span
the same files and can't be cleanly split here; the commit bundles three
distinct workstreams that each belong in their own PR:
- logging rework (~43 files: level re-tiering, structured fields, `?e`,
hot-path flood latches)
- conflicting-host detection (detect.rs + detect/{linux,windows}.rs + wiring
in main.rs/mgmt.rs/Cargo.toml/docs/packaging)
- standby-sink DWM-stall attribution (windows/display_events.rs + capture/
vdisplay wiring)
NOT verified as a combination. NOT to be pushed until the refactor is done and
these are re-verified and reorganized into their proper per-workstream PRs.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
||
|
|
76791e53e9 |
docs: restructure host setup by distro, configuration by compositor
Split the docs' single distro×desktop axis (ubuntu-gnome / ubuntu-kde / fedora-kde) into two,
which deduplicates the shared mechanics and scales to distros that run several desktops (Arch):
- Install the host — per distro/OS (ubuntu, fedora, arch, bazzite, steamos-host, windows-host):
GPU driver + package + input group, then a canonical "Configure your desktop" funnel.
- Configure your desktop — per compositor (kde, gnome, gamescope, sway): host.env, compositor
quirks, the headless session, and starting the host.
New shared web-console page (enable · login password · arm pairing) removes the console/password
block that was copy-pasted across all seven host pages. Merged ubuntu-gnome + ubuntu-kde into
ubuntu; renamed fedora-kde to fedora; kept bazzite and steamos-host as dedicated appliance guides
(trimmed of duplication). Moved the KWin headless session, the GNOME EGL/lock traps, and the
gamescope attach/managed model out of the distro pages onto their compositor pages.
Fixed while restructuring: distro-specific paths on kde (kde-desktop-setup.sh is Fedora/Bazzite-only;
the .deb ships host.env.kde under /usr/share/punktfunk-host), the interactive "start the host" step
that was lost in the merge, sway over-claiming Hyprland, and a pre-existing broken anchor in
how-it-works.
Removal of the three old pages was captured by the preceding commit
|
||
|
|
5c6ae43ed2 |
feat(punktfunk1): configurable data-plane UDP port (--data-port)
The native data plane used a random ephemeral UDP port (hole-punched), which a strict firewall can't pre-open — so remote clients behind one couldn't connect. Add an optional fixed data port: - `Punktfunk1Options`/`NativeServe` gain `data_port`; `bind_data_socket` binds the fixed port (→ direct, no hole-punch) or falls back to a random port + hole-punch when unset or the fixed port is busy (a concurrent session already holds it). - `UdpTransport::from_socket`/`from_socket_punch` adopt an already-bound socket, so the host keeps the SAME data socket from handshake through streaming — no drop-then-rebind window in which a concurrent session could steal a fixed port. - `main.rs` wires the CLI flag through to `NativeServe`. - Firewall docs updated (troubleshooting.md + apt/pacman/bazzite READMEs): control plane is the fixed UDP 9777; the data plane is a separate random port that usually needs no rule, with the fixed-port option for strict firewalls. Unit-tested: default random+hole-punch, and fixed-port-then-fallback-when-busy. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
b292ce2c1f |
fix(packaging/windows): Windows 11 22H2 floor + tray install task + stale console-port fixes
The OS floor is now enforced at install time (MinVersion=10.0.22621 with an explanatory [Messages] override): pf-vdisplay is built against IddCx 1.10, and on Windows 10 (incl. LTSC) / Win11 21H2 the device fails start with Code 10 STATUS_DEVICE_POWER_FAILURE (field-reported). Docs (site requirements/install/ windows-host pages + README) state the floor; new docs-site Security page. Installer also gains the trayicon task (punktfunk-tray.exe file + HKLM Run key, post-install launch as the signed-in user, upgrade taskkill + uninstall --quit/taskkill choreography before file deletion), and the wizard/cleanup text/port sweeps move off the stale :3000 web-console references to :47992 (cleanups sweep both for upgrades from old installs). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
6e41356919 |
feat(protocol,clients): codec preference negotiation + Linux client decodes per Welcome (Phase 2a)
Adds a client-selectable **preferred codec** and wires the core + ABI + probe + Linux client to
negotiate and decode it. (Windows/Apple/Android follow in 2b.)
**Core:**
- `Hello.preferred_codec` (a single CODEC_* bit, 0 = auto) — a soft hint appended after
`video_codecs`. `resolve_codec(client, host, preferred)` now honors the preference when the host
can also emit it, else falls back to precedence (HEVC > AV1 > H.264). Roundtrip + preference tests.
- `NativeClient::connect` takes `video_codecs` + `preferred_codec`; `NativeClient.codec` exposes the
resolved `Welcome.codec`.
- ABI: `punktfunk_connect_ex7` (adds the two codec params; `ex6` delegates to it advertising
HEVC-only) + `punktfunk_connection_codec` getter + `PUNKTFUNK_CODEC_{H264,HEVC,AV1}` constants
(drift-guarded against the wire values). Header regenerated.
**Host:** passes `hello.preferred_codec` into `resolve_codec`.
**probe:** `--codec h264|hevc|av1|auto` sets the preference (still advertises it can decode all
three); the dump extension already follows the resolved codec.
**Linux client:** advertises the codecs FFmpeg can actually decode (`decodable_codecs()`), threads
the user's `codec` setting as the preference, and builds the decoder — both the software and VAAPI
paths, plus the mid-session VAAPI→software demotion — from the negotiated `Welcome.codec` instead of
hardcoding HEVC. New "Video codec" dropdown in Preferences (Automatic/HEVC/H.264/AV1).
Live-validated on the dev box: probe `--codec hevc` against a software (H.264-only) host resolves to
H.264 (graceful soft-preference fallback), no failure. clippy + core (57) + host (133) tests green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
||
|
|
0de648f106 |
feat(host): GameStream/Moonlight compat is now opt-in (--gamestream) — secure native-only by default
Follows the security audit (#5/#9): the GameStream-compat plane carries inherent on-path weaknesses that can't be fixed on the wire without breaking stock Moonlight — its pairing runs over plain HTTP (#9, MITM-able during the pairing window) and its legacy control encryption can reuse GCM nonces (#5, a passive eavesdropper can recover/forge input). The native punktfunk/1 plane (SPAKE2 PIN pairing + per-direction AEAD nonces) has neither. So flip the default to secure-by-default: - `serve` → native punktfunk/1 plane + management API ONLY (no GameStream surface). - `serve --gamestream` → ALSO the GameStream/Moonlight-compat planes (nvhttp pairing, RTSP, ENet control, _nvstream mDNS). Opt-in, logged with a trusted-LAN caveat. `--moonlight` is an alias. - The native plane is now ALWAYS on in `serve` (`--native` is a kept-for-compat no-op); the unified GameStream+native host is `serve --gamestream`. `gamestream::serve` gates the GameStream spawns (nvhttp/rtsp/control/mdns) on the flag; the native plane + mgmt + native-pairing handle always run. To avoid silently regressing validated Moonlight deployments, the explicit deployment configs PRESERVE Moonlight via `--gamestream` (each documents dropping it for a secure native-only host): the Linux systemd unit, the Steam Deck installer, and the Windows service default (DEFAULT_HOST_CMD). The bare `serve` default (new/manual use) is secure. Docs swept to match (host-cli, moonlight, quickstart, install, packaging READMEs, CLAUDE.md, README, …): Moonlight setup now instructs `--gamestream`; native/console refs use bare `serve`. OpenAPI regenerated (a stale "run `serve --native`" string). fmt + clippy clean; 94 host tests green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
0be3183cf2 |
docs: update README + docs site for public readiness
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> |
||
|
|
7de473936b |
docs(dist): end-user install front door + serve/pairing/firewall accuracy fixes
Make the host docs match the real distribution path and the actual CLI. Reviewed by a multi-agent pass (6 editors against one verified fact sheet + an accuracy reviewer); its findings (a wrong client-Recommends claim, a native-concurrency overstatement) folded in. - Install front door: new README "Install (host)" method-picker + docs-site/install.md (+ nav), routing each distro to its package registry; source build demoted to a fallback. - Registry-first install: ubuntu-gnome/ubuntu-kde now lead with the apt registry (not a cargo build); bazzite leads with the Gitea RPM registry (was COPR/source). Source builds moved to an appendix. - CLI accuracy: serve --native arms pairing from the web console (NOT --allow-pairing, which with --require-pairing/--max-concurrent is m3-host-only); --open disables mandatory pairing. host-cli/configuration/pairing/quickstart/troubleshooting corrected; mgmt API documented as always HTTPS+token. Native host serves one session at a time (extras queue) — not multi. - Firewall: real ports documented (native UDP 9777 + the ephemeral data port caveat + GameStream ports) for Debian + Arch (ufw + nftables), not just Bazzite. - Sync/accuracy: punktfunk-client (GTK4) presented as a shipping client (not "roadmap"), punktfunk-client-rs as the headless tool; host Recommends punktfunk-web only (not the client); COPR chroots f43/44; bootc header says Gitea registry not COPR. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
f16bb47218 |
docs: user-facing docs revamp — structured product docs + per-platform setup
Replace the dev/agent-log pages with a proper user-facing doc set: - Getting Started: Introduction (rewritten), How It Works, Quick Start. - Host Setup: Requirements, then clean per-platform guides — Ubuntu GNOME, Ubuntu KDE, Fedora KDE (new), Bazzite (rewritten) — plus Running as a Service (desktop / headless GNOME / headless KDE). - Connecting: Clients overview, Moonlight, Pairing & Trust. - Configuration: host.env reference, Host CLI, Troubleshooting. - The dev/design notes (architecture, roadmap, the deferred design specs, CI) move to a clearly-separated "Project & Internals" nav section. Removes the superseded box-specific pages (gnome-box, headless-box, linux-setup, overview). status.md (the internal progress tracker, with box IPs) is kept as a file but dropped from the public nav. Site builds clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |