93902ff60efde2c6c0db6ff9e147acccd07bb7df
8
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
5db93c1156 |
fix(packaging/windows): a release must not sign itself with a throwaway cert
Both pack scripts fell back to a fresh `New-SelfSignedCertificate` whenever MSIX_CERT_PFX_B64 was absent, and said nothing about it beyond one Write-Host. That fallback is right for canary and dev builds. On a tag it is not: an ephemeral cert is regenerated per build, so nobody can pin it, and a release signed with one is indistinguishable from a release signed by whoever else got to the artifact. A secret that got renamed, rotated away, or simply wasn't inherited by a new workflow would have downgraded a real release silently and shipped it. pack-msix.ps1 and pack-host-installer.ps1 now resolve -RequireSignedCert (default 'auto' = true iff GITHUB_REF is refs/tags/v*) and throw instead of falling back; pack-host-installer.ps1 also refuses -NoSign on the same condition. Reading GITHUB_REF inside the scripts rather than taking a workflow flag means a future packaging workflow inherits the guard instead of having to remember it. No effect on today's releases: MSIX_CERT_PFX_B64 / MSIX_CERT_PASSWORD are both set as repo secrets, so the supplied-cert branch is the one tag builds take. This only closes the trapdoor underneath it. Verified on the windows-amd64 runner: both files parse, and the guard resolves true for refs/tags/v0.21.0, false for refs/heads/main and for an unset ref, with 'true'/'false' overriding as intended. Not touched: the pf-vdisplay / gamepad driver builds use the same pattern with DRIVER_CERT_PFX_B64, which has no secret behind it — those need attestation signing (a Partner Center action), and a guard there would just fail every tag. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
bf98102714 |
feat(packaging): ship punktfunk everywhere, and deprecate the session's stray pairing flag
ci / web (push) Successful in 57s
ci / docs-site (push) Successful in 1m5s
android / android (push) Canceled after 3m17s
apple / swift (push) Canceled after 3m18s
apple / screenshots (push) Canceled after 0s
arch / build-publish (push) Canceled after 3m18s
ci / rust (push) Canceled after 3m19s
ci / rust-arm64 (push) Canceled after 3m20s
ci / bench (push) Canceled after 3m18s
deb / build-publish (push) Canceled after 2m23s
deb / build-publish-host (push) Canceled after 2m13s
deb / build-publish-client-arm64 (push) Canceled after 0s
decky / build-publish (push) Canceled after 0s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Canceled after 0s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Canceled after 0s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Canceled after 0s
docker / build-push (ci, ci/rust-ci-noble.Dockerfile, punktfunk-rust-ci-noble) (push) Canceled after 0s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Canceled after 0s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Canceled after 0s
docker / build-push-arm64cross (push) Canceled after 0s
docker / deploy-docs (push) Canceled after 0s
flatpak / build-publish (push) Canceled after 2s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Canceled after 0s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Canceled after 0s
windows-host / package (push) Canceled after 3m25s
windows-host / winget-source (push) Canceled after 0s
windows-msix / package (arm64, C:\Users\Public\ffmpeg-arm64, --no-default-features, aarch64-pc-windows-msvc, C:\t-a64) (push) Canceled after 0s
windows-msix / package (x64, C:\Users\Public\ffmpeg, , x86_64-pc-windows-msvc, C:\t) (push) Canceled after 0s
windows / build (aarch64-pc-windows-msvc) (push) Canceled after 0s
windows / build (x86_64-pc-windows-msvc) (push) Canceled after 0s
The rest of C1. A CLI that only exists in a dev tree is not a door anyone can use, so it now builds and installs in deb, rpm, arch, nix, flatpak and MSIX alongside the client and the session. On Windows it gets its own `AppListEntry="none"` application with the alias `punktfunk.exe` — a command, not a Start-menu tile — which is what the Playnite importer will shell to for `punktfunk library <host> --json`. `punktfunk-session --pair` prints a deprecation notice and forwards. Pairing is a trust ceremony and belongs to the brain, fronted by `punktfunk pair` or a shell; a renderer owning one is precisely the mixing of concerns this split exists to undo. It keeps working for a release, because someone's provisioning script is calling it today. Decky's invocations are untouched and verified still working (`--list-hosts` JSON shape unchanged, `--reachable` exit codes unchanged): those flags are a frozen compat contract until Decky migrates to the verbs at its own pace. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
2508b72062 |
feat(client/windows): make the console UI findable, and launchable on its own
Two problems, one feature. The gamepad/couch UI existed but you had to
already know it was there:
- On the hosts page its card only rendered when a controller was CONNECTED,
so with no pad plugged in there was no visible entry point at all -- the
only other door being a per-host overflow menu behind a "..." nobody
opens. The card now always shows, with copy that adapts to whether a pad
is present, so the feature is findable before you own the hardware.
- There was no way to start it directly. An HTPC or TV box wants the couch
interface as its first screen, not the desktop shell. "punktfunk-client
--console" now hands straight off to it (fullscreen unless --windowed),
which covers shortcuts, Steam entries, autostart and Task Scheduler.
The Start-menu tile needs its own executable: an MSIX <Application> cannot
pass arguments to a full-trust exe, so "punktfunk-client.exe --console" is
not expressible there. punktfunk-console.exe is a ~20-line hand-off to the
session binary's browse mode, staged into the package and given its own
tile ("Punktfunk Console").
Nothing new is implemented behind either door: a bare "--browse" was
already a complete standalone client (host list, discovery, PIN pairing,
settings, Wake-on-LAN, library). It just had no front door.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
||
|
|
d6647b9183 |
feat(clients/windows): port the Vulkan session client to Windows — session-always
The punktfunk-session Vulkan client (clients/linux-session, now clients/session) builds and runs on Windows; the WinUI shell spawns it for every stream. Verified live: 10-bit HEVC via Vulkan Video on both AMD (iGPU) and NVIDIA, 5120x1440 at 130 fps / 8 ms end-to-end on the RTX 4090. - pf-ffvk: Windows bindgen branch (FFMPEG_DIR + PF_FFVK_VULKAN_INCLUDE, no pkg-config); provisioning fetches Vulkan-Headers (pinned v1.4.309). - pf-client-core: builds on Windows — WASAPI audio (audio_wasapi.rs, cfg-swapped via #[path], same surface as the PipeWire twin), VAAPI/dmabuf gated inline (chain = vulkan -> software), trust reads the WinUI shell's %APPDATA% stores (parity tests pin both serialized shapes), Settings gains adapter/hdr_enabled (serde-defaulted; Linux stores unaffected). - pf-presenter: builds on Windows — dmabuf module Linux-gated; SDL keyboard grab while captured (Alt+Tab/Win reach the host); pick_device ranks discrete over integrated (device 0 was the iGPU on hybrid boxes — the silent footgun) and honors PUNKTFUNK_VK_ADAPTER (the Settings GPU pick, exported by the session). - run loop: block in one SDL wait woken by input AND decoded frames (a per- session forwarder pushes a FrameWake user event) instead of a 1 ms poll — measured 111%% -> 5%% of a core (NVIDIA), 86%% -> 3.5%% (AMD), stats unchanged. The pump's decode-fence wait became once-per-window sampling (no per-frame pipeline stall; the stat now shows true backlog). - pf-console-ui: builds on Windows (skia-safe msvc prebuilts); font lookup falls through fontconfig aliases to concrete DirectWrite families (Consolas/Segoe UI) — browse/coverflow works, verified against a live host. - WinUI shell: session-always via new src/spawn.rs (GTK spawn.rs port — CREATE_NO_WINDOW, stdout contract, kill handle); the Stream screen is a status card (chips + stage lines from the child's stats). The legacy in-process D3D11VA path stays behind Settings "Streaming engine" / PUNKTFUNK_BUILTIN_ STREAM=1 as the A/B baseline until Phase 8 deletes it. SessionParams.video_caps makes the HDR toggle real. - clients/linux-session renamed to clients/session (builds for both OSes). - CI/MSIX: both workflows build/test both bins with widened path filters; the MSIX ships punktfunk-session.exe. ARM64 session builds --no-default-features (rust-skia has no aarch64-pc-windows-msvc prebuilts; flip when it does). A/B on this box (5120x1440 HEVC vs home-worker-5): NVIDIA Vulkan 130 fps / 8 ms e2e / 1.6 ms decode — clearly better than the built-in path. The AMD iGPU VCN saturates at ~52 fps where its own D3D11VA does ~70 — Adrenalin Vulkan decode is slower on APU silicon; discrete RDNA validation gates Phase 8. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
1f5a2e4920 |
feat(clients/windows): all-vendor video pipeline rewrite + app icon + hosts-page tiles
Decode+present rewrite (first real pixels on glass for this client): - Decode: FFmpeg D3D11VA on NVIDIA/AMD/Intel. get_format now only returns AV_PIX_FMT_D3D11 and lets libavcodec build the decode pool from hw_device_ctx (hand-built frames contexts failed three different ways: NVIDIA rejects DECODER|SHADER_RESOURCE arrays, BindFlags=0 fails texture creation, Intel rejects non-128-aligned HEVC surfaces at the first SubmitDecoderBuffers). A DXVA profile probe before the hwdevice commits hardware-vs-software up front instead of burning the opening IDR; extra_hw_frames covers the frames the client holds. - Present: the decoded slice is copied with ONE display-size-boxed CopySubresourceRegion (a planar slice is a single subresource in D3D11; the old two-copy D3D12-style code silently no-opped - the black screen) into a sampleable NV12/P010 texture, per-plane SRVs + YUV->RGB shaders. - New dedicated render thread (render.rs): presenting is decoupled from the XAML thread; frame-latency-waitable swapchain + SetMaximumFrameLatency(1), newest-wins drain after the wait, crossbeam frame channel with pts for a capture->presented p50 log. - HiDPI: pixel-sized buffers + SetMatrixTransform(96/dpi) - was blurry at 125/150 % scaling. - Software fallback now feeds the same shaders (swscale -> NV12/P010 planes -> two dynamic plane textures); ps_rgba/X2BGR10 path deleted, hw/sw colour math identical. - Adapter selection for hybrid boxes: PUNKTFUNK_ADAPTER > the window's monitor's adapter > default; PUNKTFUNK_D3D_DEBUG=1 debug layer. - Session pump: request_keyframe at start and on hw->sw demotion (infinite GOP would otherwise sit on a black screen). Validated live on the Arc Pro + RTX 3500 Ada laptop against the local Windows host: 60 fps D3D11VA on both vendors, software path, GUI on glass. Also: embedded app icon (build.rs winresource + WM_SETICON, MSIX Square44x44 targetsize assets, pack-msix stages them) and the hosts-page tile rework (tap-to-connect tiles with sibling overflow menu - fixes forget-also-connects - in-tile rename editor, add-host modal via root state). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
f7a9549cd1 |
chore(licensing): LGPL FFmpeg swap, third-party notices, attribution hygiene
The MIT OR Apache-2.0 SOURCE license is clean (audit found no copied copyleft); the
gaps were all binary-distribution (Layer-2). This makes the shipped artifacts honest:
- Windows host + client: bundled FFmpeg BtbN gpl-shared -> lgpl-shared (AMF/QSV/decode
unaffected; the GPL-only x264/x265 were never used), and ship the FFmpeg LGPL notice
+ license text in the installer + MSIX (licenses/).
- THIRD-PARTY-NOTICES.txt generated + bundled into installer/MSIX/deb/rpm. Offline
generator (scripts/gen-third-party-notices.{py,sh}) + cargo-about config (about.toml/
.hbs) with a permissive-only accepted-license allow-list as a copyleft regression gate.
- Reword the win32u GPU-preference hook comments to reflect independent reimplementation
(no Apollo/Sunshine GPL-3.0 source copied).
- README dual-license + inbound=outbound contributor clause + non-affiliation trademark
disclaimer; new CONTRIBUTING.md.
- LICENSE files into the standalone driver + vk-layer workspaces; deb copyright holder
aligned to "unom and the punktfunk contributors".
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
||
|
|
67d58bfde3 |
feat(windows-client): cross-compile + ship ARM64 (aarch64) off the x64 runner
windows.yml + windows-msix.yml gain an x86_64/aarch64 target matrix. ARM64 is cross-compiled on the one x64 Windows runner — the x64 MSVC toolset ships the ARM64 cross compiler, aarch64-pc-windows-msvc is tier-2 with host tools, and SDL3/libopus (build-from-source) cross-compile cleanly. The only arch-specific external dep is FFmpeg's import libs: the matrix points FFMPEG_DIR at a per-arch tree (x64 C:\Users\Public\ffmpeg, arm64 C:\Users\Public\ffmpeg-arm64, both FFmpeg 7.x / avcodec-61). Per-arch short CARGO_TARGET_DIR avoids a shared target dir; fmt + test run only for x64 (aarch64 can't execute on the x64 host). pack-msix.ps1 gains -Arch x64|arm64 (stamps the manifest ProcessorArchitecture, arch-suffixes the .msix/.cer); windows-msix.yml matrixes both arches and publishes ..._x64.msix / ..._arm64.msix. setup-windows-runner.ps1 provisions the rustup target + the ARM64 FFmpeg tree (idempotent). Verified live on the runner (home-windows-1): debug+release cross-build green, clippy -D warnings green, and MSIX pack produces a valid arm64 package (manifest arch=arm64; bundled exe/SDL3/avcodec/reactor-bootstrap all PE machine 0xAA64). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
2f2147b093 |
refactor: drop milestone names + consolidate clients; loss-recovery & rumble fixes
Two bodies of work in one commit (the rename moved files the fixes also touched). Naming/structure cleanup (pre-launch): - Host modules m3.rs->punktfunk1.rs, m0.rs->spike.rs; CLI m3-host->punktfunk1-host, m0->spike; bare `punktfunk-host` now prints help. Types M3Options/M3Source-> Punktfunk1Options/Punktfunk1Source. - Clients consolidated out of crates/ into clients/: punktfunk-client-rs-> clients/probe (crate punktfunk-probe), client-linux->clients/linux, client-windows->clients/windows, punktfunk-android->clients/android/native (crate punktfunk-client-android; kept [lib] name=punktfunk_android so the JNI contract is unchanged). crates/ now holds only core + host. - Milestone codes M0-M4 purged from code/CLI/CLAUDE.md/README/docs/docs-site, kept only in docs/implementation-plan.md. docs/m2-plan.md-> docs/gamestream-host-plan.md. CI/gradle/flatpak paths updated. Client loss-recovery (video froze and never recovered after a brief drop): - Export punktfunk_connection_frames_dropped through the C ABI (the core already tracked it for the client keyframe-recovery loop; it was never reachable from the ABI clients). Regenerated punktfunk_core.h. - Apple (StreamPump + Stage2Pipeline) and Android (decode.rs) now poll frames_dropped and request a keyframe when it climbs -- the same loss-driven recovery Linux/Windows already had. Under infinite GOP the decoder silently conceals reference-missing frames, so the decode-error trigger rarely fires. Apple rumble robustness (worked then went spotty -- DualSense + Xbox): - Add CHHapticEngine stopped/reset handlers (rebuild on app background / audio interruption / server reset) and drop the permanent `broken` latch on a transient drive failure; latch only when the controller truly has no haptics. - Surface swallowed SDL set_rumble errors on Linux/Windows + diagnostic logging. Verified: cargo build/clippy/fmt --workspace, C-ABI harness, header drift. Not runnable on this box (verify in CI): Gitea workflows, gradle/Android, flatpak, Swift/decky. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |