• v0.31.2
    audit / docs-site-audit (push) Successful in 23s
    audit / bun-audit (web) (push) Successful in 24s
    audit / bun-audit (sdk) (push) Successful in 26s
    audit / pnpm-audit (push) Successful in 19s
    audit / bun-audit (plugin-kit) (push) Successful in 26s
    audit / cargo-audit (push) Failing after 40s
    ci / web (push) Successful in 1m21s
    ci / docs-site (push) Successful in 1m13s
    ci / bun-nix (push) Successful in 16s
    ci / docs-drift (push) Successful in 21s
    audit / license-gate (push) Successful in 4m57s
    audit / miri (push) Successful in 6m17s
    audit / c-abi-asan (push) Successful in 6m24s
    android-screenshots / screenshots (push) Successful in 1m54s
    ci / rust-arm64 (push) Successful in 1m38s
    ci / rust (push) Successful in 8m29s
    android / android (push) Successful in 11m48s
    arch / build-publish (push) Successful in 9m23s
    linux-client-screenshots / screenshots (push) Successful in 4m53s
    sbom / sbom (push) Successful in 33s
    web-screenshots / screenshots (push) Successful in 6m46s
    decky / build-publish (push) Successful in 48s
    docker / builders-arm64cross (push) Successful in 10s
    docker / builders (--build-arg FEDORA_VERSION=44, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm, -f44) (push) Successful in 20s
    docker / builders (ci/android-ci.Dockerfile, punktfunk-android-ci) (push) Successful in 13s
    docker / builders (ci/arch-ci.Dockerfile, punktfunk-arch-ci) (push) Successful in 15s
    docker / builders (ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 14s
    docker / builders (ci/flatpak-ci.Dockerfile, punktfunk-flatpak-ci) (push) Successful in 11s
    docker / builders (ci/gamescope-trixie.Dockerfile, punktfunk-gamescope-trixie) (push) Successful in 8s
    docker / builders (ci/rust-ci-noble.Dockerfile, punktfunk-rust-ci-noble) (push) Successful in 16s
    docker / builders (ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 13s
    docker / apps (., web/Dockerfile, punktfunk-web) (push) Successful in 17s
    docker / apps (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 1m31s
    docker / deploy-docs (push) Successful in 17s
    nix / flake (push) Successful in 22m13s
    deb / smoke-install (push) Successful in 2m52s
    deb / build-publish (push) Successful in 5m12s
    deb / build-publish-host (push) Successful in 5m39s
    deb / build-publish-gamescope (push) Successful in 1m5s
    deb / build-publish-client-arm64 (push) Successful in 2m42s
    rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 18m49s
    apple / distribute (push) Successful in 13m6s
    apple / swift (push) Successful in 2m4s
    rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 21m22s
    apple / screenshots (push) Successful in 9m40s
    windows-host / package (push) Successful in 13m30s
    windows-host / canary-manifest (push) Skipped
    windows-host / winget-source (push) Successful in 28s
    windows-client / client (arm64, --no-default-features, aarch64-pc-windows-msvc, C:\t-a64) (push) Successful in 5m57s
    windows-client / client (x64, , x86_64-pc-windows-msvc, C:\t) (push) Successful in 9m45s
    flatpak / build-publish (push) Failing after 8m56s
    Stable

    enricobuehler released this 2026-08-21 20:50:53 +00:00 | 6874 commits to main since this release

    Wire-compatible with 0.31.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 is a fix release, and most of it continues the hunt 0.31.1 started: a stream that connects, reports itself perfectly healthy at every gauge, and shows you a black screen. Two more causes end here, and both are about which of your host's addresses it used — video that left the host by whichever network connection the machine happened to prefer rather than the one your client actually dialled, and a host that started up faster than its own network and then spent the rest of the day telling everyone to connect to an address that only ever means "this machine". The other half is Windows security: the firewall rules Punktfunk installs named ports but not programs, which left those ports open to anything running on that PC — they name Punktfunk now, and that is the one change here that can affect another program on the same machine. On Android, the controller fix from 0.31.1 turned out to be firing on controllers that never needed it, breaking buttons that had been correct all along.

    TL;DR

    • A host with two ways to reach your client streamed into a black screen. Ethernet and Wi-Fi both connected, or a VPN adapter installed, was enough: the video left by whichever one the machine preferred, and your client discarded every packet of it. Nothing else about the session was wrong, which is exactly why it was so hard to see.
    • A host that started before its network was ready never recovered. It advertised an address meaning "this machine", so clients listed it and could not connect to it, Moonlight-compatible sessions could not stream, and Wake-on-LAN silently stopped working. Restarting the host was the only cure; now there is nothing to cure.
    • Windows: Punktfunk's firewall rules were open to every program on your PC. They named only port numbers, so any program — with no administrator rights and no prompt — could take one of those ports and be reachable from your network through a rule meant for Punktfunk. Read Before you update: one thing on that machine may now need a rule of its own.
    • Android: 0.31.1's controller fix broke controllers that were already correct. On a GameSir G8+ and an Xbox Elite Series 2 over Bluetooth, X answered Y, Y answered the left shoulder, and both shoulders answered menu buttons.
    • Your host now follows its own address when it changes — a new lease from your router, or a machine moved between Wi-Fi and Ethernet — instead of announcing the address it had at startup forever.

    Before you update

    • Windows hosts: run the installer rather than replacing the program by hand. The firewall fix rewrites the rules Punktfunk installs, and that happens in the host's own service-install step, which the installer runs for you on every update. If you run the host some other way, run punktfunk-host service install once as an administrator. Skipping it leaves the old wide-open rules in place; nothing on the client side needs doing.
    • Windows hosts: something else on that machine may need its own firewall rule now. Punktfunk's rule for the discovery port (5353) used to be open to every program, so anything else on that PC that answers discovery — another streaming host, a media server, a printer or scanner utility — could have been reachable through Punktfunk's rule without ever having one of its own. That ends with this release. If something else on the machine stops being discoverable after you update, give it its own rule. The installer prints a note saying exactly this while it works.

    Improved

    • Your host keeps up with its own address instead of freezing it at startup. The address a host publishes for clients to dial was worked out once, when the host process started, and then never looked at again. Now it is re-read as things change and the published address is updated to match — so a new lease from your router, or a laptop host carried from Wi-Fi to Ethernet, no longer leaves your clients dialling somewhere the host has not been for hours. This is the general form of the cold-boot fix below, and it covers the cases nobody had got round to reporting yet.
    • When a stream does go black, the host's log now tells you the truth about it. The message it printed used to name a cause with real confidence — and was wrong often enough to send people to the wrong place entirely, including at least one investigation that went to the firewall while the actual fault was the network card. It no longer asserts a cause it cannot know, and it now records which network connection the video is actually leaving by, and says so plainly when that is not the one the client arrived on. That single line is what turns the black screen above from a mystery into something a log answers.

    Fixed

    • A host with more than one live path to your client sent the video down the wrong one, and you got a black screen with every indicator green. Two network connections up on the same network — the very common Ethernet-and-Wi-Fi-both-on — or a VPN or overlay adapter that claims to know a better route, and the host let the machine choose which one the video left by. That choice was made with no reference at all to how your client had reached it. Your client only listens for video from the address it dialled, so it threw away everything arriving from the other one, in the part of the system that counts nothing and reports nothing. Meanwhile the connection was made, sound and controller input flowed perfectly, and the host's own loss figure sat at zero — because loss is measured over packets that arrived, and none did. The host now sends the video from the same address the client reached it on.
    • A host that started before its network was ready advertised itself as unreachable, and stayed that way until it was restarted. Cold-booting a machine is a race, and the host wins it: it starts without waiting for the network, asks which address it should publish, gets no answer because there is no network yet, and falls back to the address that means "this machine and nothing else". Then it kept that answer for the entire life of the process. Everything that reads that address broke together — the host appeared in your client's list but could not be connected to, Moonlight-compatible sessions were handed the same useless address after launching a game, Wake-on-LAN quietly stopped working because the host could no longer identify the network hardware to record for it, and the web console displayed the wrong address to anyone who looked. Users found the workaround themselves, which was to restart the host once the machine had settled. The host now refuses that fallback answer entirely: if the usual method cannot say which address to use, it takes the first real network address it can find, which exists as soon as the network card is configured — well before the machine finishes working out how to route anything.
    • Windows: the firewall rules Punktfunk installs opened those ports to every program on the machine, not to Punktfunk. Each rule named a port and nothing else, and a rule like that admits whatever is listening on that port — Punktfunk or otherwise. Nothing about it required administrator rights to exploit: taking a high-numbered port on Windows needs no privileges at all, so any program that started first could sit on one of Punktfunk's ports and be reachable from your whole network. Worse, it happened without any of the usual signs, because the pop-up asking whether to let a program communicate on your network is precisely what a matching rule suppresses — Punktfunk's rule was answering that question on another program's behalf. Every rule now names the program that is genuinely meant to be listening on it, and keeps the port restriction as well, so both must match. The affected ports were the streaming, discovery, management and console ports. If Punktfunk cannot work out its own location on disk it keeps the old broader rule rather than leaving you with no rule at all, since a rule that is too generous still streams and a missing one is a black screen.
    • Android: controllers that had always worked started pressing the wrong buttons. This is a regression from 0.31.1, reported the same day on a GameSir G8+ and an Xbox Elite Series 2: X answered Y, Y answered the left shoulder, and the two shoulder buttons answered menu buttons, with everything else correct. 0.31.1 fixed controllers Android has no layout file for by reading each button's position in the controller's own report instead of trusting Android's guess — the right fix, applied to too many controllers. It decided which controllers needed it by asking what the device claimed to have, and that claim turns out to be true of any controller with six or more buttons, including every controller that was already perfectly correct. So it corrected pads that needed no correcting, and moved their buttons off the marks. It is now decided on the triggers instead: a controller that describes its triggers properly is one Android has a real layout for, and it is left completely alone — no correction to its buttons or its sticks. That is the same signal Moonlight uses for the same decision, and it matches the reports precisely, down to the fact that the very same model needed correcting on a Fire TV and was broken by it here: an Xbox Wireless Controller describes its triggers one way after a firmware update and the other way before it, and only the older one was ever wrong.

    Known issue

    • A DualSense with a dead Triangle button is not fixed here. It was reported alongside the two controllers above and looks related, but it is not the same fault — Triangle reaching neither the stream nor Punktfunk's own controller display is a different failure from a button arriving as the wrong one, and nothing in the fix above produces it. The Connected controllers page prints exactly what each press reports; that line from an affected pad is what will pin it down.

    Thanks

    Every fix in this release came from someone reporting what actually happened rather than what they assumed. Both black-screen causes were found in field logs from hosts that looked entirely healthy — and the firewall hole was reported by a user on the same day, immediately after the first of those fixes cleared their black screen and left them looking at the rules. The Android controller regression came back within a day of the release that caused it, from two people who named which button answered which, which is the difference between a report that can be fixed and one that can only be believed. Thank you.

    For developers

    Protocol, ABI, driver and embedder detail — including the version table — is in CHANGELOG.md.

    The short version: nothing versioned moves at all. The streaming protocol, the embedding interface, the driver protocol, the gamepad channel and the add-on contract are exactly where 0.31.1 left them, no message or function changed shape, and no header, package or plugin needs rebuilding, re-pairing or re-publishing in any direction. Two things worth knowing: on Windows the firewall rules provisioned at install are now scoped to the executable that listens on each port, which is the one change here that can affect another program on the same machine; and the host's reported address in the management API is now read fresh on every request instead of being fixed for the life of the process, so poll it rather than caching it.

    Downloads