-
v0.32.0
Stableaudit / docs-site-audit (push) Successful in 24saudit / bun-audit (plugin-kit) (push) Successful in 30saudit / bun-audit (sdk) (push) Successful in 26saudit / pnpm-audit (push) Successful in 22saudit / bun-audit (web) (push) Successful in 38saudit / cargo-audit (push) Successful in 48sci / rust-arm64 (push) Successful in 3m15saudit / license-gate (push) Successful in 6m1saudit / c-abi-asan (push) Successful in 6m5sci / web (push) Successful in 2m2sci / bun-nix (push) Successful in 25sci / docs-drift (push) Successful in 35sci / docs-site (push) Successful in 1m5saudit / miri (push) Successful in 8m16sci / rust (push) Successful in 9m50snix / flake (push) Successful in 21m12sdeb / build-publish-gamescope (push) Successful in 38sandroid-screenshots / screenshots (push) Successful in 1m39sdecky / build-publish (push) Successful in 56sdeb / build-publish-client-arm64 (push) Successful in 1m47sdocker / builders (--build-arg FEDORA_VERSION=44, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm, -f44) (push) Successful in 17sapple / swift (push) Successful in 2m10sdocker / builders (ci/arch-ci.Dockerfile, punktfunk-arch-ci) (push) Successful in 16sdocker / builders (ci/android-ci.Dockerfile, punktfunk-android-ci) (push) Successful in 19sdocker / builders (ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 15sdocker / builders (ci/flatpak-ci.Dockerfile, punktfunk-flatpak-ci) (push) Successful in 15sdocker / builders (ci/rust-ci-noble.Dockerfile, punktfunk-rust-ci-noble) (push) Successful in 17sdocker / builders (ci/gamescope-trixie.Dockerfile, punktfunk-gamescope-trixie) (push) Successful in 19sdocker / builders (ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 14sdocker / apps (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 28sdocker / apps (., web/Dockerfile, punktfunk-web) (push) Successful in 1m1sdeb / build-publish (push) Successful in 3m54sdeb / build-publish-host (push) Successful in 4m52swindows-client / client (arm64, --no-default-features, aarch64-pc-windows-msvc, C:\t-a64) (push) Successful in 4m45ssbom / sbom (push) Successful in 40sdocker / builders-arm64cross (push) Successful in 15sdocker / deploy-docs (push) Successful in 34slinux-client-screenshots / screenshots (push) Successful in 5m24sdeb / smoke-install (push) Successful in 2m58sflatpak / build-publish (push) Successful in 7m39sarch / build-publish (push) Successful in 11m18sandroid / android (push) Successful in 12m4swindows-client / client (x64, , x86_64-pc-windows-msvc, C:\t) (push) Successful in 8m29sweb-screenshots / screenshots (push) Successful in 6m15sapple / distribute (push) Successful in 13m17srpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 18m57srpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 18m56sapple / screenshots (push) Successful in 9m48swindows-host / package (push) Successful in 12m49swindows-host / canary-manifest (push) Skippedwindows-host / winget-source (push) Successful in 1m3sreleased this
2026-08-27 21:04:48 +00:00 | 6711 commits to main since this releaseThis release is for everyone who streams games or a desktop with Punktfunk. It works with 0.31.x, so everything you have already paired keeps working. You can update one side at a time.
The main change is that the bitrate number now tells the truth. When you set a rate, that number used to cover the picture only, while error correction, packet overhead and audio rode on top of it. So asking for 20 Mbps could put 30 Mbps on your network. You would never notice on a fast wired connection, but on a weak one it was the problem you were tuning around. The number you set now covers everything that leaves the machine.
The part of your client that picks the rate for you has also been rebuilt. It used to mistake a still picture for a bad connection. A paused game convinced it the link was failing, so the next moment of motion arrived at the worst quality available. Climbing back could take a minute and a half. It now tells stillness apart from congestion, and recovers in seconds.
It is also a security release, though the count sounds worse than it is. A review of the whole system produced 58 findings, and most are small: hardening, build infrastructure, and places where a comment promised more than the code delivered. The one worth your attention needed somebody already signed in to your web console. From there they could reach the pairing controls without being asked for the console password, and pairing a device lets it launch programs. If anyone else can sign in to your console, take this update.
TL;DR
- The bitrate you set is now the bitrate on the wire. It used to cover the picture only. If you tuned your rate by trial and error, read "Before you update".
- Automatic bitrate no longer misreads a still picture as a bad connection. Motion starts sharp, and recovery takes seconds instead of 100.
- A security review fixed 58 findings, most of them small. The one that mattered needed somebody already signed in to your web console. From there they could pair a device without the console password, and pairing is what lets a device launch programs.
- Android TV: fixed a permanent black screen with working sound. Some devices could never start their decoder, so no picture ever arrived.
- Two people streaming at once now both get a controller. The second person used to get no controller on Windows, or a merged one on Linux.
- Fixed garbage rectangles that never went away. Black bars moved "like an equalizer" on every decoder, and nothing ever recovered.
- Moonlight-compatible streaming got real work. Encryption is on by default, Wake-on-LAN works, and resuming a session now resumes it.
What's in this release
Before you update
- Your bitrate setting means something slightly different now. Nothing breaks, and you need do nothing. But the same number now puts less on your network than it did. If you tuned by trying numbers until streams behaved, you can ask for more than before. If you tuned down because streams were unstable, leave it where it is — the overshoot you were compensating for is gone.
- Moonlight users: your video and control channel are now encrypted by default. Clients that support it turn it on themselves. We watched one do exactly that on a local network, unprompted. That is why it became the default. A switch exists to go back; the developer changelog names it.
- If you script the web console's pairing steps, they now need the console password. Arming a pairing, approving it and submitting the PIN no longer accept a signed-in browser session alone. That is the security fix described below, so the change is deliberate. Add the password to your script.
New
- 10-bit colour without high dynamic range (HDR). Asking for 10-bit used to mean asking for HDR, because the two were welded together, and they are separate again. A new standard dynamic range (SDR) setting, called "10-bit SDR", asks for the extra precision on its own and stays off by default. Neither screen switches into HDR, no colour is remapped, and compression stops adding banding to gradients such as skies and fades. It needs a Windows host, an NVIDIA graphics card and High Efficiency Video Coding (HEVC), so every other setup stays 8-bit and says so.
- Keep your host's speakers playing. A new per-session setting asks the host to leave its audio devices alone. The host listens to whatever is already playing instead of re-routing sound to a silent output. Headphones plugged into the host stay live, and you still hear everything on the client. An older host simply ignores the request, and the setting appears in the desktop and gamepad interfaces.
- Setup commands now know your stream's mode. A command you run before or after a game receives the width, height, refresh rate and whether the session is HDR. That means one setup step instead of one entry per device you stream to. It works on Windows hosts too, where those commands previously received only the app's identifier.
- "Send logs to host" reached every interface. The button packages what your client saw and sends it to the host, so a report carries evidence instead of a description. It now works in the Linux, Windows and Android touch interfaces. A gamepad interface that cannot start also says why instead of failing silently.
- Heroic's fullscreen interface can be a tile. On Linux, a library tile can open Heroic's gamepad-friendly console mode directly.
Improved
- Automatic bitrate was rebuilt. Every part came from a report where a stream behaved badly on a connection that measured fine.
- Stillness is no longer mistaken for congestion. Your host now marks the moments when the picture is not changing. Your client treats those stretches as carrying no information, so they neither raise nor lower your quality. Previously a static menu looked exactly like a connection delivering nothing.
- Recovery is fast and bounded. Climbing back after a dip used to crawl, taking about 100 seconds from the bottom. It now takes seconds, and never overshoots what your connection recently delivered.
- A slow source can climb. A menu running at 35 frames per second on a 90 Hz setup was judged against 90. It looked like it was wasting its allowance, so it could never earn better quality. Your client now measures against what the source actually produces.
- The floor is lower. The lowest rate the control settles at drops from 5 Mbps to 2 Mbps. A genuinely poor connection now gets a stream that holds together.
- Your traffic gets priority on your own network. Streaming data is now tagged so Wi-Fi access points give it priority over other traffic on the same air. Tagging happens only toward addresses on your local network. It stays off toward the internet, because some providers and routers mishandle tagged traffic there.
- Frames go out spread over time instead of in a burst. The allowance for sending a frame in one blast was a fixed size chosen for gigabit Ethernet. On Wi-Fi that meant frames went out back to back. It is now measured in time at your actual rate.
- Button hints match the device in your hand. A TV remote used to be told to press Enter, Esc and Tab, which it does not have. A Nintendo pad showed Xbox letters, so "A — Select" sat over the button engraved B. Hints now follow whatever last drove the interface. A PlayStation pad gets shapes, a Nintendo pad gets its own letters, and a TV remote gets an OK badge with the missing buttons hidden.
- A TV remote can reach the settings tabs. The tab strip answered only to shoulder buttons. Press Up from the top row to get there.
- The mouse pointer is the right size on a high-DPI client. On a 200% display our pointer was drawn at half the size of every native one.
- The web console is named in every install line, and a host without it gets it installed.
Fixed
- Android TV: a permanent black screen with working sound. Reported on a Xiaomi Mi TV Stick, where the decoder accepted the video format and then failed to start, so no picture was ever decoded. Audio, input and your library all kept working, which made it look like a host problem. Your client now tries a ladder of simpler decoder setups instead of giving up after one attempt. A device that already works pays nothing, and the setup that succeeded is logged so the next device names its own cause.
- Two people streaming from one host both get a controller now. Every OS-level name for a virtual controller came from the controller's number, and every client numbers its first controller zero. So two people each holding a controller collided. On Windows the second person got no controller for the whole session, and the error told the operator to restart the service, which would have killed both sessions. On Linux nothing errored at all and the two controllers merged into one.
- Garbage rectangles that appeared and never left. Reported as black bars moving "like an equalizer", identical on every decoder. A frame arriving in pieces could claim a position inside the valid range that did not actually fit, leaving a gap and overlapping its neighbour. The frame was still marked complete, so the picture was assembled from the wrong bytes, and nothing recorded a loss or asked for a fresh frame. Android was never affected.
- A brief pause no longer wrecks quality for the rest of the session. When your client gave up waiting for frames that then arrived, it counted them as lost packets. One recording showed exactly 5% packet loss on a connection that lost nothing, and the rate was cut by 30% three times in four seconds. Neither thing that number controls could have helped, because error correction repairs loss and not delay. Real packet loss still counts as before.
- A stall report no longer blames your laptop screen. On a laptop streaming a still desktop, the host reported dozens of stalls and pointed at the internal panel. Nothing was being drawn, because on a still desktop only the mouse pointer changes, and it moves only when your input arrives. The host was correctly displaying nothing. It now checks whether anything actually changed before blaming anything.
- A truncated video stream no longer crashes the decoder. An access unit that claimed more data than it carried could stop the decoding thread outright. It is now treated as a parse error. This affected every AV1 path.
- "Capture system shortcuts" now works in Desktop mouse mode. The setting was wired up and then discarded by a single condition. That made it useless for exactly the remote-desktop case where it matters most.
- Windows: the couch interface's tiles no longer pop up a console window.
- Linux: KDE's stored display setup no longer darkens your desk permanently. The host's changes were saved on top of your own configuration, and the restore never saw the original. Your setup is now captured before anything changes, and re-applied after the stream ends.
- AMD: AV1 streams could arrive out of order. B-frames are now pinned off, and the stream is checked rather than assumed to be in order. AMD encoders also report the bitrate they actually applied instead of the one they were asked for. NVIDIA sub-frame delivery is now verified in release builds.
- Moonlight-compatible streaming, a batch of fixes:
- Wake-on-LAN never worked. The host advertised a fake hardware address, so every attempt was a silent no-op. It now advertises its real one.
- Resuming a session did not resume it. The control channel was left undecipherable because keys were not refreshed, and video did not restart cleanly.
- HDR games sent no colour information. The host switched the display into HDR mode and then sent nothing describing the picture. It now sends the real grade every frame.
- Stereo audio had no loss protection. Error correction covered surround layouts only, leaving the most common setup with none.
- The host now adapts when your client reports lost packets, adjusting error correction and rate as conditions change. Moonlight's latency overlay also shows real host numbers instead of zero.
- The host no longer claims 4K HEVC capacity it may not have. A host with no graphics card encodes H.264 only, but still advertised an HEVC ceiling.
Security
A review on 2026-08-25 produced 58 findings across the host, the console, the apps and our build infrastructure. Most are small — tightening you would never notice, and places where a boundary was described correctly in its own documentation while the code had quietly drifted from that promise. A handful mattered. One mattered more than the rest, and it is worth being precise about what it was and was not.
That one was the web console's pairing controls. Reaching them meant being signed in to the console already, so this was not something a stranger on your network could do. But once signed in, those controls ran through a general-purpose route carrying the operator's own credentials. So alone among the trust-root actions, they never asked for the console password. Since pairing a device is what lets that device launch programs, the gap turned "signed in to the console" into "can start something on the host".
What changed: arming a pairing, approving it and submitting the PIN now all sit behind that password. The PIN itself is handed over once in the protected response, rather than being readable by anything polling for status.
Other fixes in this release:
- Add-ons can no longer read the unredacted log, which carried webhook credentials that were withheld from them elsewhere.
- A revoked guest now loses clipboard access immediately, in both directions.
- Peers on your network can no longer occupy every connection slot without a stream to join.
- Secrets on Windows are created with their permissions already applied, rather than being briefly readable by anyone.
- Five ways to crash the host with a malformed video packet are closed.
- The identity key on Apple devices no longer rides along in encrypted backups.
- Deep links auto-connect only by a stable identifier. A link naming a display name or an address asks you first.
- Moonlight-compatible media ports now verify who is connecting. Both media planes used to accept the first packet from the right address without looking inside it. The value they were meant to check was the same fixed constant on every host, and nothing compared it. It is now a per-session secret, and the request that hands it out requires authorisation.
- The Moonlight-compatible control channel no longer reuses one number space between the two directions.
Thanks
Nearly everything above started as somebody describing exactly what they saw:
- The bars moving like an equalizer, with the detail that they looked identical on every device. That is what ruled out the decoder.
- The stream that dropped to 7 Mbps in four seconds, reported with measurements showing the connection had lost nothing. That was the hard half.
- The TV stick with sound but no picture, reported with a log covering nine sessions.
- Five separate requests from one returning user, each of which turned out to be a real defect rather than a missing feature.
- The remote that was being told to press Esc.
Thank you.
One caveat we would rather write down than have you find. The 10-bit SDR path is verified on Windows with NVIDIA hardware over HEVC. Other combinations deliberately stay 8-bit and say so, rather than guessing.
For developers
Protocol, application binary interface (ABI), driver and embedder detail is in the v0.32.0 CHANGELOG. It carries the version table and the full breaking-change list.
The short version: the ABI that embedders build against moves 25 to 26, and nothing else versioned moves. The new interface takes every connect option in one size-prefixed struct, which closes an eleven-generation ladder of numbered entry points. Every older entry point keeps its symbol and its behaviour, so existing embedders keep working. The streaming protocol, driver protocol, gamepad channel, add-on contract and management API are all where 0.31.4 left them.
Read the breaking-change list anyway, because most of it is behavioural rather than numbered. The bitrate on the control plane is now the total wire budget rather than the encoder rate, deliberately without a capability handshake. If you read the live bitrate as an encoder rate, it is not one any more. The rate floor drops, and traffic marking now defaults on toward local peers. Moonlight-compatible video and control encryption default on, PyroWave sessions force automatic rate, and the pairing routes move behind the console password.
Downloads