• v0.11.0
    ci / web (push) Successful in 45s
    ci / docs-site (push) Successful in 51s
    ci / bench (push) Successful in 6m6s
    windows-host / package (push) Successful in 8m11s
    android-screenshots / screenshots (push) Successful in 4m13s
    windows-msix / package (arm64, C:\Users\Public\ffmpeg-arm64, --no-default-features, aarch64-pc-windows-msvc, C:\t-a64) (push) Successful in 3m9s
    decky / build-publish (push) Successful in 17s
    windows-msix / package (x64, C:\Users\Public\ffmpeg, , x86_64-pc-windows-msvc, C:\t) (push) Successful in 4m7s
    ci / rust (push) Successful in 18m6s
    android / android (push) Successful in 11m58s
    arch / build-publish (push) Successful in 12m2s
    docker / deploy-docs (push) Successful in 9s
    docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 7s
    docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 9s
    docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 10s
    docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 9s
    docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 9s
    flatpak / build-publish (push) Failing after 8m14s
    apple / swift (push) Successful in 5m27s
    linux-client-screenshots / screenshots (push) Successful in 7m23s
    deb / build-publish (push) Successful in 11m57s
    web-screenshots / screenshots (push) Successful in 2m49s
    rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 16m49s
    rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 16m45s
    release / apple (push) Successful in 28m50s
    apple / screenshots (push) Has started running
    Stable

    enricobuehler released this 2026-07-14 22:14:13 +00:00 | 9 commits to main since this release

    Wire-compatible with 0.10.x — no protocol or ABI change (WIRE_VERSION stays 2, the native C ABI stays v6). This is a throughput + controllers release: the transport's measured ceiling moves from ~1.5 to ~4.8 Gbps wire, Automatic bitrate now finds the link's real capacity and rides it without keyframe spikes, four new controller identities land across the clients and both hosts, and the long-standing "rumble and adaptive triggers never work with a Linux host" is root-caused and fixed. The new gamepad kinds ride additive GamepadPref wire bytes an older host simply folds onto an existing pad type — nothing touches the handshake, so any 0.10.x host/client pair keeps working with no re-pairing.

    Multi-gigabit transport

    The receive path was rebuilt for the new ceiling — ~1.5 → ~4.8 Gbps wire between capable endpoints:

    • ARMv8 hardware AES-GCM — every aarch64 client (Apple Silicon, iPhone/iPad, Android, Steam Deck OLED…) was running software crypto; hardware AES was the single biggest wall. Large frames additionally seal on two AES-GCM lanes so encryption no longer serializes a big AU behind one core.
    • Zero-copy pooled reassembly — shards land at their final access-unit offset on arrival; no per-frame reassembly copy, no per-block allocation.
    • FEC encoder reuse — cached erasure codecs + pooled parity buffers; per-block engine setup drops out of steady-state frames (Moonlight wire parity pinned byte-exact).
    • Pace-aware send chunking — pace chunks scale 16→64 packets with the rate so a ≥1 Gbps frame keeps honest inter-chunk sleeps (and ~4× fewer syscalls) instead of collapsing into an unpaced blast; the auto microburst cap scales to a quarter of the frame (PUNKTFUNK_PACE_BURST_KB pins an absolute override).
    • Reordering no longer reads as packet loss — early-FEC-reconstructed shards that then arrive are netted out of the loss estimate, so plain reordering can't inflate LossReports, over-size adaptive FEC, or permanently end the bitrate controller's climb.
    • ObservabilityPUNKTFUNK_PERF=1 prints receive-path stage timing + frame-jitter percentiles; a throughput-sweep script and headless-accurate probe sweeps ship in-tree.

    Automatic bitrate that finds your link

    Automatic now probes the link's capacity and slow-starts up to a measured ceiling instead of sitting on a fixed default — and quality steps got dramatically cheaper: in-place encoder rate reconfigure (NVENC nvEncReconfigureEncoder on Linux + Windows, AMF dynamic properties, Vulkan rate-control update) means an ABR adjustment retargets the encoder mid-stream with no IDR. Verified on hardware: 20→60→10 Mbps live with zero keyframes. Backends without in-place support keep the old rebuild-on-next-IDR path; punktfunk-probe --rebitrate KBPS:SECS validates a host headlessly.

    Four new controller identities

    Clients now declare what's physically in your hands, and the host builds exactly that:

    • DualSense Edge — Linux UHID + Windows UMDF; the four back paddles land on the Edge's native button slots instead of being folded away or dropped.
    • Nintendo Switch Pro Controller — Linux UHID via hid-nintendo; Android also maps the Switch 2 Pro Controller and a paired Joy-Con 2 onto it.
    • Classic Steam Controller — Linux UHID via hid-steam, dual-trackpad layout intact.
    • Steam Deck on Windows hosts — a Steam-Input-promoted UMDF virtual Deck (the &MI_02 interface synthesis Steam's driver filters on), with a Steam-accepted unit serial so the controller name renders clean.

    Under the hood all virtual-pad backends moved onto one shared, unit-tested slot/lifecycle/feedback skeleton (PadSlots + UhidManager) — one place for arrival routing, unplug sweeps, heartbeats, and feedback dedup.

    Rumble + adaptive triggers on Linux hosts — root-caused and fixed

    Game feedback (rumble, DualSense adaptive triggers, lightbar, player LEDs) worked from Windows hosts but effectively never from Linux ones. The capture code was proven correct on real hardware (new on-box tests drive every chain the way a game would); the real causes were access and identity:

    • hidraw access — Steam/SDL drive a DualSense's triggers/lightbar exclusively over hidraw, and without it Steam demotes the pad to a generic evdev device, losing its rumble handling too. The host udev rules now grant the input group the virtual pads' hidraw nodes for every identity we create — no longer dependent on the distro's steam-devices rules plus seat-session ACLs that a headless/dedicated streaming session never gets.
    • Per-pad serials, both hosts — every virtual DualSense/DS4 presented one hardcoded pairing MAC (and on Windows, one USB serial string); SDL/Steam dedup controllers by serial, so a second pad could be merged into the first. Serials now carry the pad index on Linux (UHID pairing replies) and Windows (UMDF feature reports + HidD_GetSerialNumberString).
    • No more 5 s stalls — the UHID PlayStation backends ack SET_REPORT instead of letting writers hang into the kernel timeout.

    Three permanent on-hardware tests pin the whole surface: DualSense evdev-FF + raw hidraw output report (rumble, lightbar, LEDs, and both adaptive-trigger blocks verbatim), uinput X-Box FF upload→mix→stop-on-erase, and usbip Deck rumble via the controller interface.

    Client quality-of-life

    • On-screen keyboard mid-stream — a three-finger swipe up/down shows/hides the device keyboard on iOS and Android (trackpad/pointer modes); scrolling is now an exactly-two-finger gesture on mobile.
    • "Rumble on this phone/iPhone" — opt-in: pad-0 rumble mirrors onto the device's own vibration motor, for motor-less clip-on pads.
    • Linux client decoder orderauto is now device-aware: Vulkan Video first on NVIDIA and all AMD (it outperforms VAAPI on RADV, and the Deck's VanGogh chroma-fringes over VAAPI), VAAPI first on Intel; and a mid-session Vulkan failure streak now demotes to VAAPI instead of software, so a broken Mesa Vulkan path can never strand a box on CPU decode. The GTK settings gain the missing explicit "Vulkan Video" option.
    • Console (gamepad) UI — a touch-mode setting and request-access pairing: a new device can knock and be approved from the host side without typing a PIN.
    • Decky plugin — native-touch controller layout, restructured shortcuts, and store artwork.

    Host & platform fixes

    • Dedicated gamescope session vs. desktop Steam — launching the dedicated session now frees a desktop-session Steam first (Steam is single-instance; the collision black-screened the game library).
    • Headless gamescope env isolation — the managed session no longer inherits a desktop DISPLAY/WAYLAND_DISPLAY.
    • NVIDIA hosts warn loudly when a CUDA session runs a build compiled without the direct-SDK NVENC path (which carries the real loss recovery).
    • Android TV visibility on Google Play — microphone and Wi-Fi permissions no longer imply required hardware features, so TV devices (e.g. Philips OLED TVs) stop being filtered from the listing.
    Downloads