180 commits since v0.27.0. Cut from origin/main9c133350. THE NUMBER: 0.28.0, not 0.27.1. The CHANGELOG's in-development section was titled "v0.27.1", which the release does not support — 17 `feat(...)` commits, a packager-visible default flip (GameStream opt-in on every route), the edition-2024 MSRV rise, and now a genuinely BREAKING host change (the built-in library scanners are deleted). `scripts/ci/pf-version.sh`'s canary rule agrees independently: CI already stamps canaries `0.28.<run>`. TWO DEFECTS FOUND AND FIXED WHILE PREPARING, both pre-existing on main: 1. C ABI_VERSION was stale at 18. Two exported symbols landed since v0.27.0 without a bump — punktfunk_connection_note_frame_index_ex and punktfunk_reanchor_gate_arm_expecting_drops (72 -> 74 declarations in include/punktfunk_core.h). The constant's own doc history makes the rule explicit: v17 and v18 each bumped for adding exactly one symbol. Bumped to 19 with its doc entry; the header is regenerated (cbindgen, CI-gated) and the C ABI harness passes printing abi_version=19. 2. docs-site/public/openapi.json had drifted to 0.21.0 against api/openapi.json, missing five endpoints. The copy is a documented manual step that nothing in CI enforces (CONTRIBUTING.md says so outright). Re-synced — and then it DRIFTED AGAIN inside this same cycle when the scanner-removal regen updated api/openapi.json alone, so it is re-synced a second time and the CHANGELOG now says to treat the copy as part of regenerating, not a follow-up. ⭐ The final docs batch also invalidated a line in this CHANGELOG: the identity section still said the P-256 key was "generated by ring via rcgen", which contradicted this same document's "ring is gone from the tree entirely". Corrected to "rcgen on the workspace's aws-lc-rs backend", matching92db6651. api/openapi.json stays stamped 0.27.0: it cannot be regenerated here (punktfunk-host does not compile on macOS) and does not need to be — the drift test normalizes info.version, so only the SURFACE is gated, and the surface is current. CHANGELOG: retitled to v0.28.0, gained the version table (wire 2 unchanged; C ABI 18->19; edition 2021->2024 and MSRV 1.82->1.85; driver protocol 6 and gamepad channel 3 unchanged; plugin-kit 0.4.0->0.4.1), a breaking-changes section, and ~29 topics the in-development text predated — including the four that landed last: the scanner->plugin migration, the Mutter rebuild serialization, the KWin <=60 Hz readback, and the Apple/Android de-prime fuse. ⭐ THE BREAKING ONE, stated plainly in both halves: the six built-in library scanners are DELETED and the library is assembled entirely by plugins. There is deliberately no migration — a plugin claims its store and republishes each title under the same `<store>:<external_id>` id, so entry ids, GameStream app ids, art caches, Moonlight pins, per-source toggles and per-entry hides all keep working. The one visible consequence, and the whole upgrade note: a host with NO library plugins installed has an empty grid. ⭐⭐ The Mutter two-client segfault this release now fixes (a5c9b7b8) is the one found during THIS release's on-glass validation: chaining two clients through a kept display killed gnome-shell in meta_monitor_manager_rebuild. It was A/B'd on .21 against the released 0.27.0 and shown byte-identical there, so it was never a 0.28.0 regression — and the fix's own commit message cites that A/B. GATES RUN, all green on this commit (re-run after the rebase onto86cbbea0): cargo fmt --all --check clean cargo metadata --locked OK against the new dependency tree Cargo.lock versions-only vs origin/main, 36/36 lines cargo test -p punktfunk-core 210 passed c_abi harness PASS, abi_version=19 (needs LIBRARY_PATH for opus on macOS; a link path, not a defect) docs-site build exit 0 (bun install --frozen-lockfile + build) Play notes gate 440/500 CHARACTERS, not byte-identical to any other release (`•` is 3 bytes — count characters, as the gate does) notes voice check 0 hits above `## For developers`; TL;DR at 6 bullets (README caps it at six) ON-GLASS (against the canary of14425716, code-identical bar ABI_VERSION): Windows .173 0.28.13309 + Android and iPad, Linux .21 0.28.0-0.00013300 + iPhone — both PASS. The idle sleep-blocker fix is proven before/after on .173 (`powercfg /requests` SYSTEM: the mic devnode -> "Keine."), and the GameStream flip is proven at the socket level on .21 (47984/47989/47999 absent by default, restored by PUNKTFUNK_GAMESTREAM=1). Old-client compat holds: Android 0.26.0 streams against the 0.28.0 host. ⏳ NOT re-validated: the Mutter fix itself. .21 (VM 103) is stopped — it and home-bazzite-2 (VM 119, currently running) share one passed-through GPU, so bringing .21 up would stop the other VM. Owed once .21 is free; the repro is iPhone 2868x1320 -> SIGTERM -> Android 2800x1260, and the marker to confirm the build carries the fix is the string "mutter: waited out a monitor-topology rebuild before releasing the lock". NOT INCLUDED: the 14 unpushed pf-capture/pf-vdisplay sweep commits on the local main. Never through CI; pushing them is the user's call.
18 KiB
Wire-compatible with 0.27.x — everything you have already paired keeps working, and you can update one side at a time. Nothing here changes how a host and a client agree on what to send each other, so an old client on a new host, or the other way round, streams exactly as it does today.
This release is mostly about a host that behaves itself on the machine it lives on. A Windows host no longer keeps your computer awake around the clock, and no longer costs you frames in the game you are playing locally — both were real, both were reported from the field, and neither had anything to do with streaming. On Linux, the setting that was supposed to make streaming smoother turned out to be causing the stutter people kept reporting, and it is now off. Controllers get their speaker and touch feedback on Linux hosts for the first time, Wi-Fi machines can finally be woken remotely, and Debian is a supported system at last. There is one change you may need to act on: the Moonlight-compatible half of the host is now something you switch on rather than something that is always there.
TL;DR
- Your game library now comes from add-ons, not from the host itself — and if you have none installed, your library will be empty after updating. One click per store puts it back. See Before you update.
- If you connect with Moonlight, you must switch it on after updating. The host now speaks only its own protocol unless you tell it otherwise. Punktfunk's own clients are unaffected. See Before you update.
- A Windows host misbehaved on the machine it was installed on, whether or not anyone was streaming: it stopped the computer from ever going to sleep, and it could wreck the frame rate of a game you were playing on that same machine — badly enough that one report cured it by uninstalling. Both fixed.
- Two long-standing Linux streaming faults are gone. The "make it smoother" setting was in fact causing the stutter people kept reporting — both places we asked the graphics card for priority are now off by default, nothing to switch on — and streams no longer tear with pink, blocky corruption at high frame rates on gamescope machines.
- Linux hosts gain two things: your controller's speaker and touch feedback work on them for the first time, not just on Windows ones, and Debian 13 is now supported with the patched compositor finally installable via
apt— it had never once been published, on any release. - Your host's identity is being modernised, and there is a date on it. Existing setups keep working exactly as they are; from 1 October 2026 a host still using the old identity will ask its clients to pair once more. You can switch early in one go — see Before you update.
Before you update
- Your library comes from add-ons now — check yours after updating. Punktfunk used to look for your Steam, Epic, GOG, Heroic, Lutris and Xbox games itself. That job has moved to add-ons you install per store, which has been the supported way since the version before last. The built-in half is now gone, so if you have no library add-ons installed, your library will be empty. Putting it back is one click per store on the Library page — nothing else changes: your games keep the same entries, the same artwork, the same pins, and any store you had switched off stays switched off. Nothing to migrate and nothing to re-pair.
- Your host has a new identity for Punktfunk's own connections — and you can switch to it today if you want to. Until now one key proved your host's identity to everything, inherited from the Moonlight-compatible half and older than the security work around it. Punktfunk's own connections now get their own, freshly generated, on a modern elliptic-curve key. A brand-new install uses it immediately. An existing install deliberately keeps the old one: your clients remember the exact key they trusted the day you paired, and swapping it underneath them would lock every one of them out at once. Nothing is weakened in the meantime, and nothing breaks. If you want the new identity now, unpair every Punktfunk client on that host, restart the host, and pair them again — that is the whole procedure, and the host prints the same instruction in its log. From 1 October 2026 the host will stop falling back to the old identity, so any host that has not migrated by then will ask its clients to pair once more. Moonlight-compatible connections are untouched by all of this and keep their own separate identity, which cannot change.
- If you use Moonlight, or any Moonlight-compatible client, read this. The host used to answer both its own clients and Moonlight's out of the box. It now answers only its own unless you ask for the other, because the Moonlight-compatible half predates Punktfunk's own security work and is the older, weaker way in. Nothing about your setup is lost — set
PUNKTFUNK_GAMESTREAM=1in the host's configuration file and it works exactly as before. Punktfunk's own clients need no change at all. On NixOS the corresponding setting is now off by default; on a Steam Deck the installer takes a flag to opt in. Windows was already like this and does not change. - Bazzite, if Game Mode has been showing you the machine's own screen instead of giving you your own display: that was our fault, in the configuration file we told you to copy. Copy the new one and the problem goes away. If you edited yours by hand, remove the line that forces the attach mode.
- Linux Mint, or plain Ubuntu 24.04: these cannot host. The desktop underneath them has no way to create the extra display Punktfunk needs, and Ubuntu 24.04 is too old to run the compositor that would work around it. The host will now tell you this plainly instead of suggesting a setting that cannot help. Mint 22.x is supported by its makers until December 2026, so this is not a short wait — a supported system is the only fix.
- Debian or Ubuntu, if you were ever told to install
punktfunk-gamescopeand it was not there: it genuinely was not. It had never been published foraptin any release, despite the notes and documentation saying otherwise. It is there now, for Debian 13 and Ubuntu 26.04. Ubuntu 24.04 cannot run it at all. - If you build Punktfunk from source, you now need a working C compiler. Nothing else was added.
New
- Your controller's speaker and touch feedback work on Linux hosts. The per-controller audio that drives a DualSense's speaker and its finer feedback existed only on Windows hosts; on a Linux host your controller quietly fell back to plain rumble and nothing said why. Linux hosts now present each controller to games as its own audio device, exactly as Windows ones do.
- A machine on Wi-Fi can be woken remotely. Waking a sleeping host over the network only ever worked on wired machines. On Wi-Fi the host asked the wrong part of the system whether waking was switched on, so it told you it was not even when it was, and then offered a command the wireless driver rejects. It now asks the right question, gives advice that works, and the client aims the wake-up at every network it can see rather than trusting the default route — which, with a VPN running, never reached the wireless network at all.
- Debian 13 is a supported system for hosting, tested on every release from now on. It had quietly worked for a long time while the documentation said it was unsupported.
- Launcher tiles show the launcher's mark, so a Steam title looks like one at a glance.
- Every pinned card has a library of its own, and launching from it uses that card's settings.
- Experimental: hold a display steady while streaming. On machines with an AMD graphics card, Punktfunk can hold the connection to your monitor open while your own screens are switched off for a stream. This targets a specific stutter that comes from a sleeping monitor being woken and asked to identify itself over and over. It is off by default, and the switch only appears if your machine has the hardware it applies to.
Improved
- Streaming stopped asking your graphics card for emergency priority — and everything got smoother. Two places asked for it, and a long field investigation into a stutter nobody could explain convicted both. The stall it produced was regular, arriving every few seconds, and turned out to be the graphics scheduler reacting to a demand it could not honour — not anything Punktfunk was doing on a timer. Neither request is made now, which is also what every comparable product does. Nothing to switch on, and the frame pacing this was supposed to protect is unaffected.
- The connection recovers from a lost frame without freezing. After a dropped frame the picture would freeze and stay frozen far longer than it needed to, most visibly on machines with an AMD graphics card and only when streaming in H.265 — the same loss was being counted twice, so a picture that had already repaired itself was frozen again by the stale second count. Streams recover as soon as they are actually whole.
- The Android console got a proper going-over — the real desktop backdrop behind it, an interface that stops shifting under your cursor, a controller route for the statistics overlay, and tables that no longer drift out of step with the other clients without saying so.
- "Update all" for your add-ons. The plugins page could only update one at a time, one dialog each. There is now a single button beside the list, and a count on the tab so you can see there is something to update without going looking. They install one after another, because the host only accepts one at a time.
- The microphone button has left the stream overlay on Android. It sat in the corner of every stream that used your mic. Muting is unchanged — the Select + Y button chord still does it, and the on-screen hint for that chord is now the only reminder. A proper on-screen control set is being built, and mute will come back as part of it.
- A statistics setting chosen between two streams now takes effect. It used to be read once at the start of a stream, so a change made in between did nothing until the app was restarted.
- Connections are protected against future code-breaking computers. Every encrypted connection now offers a post-quantum key exchange first, falling back to the classical one for anything that does not understand it. Nothing to configure, and nothing about pairing or your existing setup changes.
- A stream no longer refuses the fast decoder over a mislabelled quality setting. Some encoders claim a higher level than they use; that claim is now trimmed rather than treated as a reason to fall back to slower decoding.
Fixed
- A Windows host stopped the computer from ever sleeping. Installing it was enough — connected or not, streaming or not. The microphone it provides to games was left running around the clock writing silence, and Windows treats any running audio stream as a reason to keep the machine awake. It now stops when nothing is speaking and starts again the instant something is, fast enough that you will not hear the difference. Streams still keep the machine awake while they are running, as they should.
- A Windows host could ruin the frame rate of a game running on the same machine. One report measured a game's worst frames at 2–5 per second and cured it by uninstalling Punktfunk. Two separate faults: on a machine where the audio devices could not be created properly, the host retried the full creation every minute forever, and each attempt made every game on the machine rebuild its audio; and the first stream ever run permanently raised the host's own priority above everything else, because the settings meant to last for one stream were never put back. Both are fixed, and the priority now goes back down when the stream ends.
- Streams tore with pink, blocky corruption at high frame rates on gamescope machines. The picture was being handed back to the compositor to be drawn over while it was still being read for sending, so parts of two different frames arrived in one. Reported at 120 frames per second; ordinary desktop sessions were never affected, which is why it took so long to place.
- Game Mode on Bazzite mirrored the machine's own screen instead of giving the client its own display, and a game launched from a client's library could not get a session of its own. The configuration file we ship — and tell people to copy exactly — forced a setting that overrode all of that.
- Games ran on a black screen in Nobara's Game Mode. The fix that shipped last release was being undone by the system's own start-up script moments after it was applied, so sound and controls worked over a black picture while the log said the problem had been handled.
- A crash-looping overlay could turn the whole stream black while every health indicator stayed green, on Bazzite handhelds. An invisible window was winning the contest for what gets shown, and the stream faithfully sent that.
- Streaming a desktop still did not work on NixOS with KDE. Last release's fix depended on reading something the system refuses to reveal about a program holding a special permission — and on NixOS the desktop itself holds one. The host now falls back to a way of asking that works, and the same fix covers other systems where the compositor holds that permission.
- One slow start could downgrade a host until it was restarted. The first attempt to get a picture is deliberately given a short deadline, but when that deadline passed the host concluded the machine had refused whatever it had asked for — high dynamic range, or the fast capture path — and stopped asking for the rest of its life. A gamescope machine starting up cold routinely needs longer than that deadline, so one lost race at connect pinned every later session to the slower, dimmer path.
- Steam gained a duplicate Punktfunk entry on every restart on Steam Deck, accumulating without limit. The plugin also stopped announcing itself with a pop-up every single launch.
- Removing a paired device now actually removes it. It was not being saved, so the device reappeared at the next restart, and a device that was already connected kept streaming until it chose to leave. Removing a pairing now ends that device's live session too.
- Connecting a second device could kill the desktop on a Linux host running GNOME. Connecting one device, leaving, then connecting a different one at a different screen size crashed the desktop outright — and every stream afterwards failed with a black picture until someone signed back in at the machine. Two pieces of the host's own display handling could overlap the desktop's rebuild of its screen list; they are now made to wait for each other. This was never new — it behaved exactly the same on the previous release — but it is fixed now.
- Streaming a 4K screen at 60 Hz on a KDE host gave you a 1080p picture. The host asked for the full size, KDE built something smaller, and nothing checked — while the log confidently printed the size that had been asked for, which is why the first look at this went the wrong way. The real size is now read back and reported.
- Audio on an iPad broke up where a Mac was fine. The rule that decides when to give up on a stalled audio buffer was counting audio deliveries rather than time, and an iPad asks for much shorter ones — so the same setting gave an iPad about 20 ms of slack where a Mac got 44 ms, on the device with the burstiest connection. It is measured in time now. On a simulated connection with a 100 ms hiccup every 5 seconds, ten minutes went from 120 audible gaps to 2.
- Android was unscrambling every stream the slow way. Phones and Android TV boxes have dedicated hardware for the encryption Punktfunk uses, and the app was supposed to use it — but the setting that switched it on was being wiped out by the Android build tooling before the app was ever compiled, on every build we have ever shipped. Every packet was unscrambled in software instead, which costs processor time and battery for nothing. The app now detects the hardware at runtime, so there is no setting left to lose.
- The published interface documentation described a version of the host nobody was running. It had drifted several releases behind, so five newer parts of the host's interface were missing from it entirely.
For developers
Protocol, ABI, driver and add-on detail — the version table, the new environment variables, the build-time changes and what did not move — is in CHANGELOG.md.
The short version: nothing breaks on the wire. The wire protocol stays at 2, so every pairing and every shipped client keeps working. The C ABI moves 18 → 19 by addition — two new entry points for the loss-recovery fix above — and both existing entry points keep their signatures and their behaviour, so an embedder that ignores the new symbols behaves exactly as it does today.
The new host identity is ECDSA P-256, not Ed25519 — deliberately: no mainstream browser accepts an Ed25519 server certificate, and an operator opens /api/docs in one. The Moonlight-compat plane keeps its RSA identity permanently, because Moonlight mandates RSA and its pairing hashes bind the certificate's signature bytes; only the native plane's legacy fallback is dated, and it is removed on 1 October 2026.
The one genuinely breaking change is on the host: the six built-in library scanners are deleted, and the library is now assembled entirely by plugins. There is deliberately no migration — a plugin claims its store and re-publishes each title under the same identifier the scanner used, so entry ids, app ids, artwork caches, pins, per-source toggles and per-entry hides all keep working untouched. The one visible consequence is an empty grid on a host with no library plugins installed.
Three things change how you build rather than how anything runs: the tree moves to Rust edition 2024 with a declared minimum of 1.85, building from source now needs a C compiler, and the Moonlight-compatible half is a compile-time feature as well as a runtime switch — building without it produces a host with the entire legacy protocol stack, and its transpiled C networking code, absent from the binary.
If you package Punktfunk: the Moonlight default flip and the Bazzite configuration template are the two changes your users will notice. Neither needs a packaging change.