chore(release): cut 0.34.0 #467
+199
@@ -17,6 +17,205 @@ as they are. See `docs/writing.md` §2.
|
||||
|
||||
---
|
||||
|
||||
## v0.34.0
|
||||
|
||||
140 commits since v0.33.0. Wire stays 2. **C ABI moves 26 → 28, and v27 WIDENS a struct** — an
|
||||
out-of-tree embedder must recompile, not just relink.
|
||||
Embedders: read **Breaking**. Detail: `design/touch-client-overlay.md`.
|
||||
|
||||
### Versions
|
||||
|
||||
| | v0.33.0 | v0.34.0 | Notes |
|
||||
|---|---|---|---|
|
||||
| Wire protocol | 2 | **2** | unchanged. `HOST_CAP2_TOUCH` (`0x02`) joins the trailing `Welcome::host_caps2` byte (absent → `0`); the two raw-HID datagram forms already shipped with the Linux passthrough |
|
||||
| C ABI | 26 | **28** | **MOVES TWICE.** v27 = raw-HID passthrough over the C surface, and it **widens `PunktfunkHidOutput` 19 → 85 bytes** — Breaking. v28 = `punktfunk_connection_host_caps2` + `PUNKTFUNK_HOST_CAP2_TOUCH`, purely additive |
|
||||
| Rust edition | 2024 | **2024** | unchanged |
|
||||
| MSRV (`rust-version`) | 1.85 | **1.85** | unchanged |
|
||||
| Workspace crate dirs | 27 | **27** | unchanged (39 `[workspace] members`, also unchanged) |
|
||||
| Virtual-display driver protocol | 6 | **6** | unchanged (minimum accepted still 3). `pf-driver-proto` gains the Triton tables and the frame-statistics call, neither of which is a protocol event |
|
||||
| Windows virtual-gamepad channel | 3 | **3** | unchanged, but it carries two additions: `DEVTYPE_TRITON` = **7** (the next free slot) and `OUT_FEATURE_BIT` (`0x8000_0000`) on the out-length word, read only by the Triton devtype |
|
||||
| Plugin index schema | 1 | **1** | unchanged |
|
||||
| Host event schema | 1 | **1** | unchanged (`punktfunk-host/src/events.rs` shows no diff) |
|
||||
| `api/openapi.json` | 0.33.0 | **0.34.0** | **regenerated, and the surface is verified rather than assumed.** No path, operation or schema moved; the only non-stamp diff is the `disable_physical_monitors` description, rewritten because the second selector it documented now runs by default (see `standby_sink_neutralise` under **Changed**). ⭐ The staleness test that proves this — `mgmt::tests::openapi_document_is_complete_and_checked_in`, which normalises `info.version` so a bump alone cannot trip it — **now runs on macOS**, because `punktfunk-host` compiles there again. Every prior release carried a "re-stamped, not regenerated" caveat for exactly that reason; this one does not. `api/` and `docs-site/public/` are byte-identical to each other |
|
||||
| gamescope patch level (`+pfhdrN`) | 8 | **8** | unchanged; no new patch files, `packaging/gamescope/PKGBUILD` still declares `pfhdr8` |
|
||||
| `@punktfunk/host` (SDK) | 0.1.6 | **0.1.6** | unchanged; nothing under `sdk/` moved |
|
||||
| `@punktfunk/plugin-kit` | 0.4.4 | **0.4.4** | unchanged; nothing under `plugin-kit/` moved |
|
||||
|
||||
### Breaking
|
||||
|
||||
- **`PunktfunkHidOutput` grows 19 → 85 bytes (ABI v27).** The pre-v27 prefix layout is
|
||||
byte-identical and the tail is appended (`hid_kind`, `raw_len`, `raw[PUNKTFUNK_HID_REPORT_MAX]`),
|
||||
so a binary built against a v26 header passes a 19-byte out-slot that a v28 core overruns.
|
||||
**`punktfunk_abi_version()` equality is the guard** and always has been: recompile against the
|
||||
regenerated header. This is the first deliberate widening this surface has made — a second struct
|
||||
plus a second pull symbol was considered and rejected, because the hidout plane has one puller by
|
||||
contract and forking its drain loop would push that fork into every embedder forever.
|
||||
- **`punktfunk_connection_next_hidout` now returns events it used to skip.** `HidOutput::HidRaw`
|
||||
previously fell out as `NoFrame`; it now surfaces as `PUNKTFUNK_HIDOUT_HID_RAW`. A puller that
|
||||
assumed every event was DualSense feedback must switch on `kind` and ignore the kinds it does not
|
||||
serve. Only an as-is Steam Controller 2 session emits these, so a client with no such capture sees
|
||||
no change in practice.
|
||||
|
||||
### Added
|
||||
|
||||
- **Raw HID passthrough over the C ABI (v27).** `punktfunk_connection_send_hid_report` sends one
|
||||
captured report up as `RichInput::HidReport` (`[0xCC][0x04]`, clamped to
|
||||
`PUNKTFUNK_HID_REPORT_MAX` and masked into the 16-pad space); `PUNKTFUNK_HIDOUT_HID_RAW` (`6`)
|
||||
brings the host's hidraw writes back down, tagged `PUNKTFUNK_HID_RAW_OUTPUT` or
|
||||
`PUNKTFUNK_HID_RAW_FEATURE` so the client knows which device channel replays it. New wire
|
||||
constants `PUNKTFUNK_RICH_HID_REPORT` (`4`) exist so client tests can pin the byte against the
|
||||
header. Both datagram forms predate this release; what is new is that a C embedder can reach them.
|
||||
- **`punktfunk_connection_host_caps2` and `PUNKTFUNK_HOST_CAP2_TOUCH` (`0x02`) (v28).** The second
|
||||
capability byte was unreadable from C. A client whose touch model is passthrough gates on the bit
|
||||
and falls back to its cursor model with a notice, because a host without it drops every contact
|
||||
silently. Linux sets it on the libei, gamescope-EIS and KWin backends; the wlroots virtual-pointer
|
||||
backend has no touch protocol, and Windows below build 1809 cannot create a `PT_TOUCH` device.
|
||||
- **`DEVTYPE_TRITON` (`7`) and the shared Steam Controller 2 wire tables** in `pf-driver-proto`:
|
||||
the `0x83` attributes reply, `0x8010`/`0x603D`-style report-length maps, `ID_GET_FIRMWARE_INFO`
|
||||
(`0xF2`) and `ID_OUT_REPORT_HAPTIC_RUMBLE` (`0x80`). `OUT_FEATURE_BIT` (`0x8000_0000`) rides the
|
||||
out-length word to separate a FEATURE report from an OUTPUT one; every other devtype writes plain
|
||||
lengths, so the bit is additive.
|
||||
- **`pf_triton`, the eighth hardware id in the `pf_gamepad` driver package** (Windows). It installs
|
||||
under the existing `pfGamepad` section — never `pfGamepadXbox`, which attaches the `xinputhid` bus
|
||||
filter — and presents as *Punktfunk Virtual Steam Controller*. **Packager- and operator-visible:**
|
||||
an existing install carries the seven-id package, so the Windows SC2 backend does nothing until
|
||||
the package is reinstalled with `punktfunk-host.exe driver install --gamepad`.
|
||||
- **`PUNKTFUNK_STANDBY_SINK_KEEP`.** Set to anything but `0`/`off` to leave a connected-but-inactive
|
||||
external sink powered while streaming. See **Changed** for why the default flipped.
|
||||
- **`overlay_actions`, a first-class client profile field** carrying the whole quick-action ring as
|
||||
one versioned JSON blob (`{"v":2, "ring":[…six slots…], "shortcuts":[…], "pad":{…}}`). It
|
||||
overrides and clears as one unit rather than per key, because a partially-applied ring is not a
|
||||
state any client should have to render. `sc2_capture` joins it as an ordinary boolean.
|
||||
- **Frame statistics reported to the OS** from the vdisplay driver (`pf-vdisplay`), plus commit-mode
|
||||
flag logging and a frame witness in the driver's swap-chain processor — the case-#4 A/B
|
||||
instrumentation, on by default and cheap.
|
||||
- **A `pairing.pending` toast anywhere in the web console**, hung off the event frame that was
|
||||
already arriving. The same event now also invalidates the pending list, which it did not: it
|
||||
refreshed the status card and the pairing status and left the list an operator actually waits on
|
||||
to its own 10 s timer.
|
||||
- **`punktfunk-host` compiles on macOS again, and CI keeps it that way.** Eleven errors across six
|
||||
files, none of them missing functionality — every one a call site or dependency that assumed
|
||||
Linux-or-Windows without saying so, grown from 9 to 11 in four weeks with nobody working on macOS.
|
||||
`gamelease` reaching past `procscan`'s platform-neutral wrappers to `Scanner::system()` now goes
|
||||
through a new `procscan::alive`, restoring that module's documented boundary. A new job checks the
|
||||
compile, which is what stops the count climbing again.
|
||||
- **`pf-vkdecode` diffs a field capture against ffmpeg frame by frame**, decoding to per-frame
|
||||
hashes and reporting which field access units needed concealment. One lock-proving helper replaces
|
||||
six `set_var` copies.
|
||||
|
||||
### Changed
|
||||
|
||||
- **A connected-but-inactive external sink is disabled for the stream's duration, by default**
|
||||
(Windows). A standby TV left on HDMI keeps Windows composing for a head nobody watches. On the lab
|
||||
box the default cut the median compose hole from **6.3 s to 0.7 s over 16 alternating runs**. It
|
||||
is an improvement, not a cure — some holes survive it. Only externals belonging to no topology are
|
||||
ever picked, so laptop panels and active monitors stay untouched; `PUNKTFUNK_STANDBY_SINK_KEEP`
|
||||
restores the old behaviour for a capture card or an AVR passthrough.
|
||||
- **A host power action releases its virtual displays first.** Sleep, restart and shutdown tore down
|
||||
the session but left the display standing, so a wake resumed onto a display built for whoever put
|
||||
the machine to sleep. A display pinned to keep-alive **Forever** is still kept deliberately — that
|
||||
pin is what holds a gamescope game across disconnects.
|
||||
- **The Windows host supervises its status tray for the host's whole lifetime**, gated on the HKLM
|
||||
`Run` value the trayicon task writes. The previous remedy covered console-initiated updates only,
|
||||
and only when the outgoing binary had recorded the intent, so winget, a hand-run setup and a plain
|
||||
crash all left the box iconless until the next sign-in. `spawn_in_active_session` now asks to
|
||||
break away from the service worker's job object; without that, every process it launched — the
|
||||
tray, the user's game, a hook — was reaped when the service stopped, contradicting its own
|
||||
documented contract. The tray menu's **Exit** now stops the host and says so; a sign-out and the
|
||||
uninstaller's `--quit` still leave a headless host running.
|
||||
- **`scripts/install.sh` asks about intent, not internals.** Its four questions became full
|
||||
controller support, third-party Moonlight clients, clipboard and start-at-boot, and the defaults
|
||||
are derived from the box: Bazzite and Nobara join the `punktfunk` group and linger, an active
|
||||
Sunshine or Apollo host opts into Moonlight compat, a seatless SSH session lingers, clipboard
|
||||
stays off. `scripts/ci/check-install-defaults.sh` is the new gate holding the script and the
|
||||
per-system docs pages together. *(luxus, #439.)*
|
||||
- **The access chip is drawn only with the stats overlay** in the presenter, Apple and Android. It
|
||||
previously stood for the whole of any limited session at every stats tier including off, which
|
||||
reads as distraction rather than information. Expiry toasts stay at every tier, because they
|
||||
announce a change rather than describe a state. tvOS already stated it inside the stats HUD.
|
||||
- **One Lucide icon set every Rust shell draws from.** The console drew Lucide marks first, but its
|
||||
path table was private to `pf-console-ui` and its slot-to-icon map lived in `ring.rs`, so the two
|
||||
desktop editors configuring the same ring could reach neither and drew words instead — three
|
||||
shells, three vocabularies for one ring. Both tables move down into `pf-client-core`, derived from
|
||||
masters in `assets/lucide` so a mark cannot drift between shells; a slot now hands out a **name**
|
||||
that `by_name` resolves, rather than an alias per slot. No font ships and no dependency lands:
|
||||
`scripts/gen-lucide-icons.py` folds each 24×24 source SVG into one path string (absolutising a
|
||||
leading relative `m`, since concatenation would re-anchor it), which Skia's own parser strokes at
|
||||
Lucide's native width 2. Lucide v0.462.0, ISC — `LUCIDE-LICENSE` is vendored and
|
||||
`scripts/gen-third-party-notices.py` picks it up.
|
||||
|
||||
### Fixed
|
||||
|
||||
- **A refused swapchain costs fullscreen, not the session** (Windows presenter). A
|
||||
`recreate_swapchain` failure in the resize handler propagated out of `run_session` and ended the
|
||||
stream, after which the shell reported a live session as *"Couldn't connect"* — which is how F11
|
||||
quit the session on the drivers that refuse a fullscreen-sized swapchain. It now warns, drops back
|
||||
to windowed, and rebuilds against the geometry that was already working. A windowed failure still
|
||||
propagates, because there is no smaller state to fall back to. Present-wait is drained before the
|
||||
old swapchain is reused.
|
||||
- **Stage 4 relinks when the display link stops vending** (Apple). Field, iPad Pro on iOS 27: the
|
||||
picture froze twice in one session while audio and input kept running, and only reconnecting
|
||||
cleared it — decode ran at full rate against `ok=0`, `noDrawable=120` and no `vendLeadMs` samples
|
||||
at all, so `CAMetalDisplayLink` had stopped calling back. Stage 4 has no drawable source of its
|
||||
own, and stage 3's `PresentGate.staleAfter` insurance does not reach this path. The render thread
|
||||
now retires the link generation past 250 ms without a vend while frames are still decoding, which
|
||||
also covers an exhausted drawable pool. Logged to the send-logs ring.
|
||||
- **Switch Pro SPI-flash reads are served by range, not by exact (address, length) pair.** Both
|
||||
sticks on a virtual Switch Pro sat in the top-right corner under Steam, centring only at full
|
||||
down-left, while buttons, motion and the kernel's own evdev node were correct throughout. Steam
|
||||
uses SDL's HIDAPI driver, not `hid-nintendo`, and it reads the same calibration as 18 bytes at
|
||||
`0x603D` and 22 at `0x8010` — neither pair matched, so both fell to the zero-fill path, which
|
||||
echoes the requested address, so SDL accepted the reply and parsed a zeroed calibration. A zero
|
||||
centre is never subtracted, leaving every raw axis positive. Reads now come from a modelled flash
|
||||
image; what `hid-nintendo` receives is byte-identical, and the caller loses its zero-fill fallback.
|
||||
- **Steam Input's touch-as-mouse no longer walks the host cursor on a Deck in Gaming Mode.** Steam
|
||||
owns the touchscreen there and replays it as a mouse whose "relative" deltas are absolute
|
||||
positions — a field capture read 0 finger events against 341 mouse motions of 300 to 450 px, each
|
||||
of which walked the locked cursor further into a corner, and with no fingers reaching SDL all
|
||||
three touch models were dead together. `SDL_TOUCH_MOUSE_EVENTS=0` never reached them because the
|
||||
events are Steam's, not SDL's. `SteamTouchMouse` recognises the shape and the presenter drops
|
||||
those motions, raising the session notice once.
|
||||
- **Touch on the letterbox bars reaches the gesture engine** (Android), **two-finger scrolling
|
||||
honours invert-scroll**, **scroll requires exactly two fingers rather than two or more**, and
|
||||
**long-press-to-drag works on every touch engine** rather than only some.
|
||||
- **The flatpak stopped claiming Gaming Mode on every desktop.** `cli::fullscreen_mode()` read
|
||||
`GAMESCOPE_WAYLAND_DISPLAY` as proof of a Deck session, and our own
|
||||
`packaging/flatpak/io.unom.Punktfunk.yml` exports `GAMESCOPE_WAYLAND_DISPLAY=gamescope-0`
|
||||
unconditionally, because the vendored gamescope WSI layer reads that variable and nothing else to
|
||||
decide whether to negotiate HDR10 (`e1adc5d6`, shipped in v0.25.0). Inside the sandbox it was
|
||||
therefore set on every launch on every desktop — reproduced on plain GNOME with no Deck, no
|
||||
gamescope process and no socket. The flatpak is the main Linux channel, so this reached most
|
||||
Linux users.
|
||||
- **`--custom-refresh-rates` reaches a SteamOS-style session.** The two `gamescope-session-plus`
|
||||
paths hand the set to the script as `CUSTOM_REFRESH_RATES`, but Valve's
|
||||
`/usr/lib/steamos/gamescope-session` (as CachyOS ships it) has never read that variable and the
|
||||
`PATH` shim forwards only `PF_HDR_ARGS` — so the flag reached no SteamOS session at all, and
|
||||
Steam's in-session display menu showed one refresh entry, no resolutions, and paced games to that
|
||||
single number. `refresh_rate_args` now chains into that drop-in's `PF_HDR_ARGS`, keyed on the
|
||||
session's own mode.
|
||||
- **A poisoned status mutex no longer aborts the tray process.** `ci.yml`'s unsafe-hygiene gate had
|
||||
been failing on main since `0329afcb`: `unwrap`/`expect`/`panic!` reachable in `extern fn`
|
||||
`wndproc` with no `catch_unwind`. It was right to — a panic crossing an extern boundary aborts
|
||||
since Rust 1.81, so a poisoned lock would take the tray icon away permanently, which is the exact
|
||||
failure the supervisor work in that same commit exists to prevent. Every read of that mutex now
|
||||
uses the poison-tolerant form.
|
||||
- **Two overlays on tvOS accept controller input.** `ConnectOverlay` and `TrustCardView` each mount
|
||||
a zero-size view owning a `GamepadMenuInput`, and both gated it to iOS and macOS. The console home
|
||||
underneath gates *itself* inactive while an overlay is up, so nothing read the pad at all: the
|
||||
wake prompt was a dead end, with neither Cancel nor Try Again reachable, and the trust card had
|
||||
the same hole between a pad-only Apple TV and every unknown host.
|
||||
- **Android TV hides the phone-body rows.** *Rumble on this phone* and *Gyro from this phone* were
|
||||
gated on hardware alone, assuming a TV box answers no to a default `Vibrator` and to a
|
||||
`SensorManager` gyroscope. An Nvidia Shield answers yes to both — most likely the attached
|
||||
controller owning the vibrator and gyroscope the queries find.
|
||||
- **Stale support claims corrected in the README, roadmap and Windows host page.** All three said
|
||||
the AMD (AMF) and Intel (QSV) encoders were CI-green only, while the support matrix — which the
|
||||
roadmap itself names as the arbiter — has recorded since 0.31 that AMF was validated on a Ryzen
|
||||
7000 iGPU and QSV on Arc. A reader comparing the two could only conclude AMD is unsupported in the
|
||||
shipping build.
|
||||
|
||||
---
|
||||
|
||||
## v0.33.0
|
||||
|
||||
45 commits since v0.32.0. Wire stays 2. C ABI stays 26. OpenAPI adds the actions routes.
|
||||
|
||||
Generated
+36
-36
@@ -1090,7 +1090,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cursor-probe"
|
||||
version = "0.33.0"
|
||||
version = "0.34.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"pf-capture",
|
||||
@@ -1222,7 +1222,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "display-disturb"
|
||||
version = "0.33.0"
|
||||
version = "0.34.0"
|
||||
dependencies = [
|
||||
"pf-win-display",
|
||||
"windows 0.62.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -2343,7 +2343,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "latency-probe"
|
||||
version = "0.33.0"
|
||||
version = "0.34.0"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
@@ -2446,7 +2446,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "libvpl-sys"
|
||||
version = "0.33.0"
|
||||
version = "0.34.0"
|
||||
dependencies = [
|
||||
"bindgen",
|
||||
"cmake",
|
||||
@@ -2475,7 +2475,7 @@ checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad"
|
||||
|
||||
[[package]]
|
||||
name = "loss-harness"
|
||||
version = "0.33.0"
|
||||
version = "0.34.0"
|
||||
dependencies = [
|
||||
"punktfunk-core",
|
||||
]
|
||||
@@ -2967,7 +2967,7 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
|
||||
|
||||
[[package]]
|
||||
name = "pf-bitstream"
|
||||
version = "0.33.0"
|
||||
version = "0.34.0"
|
||||
dependencies = [
|
||||
"cros-codecs",
|
||||
"tracing",
|
||||
@@ -2975,7 +2975,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pf-capture"
|
||||
version = "0.33.0"
|
||||
version = "0.34.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"ashpd",
|
||||
@@ -2996,7 +2996,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pf-client-core"
|
||||
version = "0.33.0"
|
||||
version = "0.34.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"ash",
|
||||
@@ -3035,7 +3035,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pf-clipboard"
|
||||
version = "0.33.0"
|
||||
version = "0.34.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"ashpd",
|
||||
@@ -3053,7 +3053,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pf-console-ui"
|
||||
version = "0.33.0"
|
||||
version = "0.34.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"ash",
|
||||
@@ -3076,7 +3076,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pf-dxvadec"
|
||||
version = "0.33.0"
|
||||
version = "0.34.0"
|
||||
dependencies = [
|
||||
"cros-codecs",
|
||||
"pf-bitstream",
|
||||
@@ -3086,7 +3086,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pf-encode"
|
||||
version = "0.33.0"
|
||||
version = "0.34.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"ash",
|
||||
@@ -3112,7 +3112,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pf-frame"
|
||||
version = "0.33.0"
|
||||
version = "0.34.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"libc",
|
||||
@@ -3125,7 +3125,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pf-gpu"
|
||||
version = "0.33.0"
|
||||
version = "0.34.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"pf-host-config",
|
||||
@@ -3139,11 +3139,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pf-host-config"
|
||||
version = "0.33.0"
|
||||
version = "0.34.0"
|
||||
|
||||
[[package]]
|
||||
name = "pf-inject"
|
||||
version = "0.33.0"
|
||||
version = "0.34.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"ashpd",
|
||||
@@ -3172,14 +3172,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pf-paths"
|
||||
version = "0.33.0"
|
||||
version = "0.34.0"
|
||||
dependencies = [
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pf-presenter"
|
||||
version = "0.33.0"
|
||||
version = "0.34.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"ash",
|
||||
@@ -3194,7 +3194,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pf-update"
|
||||
version = "0.33.0"
|
||||
version = "0.34.0"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -3202,7 +3202,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pf-update-check"
|
||||
version = "0.33.0"
|
||||
version = "0.34.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"aws-lc-rs",
|
||||
@@ -3214,7 +3214,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pf-vaadec"
|
||||
version = "0.33.0"
|
||||
version = "0.34.0"
|
||||
dependencies = [
|
||||
"cros-codecs",
|
||||
"pf-bitstream",
|
||||
@@ -3223,7 +3223,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pf-vdisplay"
|
||||
version = "0.33.0"
|
||||
version = "0.34.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"ashpd",
|
||||
@@ -3256,7 +3256,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pf-vkdecode"
|
||||
version = "0.33.0"
|
||||
version = "0.34.0"
|
||||
dependencies = [
|
||||
"ash",
|
||||
"cros-codecs",
|
||||
@@ -3267,7 +3267,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pf-win-display"
|
||||
version = "0.33.0"
|
||||
version = "0.34.0"
|
||||
dependencies = [
|
||||
"pf-paths",
|
||||
"punktfunk-core",
|
||||
@@ -3278,7 +3278,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pf-zerocopy"
|
||||
version = "0.33.0"
|
||||
version = "0.34.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"ash",
|
||||
@@ -3490,7 +3490,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "punktfunk-cli"
|
||||
version = "0.33.0"
|
||||
version = "0.34.0"
|
||||
dependencies = [
|
||||
"pf-client-core",
|
||||
"punktfunk-core",
|
||||
@@ -3500,7 +3500,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "punktfunk-client-android"
|
||||
version = "0.33.0"
|
||||
version = "0.34.0"
|
||||
dependencies = [
|
||||
"android_logger",
|
||||
"anyhow",
|
||||
@@ -3524,7 +3524,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "punktfunk-client-linux"
|
||||
version = "0.33.0"
|
||||
version = "0.34.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-channel",
|
||||
@@ -3541,7 +3541,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "punktfunk-client-session"
|
||||
version = "0.33.0"
|
||||
version = "0.34.0"
|
||||
dependencies = [
|
||||
"pf-client-core",
|
||||
"pf-console-ui",
|
||||
@@ -3555,7 +3555,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "punktfunk-client-windows"
|
||||
version = "0.33.0"
|
||||
version = "0.34.0"
|
||||
dependencies = [
|
||||
"async-channel",
|
||||
"mdns-sd",
|
||||
@@ -3573,7 +3573,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "punktfunk-core"
|
||||
version = "0.33.0"
|
||||
version = "0.34.0"
|
||||
dependencies = [
|
||||
"aes-gcm",
|
||||
"cbindgen",
|
||||
@@ -3606,7 +3606,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "punktfunk-encode-worker"
|
||||
version = "0.33.0"
|
||||
version = "0.34.0"
|
||||
dependencies = [
|
||||
"pf-encode",
|
||||
"tracing",
|
||||
@@ -3615,7 +3615,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "punktfunk-host"
|
||||
version = "0.33.0"
|
||||
version = "0.34.0"
|
||||
dependencies = [
|
||||
"aes",
|
||||
"aes-gcm",
|
||||
@@ -3685,7 +3685,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "punktfunk-probe"
|
||||
version = "0.33.0"
|
||||
version = "0.34.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"mdns-sd",
|
||||
@@ -3699,7 +3699,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "punktfunk-tray"
|
||||
version = "0.33.0"
|
||||
version = "0.34.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"ksni",
|
||||
@@ -3723,7 +3723,7 @@ checksum = "d55d956fa96f5ec02be2e13af0e20391a5aa83d6a074e3ad368959d0fab299ea"
|
||||
|
||||
[[package]]
|
||||
name = "pyrowave-sys"
|
||||
version = "0.33.0"
|
||||
version = "0.34.0"
|
||||
dependencies = [
|
||||
"bindgen",
|
||||
"cmake",
|
||||
|
||||
+1
-1
@@ -65,7 +65,7 @@ exclude = [
|
||||
ndk = { path = "clients/android/native/vendor/ndk" }
|
||||
|
||||
[workspace.package]
|
||||
version = "0.33.0"
|
||||
version = "0.34.0"
|
||||
edition = "2024"
|
||||
rust-version = "1.85"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
"name": "MIT OR Apache-2.0",
|
||||
"identifier": "MIT OR Apache-2.0"
|
||||
},
|
||||
"version": "0.33.0"
|
||||
"version": "0.34.0"
|
||||
},
|
||||
"paths": {
|
||||
"/api/v1/actions": {
|
||||
|
||||
@@ -137,6 +137,9 @@ impl PartialEq for HostsProps {
|
||||
///
|
||||
/// Hover renders the WinUI card pointer-over look — the card background lifts to the control
|
||||
/// hover fill while the pointer is inside the tile (tracked via `hover`, see `HostsProps`).
|
||||
// Three call sites, each passing a different mix of the optional tail — grouping the eight into a
|
||||
// props struct would make every one of them construct it inline for no reader gain.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn host_tile(
|
||||
id: &str,
|
||||
hover: &Hover,
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"name": "MIT OR Apache-2.0",
|
||||
"identifier": "MIT OR Apache-2.0"
|
||||
},
|
||||
"version": "0.33.0"
|
||||
"version": "0.34.0"
|
||||
},
|
||||
"paths": {
|
||||
"/api/v1/actions": {
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
This release is for everyone who streams games or a desktop with Punktfunk. It works with 0.33.x, so everything you have already paired keeps working, and you can update one side at a time.
|
||||
|
||||
The headline is a control surface for everyone who streams to a screen they hold. Touch has been able to move a cursor for a long time. It could not end a stream, show a keyboard, switch touch mode or send Ctrl+Alt+Del without leaving the picture. Now a **two-finger twist** on the stream opens a ring of six buttons under your fingers. You choose what the six are, and you edit them by using the ring itself rather than reading a list of names.
|
||||
|
||||
Phones and tablets also get an **on-screen controller**. Show it from the ring when a game wants a gamepad and you do not have one with you. The host sees a controller arrive, exactly as if you had plugged one in.
|
||||
|
||||
And the Steam Controller 2 goes much further than Linux. It now streams from an iPhone, iPad, Mac and Android device, and reaches a **Windows** host as well as a Linux one. It still arrives as itself, rather than flattened into a generic pad. That work came from a contributor, credited by name further down.
|
||||
|
||||
## TL;DR
|
||||
|
||||
- **A quick-action ring on the stream.** Open it with a two-finger twist on a phone or tablet, a short Back on Apple TV, or Select+A on a controller anywhere.
|
||||
- **An on-screen controller on Android, iPhone and iPad**, for a game that needs a gamepad you did not bring.
|
||||
- **The Steam Controller 2 now works from Apple and Android devices, and to a Windows host.** Read "Before you update" if your host runs Windows.
|
||||
- **Linux: the app stops opening fullscreen on an ordinary desktop.** Our own Flatpak told it that every machine was a Steam Deck. Flatpak is the main Linux channel, so this reached most Linux users.
|
||||
- **Apple: fixed a picture that froze while the sound kept playing.** Only reconnecting cleared it. It now recovers on its own.
|
||||
- **Windows: F11 no longer ends your session.** On some graphics drivers, going fullscreen dropped the stream and then blamed the connection.
|
||||
|
||||
## What's in this release
|
||||
|
||||
- [Before you update](#before-you-update)
|
||||
- [New](#new)
|
||||
- [Improved](#improved)
|
||||
- [Fixed](#fixed)
|
||||
- [Thanks](#thanks)
|
||||
- [For developers](#for-developers)
|
||||
|
||||
## Before you update
|
||||
|
||||
- **Windows hosts, for the Steam Controller 2 only: reinstall the controller driver.** Windows support for that pad needs a driver package your current install does not have. Run `punktfunk-host.exe driver install --gamepad` and reconnect the pad. Every other controller keeps working untouched, so skip this if you do not own one.
|
||||
- **If you keep a virtual display on "Forever", read this before sending your host to sleep.** Sleep, restart and shut down now clear the virtual displays first, so a wake starts clean. A display you pinned to Forever is kept on purpose, because that pin is what holds a game running across disconnects. If a wake lands on a black screen, release that display from the console under **Virtual displays**.
|
||||
- **Windows: the tray icon's Exit entry now stops the host.** It used to close only the icon and leave the host streaming. The menu says so before it acts. Signing out still leaves the host running, as before.
|
||||
|
||||
## New
|
||||
|
||||
- **The quick-action ring.** A two-finger twist on the stream opens six buttons under your fingers, on Android, iPhone and iPad. About 10° starts it opening and 30° commits it, so letting go early winds it back in and sends nothing. The centre button opens the full catalogue and the resolution presets. Android's Back gesture opens the same ring instead of ending your session, and Apple TV opens it with a short press of Back. A controller opens it with Select+A on every client, and the host never sees those two presses.
|
||||
- **You edit the ring by using the ring.** Tap a button to change it, drag one onto another to swap them. With a controller, the stick walks the buttons, A changes one, and Y lifts a button so A can drop it somewhere else. There is no separate list to learn.
|
||||
- **Custom keyboard shortcuts on the ring.** Give a shortcut a name, pick its modifiers, and choose the key on a keyboard you can see. Ctrl+Shift+Esc and Alt+F4 stop needing a real keyboard on the couch.
|
||||
- **An on-screen controller on Android, iPhone and iPad.** Show and hide it from the ring's **Virtual controller** button. The host sees one controller arrive when it appears and one leave when it goes, on the next free slot beside any real pad you have connected. A stick follows your thumb from wherever it lands, and the D-pad reads eight directions. A trigger reads how far down your finger sits, so a slow press stays a slow press. A finger anywhere else still drives your touch mode, so tap-to-click keeps working beside it. Choose **Full**, **Sticks and shoulders** or **D-pad and face buttons**, and set its opacity and size in settings.
|
||||
- **The Steam Controller 2 streams from Apple and Android devices.** Android reads it over USB, the Puck dongle or Bluetooth; Apple over Bluetooth. The pad reaches your host **as itself**, so the trackpads, gyro and haptics behave the way they do when it is plugged in locally. It is on by default on Android and off on Apple. Switching it on there asks for Bluetooth permission, which is a question worth asking only from someone who owns the controller.
|
||||
- **Windows hosts can present a Steam Controller 2.** Previously Linux only. The multi-pad Puck dongle stays Linux-only for now.
|
||||
- **The console tells you a device is asking to pair, wherever you are in it.** A pairing request used to appear only on the Pairing page, so it waited until somebody thought to go and look. That is worst on a phone, where the page is several taps away. A notice now names the device and offers one button through to it, and the waiting list refreshes the moment the request arrives rather than up to ten seconds later.
|
||||
- **Every client draws the same icons.** The quick-action ring showed icons in one place and words in another, because three separate apps each had their own vocabulary for the same six buttons. They now share one set, so a button looks the same wherever you meet it.
|
||||
- **A host card shows which system the machine runs**, in place of the first letter of its name. The name is spelled out underneath anyway. A host too old to say what it runs keeps its initial.
|
||||
|
||||
## Improved
|
||||
|
||||
- **A switched-off TV plugged into your Windows host stops costing you frames.** A standby screen on HDMI keeps Windows drawing for a head nobody is watching, and your stream pays for it. The host now switches such a screen off for the duration of the stream. On our test machine that cut the median stall from 6.3 seconds to 0.7 across sixteen alternating runs. It is an improvement rather than a cure — some stalls survive it. Only a screen that belongs to no display arrangement is ever chosen, so your laptop panel and your working monitors are never touched. If a screen must stay awake, for a capture card or a receiver, there is a setting to keep it.
|
||||
- **Putting your host to sleep now clears its virtual displays first.** A wake used to resume onto a display built for whoever sent the machine to sleep.
|
||||
- **The Windows tray icon survives an update.** It used to disappear on every upgrade and stay gone until the next sign-in. Only console-initiated updates were ever covered, so a winget upgrade, a hand-run setup and a plain crash all ended the same way. The host now watches the icon for as long as it runs.
|
||||
- **The Linux install script asks about what you want, not how it works.** Its questions are now full controller support, third-party Moonlight clients, the shared clipboard, and starting at boot — and it picks sensible defaults from your machine. Bazzite and Nobara join the group and keep running after you log out. A host already running Sunshine or Apollo is offered Moonlight compatibility, and an SSH session with no screen keeps running too. It still runs unattended, and re-running it is still safe.
|
||||
- **The access badge appears only when the stats overlay does.** A badge that never goes away reads as clutter. What it tells you, which is what this session may do, is something you check now and then rather than watch. Notices about a change still appear at any time.
|
||||
- **Touch handling is more consistent.** Long-press to drag now works on every client rather than some. Two-finger scrolling respects your invert-scroll setting. Scrolling needs exactly two fingers, so a three-finger gesture is no longer read as a scroll.
|
||||
- **A host that cannot accept touch now says so.** Some Linux desktops and older Windows builds have nowhere to deliver a touch contact, and they were dropping every one in silence. Your client now falls back to the trackpad model for that session and tells you when the stream starts.
|
||||
|
||||
## Fixed
|
||||
|
||||
- **Windows: F11 ended the session instead of going fullscreen.** On graphics drivers that refuse a fullscreen-sized surface, the failure ended the stream, and the app then reported a live session as "Couldn't connect". A refused fullscreen now costs you the fullscreen and nothing else.
|
||||
- **Apple: the picture froze while sound and input kept running.** Reported from an iPad Pro, twice in one session, and only reconnecting cleared it. The part of the pipeline that hands frames to the screen had stopped asking for them, and nothing noticed. It is now watched and restarted within a quarter of a second.
|
||||
- **Both sticks on a virtual Switch Pro controller sat in the top-right corner under Steam.** They reached the centre only at full down-left, while the buttons and motion were fine. Steam reads the controller's calibration in a shape we did not answer, so it read zeros and treated a zeroed centre as real.
|
||||
- **Steam Deck in Gaming Mode: touch dragged the host cursor into a corner and every touch mode stopped working.** Steam owns the touchscreen there and replays it as mouse movement, which the stream then applied as if you had moved a mouse a very long way. One capture showed 341 such movements and not a single finger. Punktfunk now recognises that pattern, ignores it, and tells you once why.
|
||||
- **Android: touching the black bars beside the picture did nothing.** Those taps never reached the gesture handling at all.
|
||||
- **Linux: the Flatpak app opened fullscreen on every desktop.** It checks one setting to tell whether it is running in Steam's Gaming Mode, and our own Flatpak sets that value on every launch. The graphics layer we bundle reads that setting, and nothing else, to decide whether to offer HDR. Inside the sandbox it was always set, so the app believed every machine was a Deck. Reproduced on a plain GNOME desktop with no Deck and no Steam session anywhere.
|
||||
- **Steam Deck and CachyOS: the in-session display menu offered one refresh rate and no resolutions.** The list of rates we build never reached a SteamOS-style session, so games paced themselves to that single number.
|
||||
- **Apple TV: the wake prompt could not be answered with a controller.** Neither Cancel nor Try Again could be pressed, which left a failed wake as a dead end. The prompt shown for an unknown host had the same problem.
|
||||
- **Android TV: settings offered rumble and gyro "from this phone" on a box that has neither.** An Nvidia Shield answers yes when asked whether it can vibrate, most likely on behalf of an attached controller, so those rows appeared and promised something the box cannot do.
|
||||
- **Windows: the tray icon could vanish for good.** An internal lock left in a bad state took the whole tray process down with it, which is exactly the disappearance the new supervision is there to prevent.
|
||||
- **Our own documentation said AMD and Intel encoding was untested.** It has been validated since 0.31, on a Ryzen 7000 integrated GPU and on Intel Arc. The README, the roadmap and the Windows host page were never updated to say so. If you skipped Punktfunk because you have an AMD card, that was our mistake.
|
||||
|
||||
## Thanks
|
||||
|
||||
Two people outside the team wrote code that ships in this release, and both are named here because the work is theirs.
|
||||
|
||||
**Keith Porcaro** built Steam Controller 2 support beyond Linux. It is five separate pieces across four platforms, and the largest single contribution in this release:
|
||||
|
||||
- the shared description of how that controller talks;
|
||||
- the Windows driver identity that lets a Windows host present one;
|
||||
- the path that carries the pad's raw reports across the stream;
|
||||
- Bluetooth capture on Apple devices;
|
||||
- the motion-sensor gate on Android.
|
||||
|
||||
If you use that controller from a phone, a tablet, a Mac, or to a Windows PC, this is why.
|
||||
**luxus** rewrote what the Linux install script asks you. It used to ask about our internals. It now asks what you want and works the rest out from your machine. They also tightened the previous release's changelog to our own house style, which is the kind of contribution nobody has to make.
|
||||
|
||||
The rest started, as usual, with people describing exactly what they saw:
|
||||
|
||||
- **"The GTK client is just launching in fullscreen."** One sentence, and it named a bug that had been shipping to most Linux users in our main channel.
|
||||
- **"All text looks boring and ugly"** about the console's dial, which is the shortest bug report we have had and completely correct.
|
||||
- **The iPad whose picture froze twice in one session** while the sound kept playing. The detail that audio survived is what pointed at the screen rather than the network.
|
||||
- **The Switch Pro sticks pinned in a corner**, with the observation that the same pad read correctly outside Steam. That one detail ruled out half the system.
|
||||
- **The Steam Deck whose touch controls all died at once** in Gaming Mode. Three separate features failing together is what showed they shared a cause.
|
||||
|
||||
Thank you.
|
||||
|
||||
One caveat we would rather write down than have you find. Touch on a Steam Deck in Gaming Mode is the one path we have not re-run on the hardware since the fix. It was built from a capture of exactly that failure and it is covered by tests, but a Deck has not played the finished build back to us. If a gesture still behaves oddly there, please tell us — and say what you saw, because that is what made every other fix on this page findable.
|
||||
|
||||
## For developers
|
||||
|
||||
Protocol, application binary interface (ABI), driver and embedder detail is in [the v0.34.0 CHANGELOG](https://git.unom.io/unom/punktfunk/src/tag/v0.34.0/CHANGELOG.md). It carries the version table and the full breaking-change list.
|
||||
|
||||
The short version: **the ABI that embedders build against moves 26 to 28, and one of those steps widens a struct.** `PunktfunkHidOutput` grows from 19 to 85 bytes, so this is a recompile rather than a relink — the existing version equality check is what catches a stale build. Everything else versioned stands still: the streaming protocol, the driver protocol, the gamepad channel, the add-on contract and the management API are all where 0.33.0 left them.
|
||||
|
||||
Packagers on Windows: the controller driver package gains an eighth hardware identity for the Steam Controller 2, so it must be rebuilt and reinstalled for that pad to work.
|
||||
@@ -0,0 +1,5 @@
|
||||
• A quick-action ring: twist two fingers on the stream for six buttons you pick — end stream, keyboard, touch mode, your own shortcuts. Back opens it too, and you edit it by using it.
|
||||
• An on-screen controller for a game that wants a gamepad you did not bring. Show it from the ring.
|
||||
• Your Steam Controller 2 now streams as itself over USB, the Puck dongle or Bluetooth.
|
||||
• Tapping the black bars beside the picture works again.
|
||||
• On a TV box, settings drop rumble and gyro rows it never had.
|
||||
@@ -284,7 +284,6 @@ PUNKTFUNK_SHOT_SETTLE_MS
|
||||
PUNKTFUNK_SLICE_STREAM
|
||||
PUNKTFUNK_SPIKE_HDR
|
||||
PUNKTFUNK_STALL_PROBES
|
||||
PUNKTFUNK_STANDBY_SINK_KEEP
|
||||
PUNKTFUNK_STATS_STDOUT
|
||||
PUNKTFUNK_STEAM_FORCE
|
||||
PUNKTFUNK_STEAM_REMAP
|
||||
|
||||
Reference in New Issue
Block a user