The host-audio switch reaches every client, not just the desktop ones #423

Merged
enricobuehler merged 2 commits from worktree-keep-host-audio-parity into main 2026-08-27 23:26:45 +00:00
Owner

keep_host_audio shipped in 0.32.0 wired end to end — the setting, the CLIENT_CAP_KEEP_HOST_AUDIO ask, the host's capture policy — but only three surfaces ever offered it: the Linux GTK client, the Windows client, and the desktop console. Apple and Android carried no reference to it at all, so the one place a phone or an Apple TV would look for "why did my PC go quiet" had nothing to find.

Reported from the field: the option could not be found on the Apple client, with the (correct) guess that other clients were missing it too.

There is no shared settings schema — each client hand-mirrors trust::Settings — so this row simply never got mirrored.

What changed

Apple gains the full tier-P treatment: a keepHostAudio defaults key, the EffectiveSettings field, the StreamProfile overlay (so a per-host profile can keep the study PC's headphones live while the TV profile mutes them), the Audio-section row, and the bit itself OR'd into the connect's clientCaps beside the presenter caps.

Android gains the same across Settings, Profiles — including the KNOWN key set, without which the key reads as unknown carry-through — the settings row, the console JSON both ways, and a new keepHostAudio argument threaded through nativeConnect into the JNI caps expression.

pf-console-ui had parked RowId::KeepHostAudio in desktop_only with a comment saying "until the Android session advertises the bit". It does now, so the gate comes off and the order-sensitive split test loses its entry. Without this the Android console would still have hidden the row after the client was wired.

The C ABI never exported the constant. client_caps is a passthrough byte, so nothing needs a version bump — but cbindgen had no rename entry and emitted a bare CLIENT_CAP_KEEP_HOST_AUDIO into every embedder's namespace, the exact pollution R21 exists to prevent. It now carries the PUNKTFUNK_ prefix its AUDIO_HIRES sibling has, plus the compile-time drift assert.

Captions are the Linux client's wording verbatim, and the row sits between audio quality and the microphone on all four clients, because a setting that reads differently per platform is the same bug in a smaller font. The docs line claiming "Linux, Windows and the desktop console" now says everywhere.

Verification

Check Result
swift build (Apple) clean
Apple unit tests 384 passed, 0 failed
:app:compileDebugKotlin BUILD SUCCESSFUL
:kit:cargoNdkClippy clean — covers pf-console-ui + punktfunk-client-android under the Android target
pf-console-ui tests (Linux container) 205 passed, 0 failed, incl. platform_row_split_hides_only_the_other_platforms_concepts
cargo fmt --all --check clean

CHANGELOG deliberately untouched — this repo writes it at release time.

Follow-up worth considering

The root cause is structural: with no shared settings schema, every new client setting is ~6 manual edits per client and any miss is silent until a user reports it. That is the pending settings-schema programme, out of scope here.

`keep_host_audio` shipped in 0.32.0 wired end to end — the setting, the `CLIENT_CAP_KEEP_HOST_AUDIO` ask, the host's capture policy — but only three surfaces ever offered it: the Linux GTK client, the Windows client, and the desktop console. **Apple and Android carried no reference to it at all**, so the one place a phone or an Apple TV would look for "why did my PC go quiet" had nothing to find. Reported from the field: the option could not be found on the Apple client, with the (correct) guess that other clients were missing it too. There is no shared settings schema — each client hand-mirrors `trust::Settings` — so this row simply never got mirrored. ## What changed **Apple** gains the full tier-P treatment: a `keepHostAudio` defaults key, the `EffectiveSettings` field, the `StreamProfile` overlay (so a per-host profile can keep the study PC's headphones live while the TV profile mutes them), the Audio-section row, and the bit itself OR'd into the connect's `clientCaps` beside the presenter caps. **Android** gains the same across `Settings`, `Profiles` — including the `KNOWN` key set, without which the key reads as unknown carry-through — the settings row, the console JSON both ways, and a new `keepHostAudio` argument threaded through `nativeConnect` into the JNI caps expression. **`pf-console-ui`** had parked `RowId::KeepHostAudio` in `desktop_only` with a comment saying *"until the Android session advertises the bit"*. It does now, so the gate comes off and the order-sensitive split test loses its entry. Without this the Android console would still have hidden the row after the client was wired. **The C ABI** never exported the constant. `client_caps` is a passthrough byte, so nothing needs a version bump — but cbindgen had no rename entry and emitted a bare `CLIENT_CAP_KEEP_HOST_AUDIO` into every embedder's namespace, the exact pollution R21 exists to prevent. It now carries the `PUNKTFUNK_` prefix its `AUDIO_HIRES` sibling has, plus the compile-time drift assert. Captions are the Linux client's wording verbatim, and the row sits between audio quality and the microphone on all four clients, because a setting that reads differently per platform is the same bug in a smaller font. The docs line claiming "Linux, Windows and the desktop console" now says everywhere. ## Verification | Check | Result | |---|---| | `swift build` (Apple) | clean | | Apple unit tests | 384 passed, 0 failed | | `:app:compileDebugKotlin` | BUILD SUCCESSFUL | | `:kit:cargoNdkClippy` | clean — covers `pf-console-ui` + `punktfunk-client-android` under the Android target | | `pf-console-ui` tests (Linux container) | 205 passed, 0 failed, incl. `platform_row_split_hides_only_the_other_platforms_concepts` | | `cargo fmt --all --check` | clean | CHANGELOG deliberately untouched — this repo writes it at release time. ## Follow-up worth considering The root cause is structural: with no shared settings schema, every new client setting is ~6 manual edits per client and any miss is silent until a user reports it. That is the pending settings-schema programme, out of scope here.
enricobuehler added 1 commit 2026-08-27 23:09:43 +00:00
The host-audio switch reaches every client, not just the desktop ones
ci / bun-nix (pull_request) Successful in 30s
ci / web (pull_request) Successful in 1m15s
ci / docs-drift (pull_request) Failing after 1m17s
ci / docs-site (pull_request) Successful in 1m44s
apple / swift (pull_request) Successful in 2m13s
apple / distribute (pull_request) Skipped
apple / screenshots (pull_request) Skipped
ci / rust-arm64 (pull_request) Successful in 2m57s
android / android (pull_request) Canceled after 3m16s
ci / rust (pull_request) Canceled after 3m1s
windows-client / client (arm64, --no-default-features, aarch64-pc-windows-msvc, C:\t-a64) (pull_request) Canceled after 3m13s
windows-client / client (x64, , x86_64-pc-windows-msvc, C:\t) (pull_request) Canceled after 0s
59bdef5230
`keep_host_audio` shipped in 0.32.0 wired end to end — the setting, the
`CLIENT_CAP_KEEP_HOST_AUDIO` ask, the host's capture policy — but only three
surfaces ever offered it: the Linux GTK client, the Windows client, and the
desktop console. Apple and Android carried no reference to it at all, so the
one place a phone or an Apple TV would look for "why did my PC go quiet" had
nothing to find. There is no shared settings schema; each client hand-mirrors
`trust::Settings`, and this row simply never got mirrored.

Apple gains the full tier-P treatment: a `keepHostAudio` defaults key, the
`EffectiveSettings` field, the `StreamProfile` overlay (so a per-host profile
can keep the study PC's headphones live while the TV profile mutes them), the
Audio-section row, and the bit itself OR'd into the connect's `clientCaps`
beside the presenter caps. Android gains the same across `Settings`,
`Profiles` — including the `KNOWN` key set, without which the key reads as
unknown carry-through — the settings row, the console JSON both ways, and a
new `keepHostAudio` argument threaded through `nativeConnect` into the JNI
caps expression.

`pf-console-ui` had parked `RowId::KeepHostAudio` in `desktop_only` with a
comment saying "until the Android session advertises the bit". It does now, so
the gate comes off and the order-sensitive split test loses its entry.

The C ABI never exported the constant: `client_caps` is a passthrough byte, so
nothing needed a version bump, but cbindgen had no rename entry and emitted a
bare `CLIENT_CAP_KEEP_HOST_AUDIO` into every embedder's namespace — the exact
pollution R21 exists to prevent. It now carries the `PUNKTFUNK_` prefix its
`AUDIO_HIRES` sibling has, plus the compile-time drift assert.

Captions are the Linux client's wording verbatim, and the row sits between
audio quality and the microphone on all four clients, because a setting that
reads differently per platform is the same bug in a smaller font. The docs
line claiming "Linux, Windows and the desktop console" now says everywhere.

Verified: swift build + 384 Apple tests; `:app:compileDebugKotlin`;
`:kit:cargoNdkClippy` over pf-console-ui and the Android native crate; and all
205 pf-console-ui tests on Linux in a container, the split test among them.
enricobuehler added 1 commit 2026-08-27 23:12:58 +00:00
The new cap constant is a wire bit, not a knob, so it joins the baseline
ci / bun-nix (pull_request) Successful in 1m1s
ci / docs-drift (pull_request) Successful in 54s
ci / docs-site (pull_request) Successful in 1m48s
ci / web (pull_request) Successful in 1m59s
apple / swift (pull_request) Successful in 2m9s
apple / distribute (pull_request) Skipped
apple / screenshots (pull_request) Skipped
ci / rust-arm64 (pull_request) Successful in 2m48s
windows-client / client (arm64, --no-default-features, aarch64-pc-windows-msvc, C:\t-a64) (pull_request) Successful in 4m0s
android / android (pull_request) Successful in 6m43s
ci / rust (pull_request) Successful in 9m4s
windows-client / client (x64, , x86_64-pc-windows-msvc, C:\t) (pull_request) Successful in 7m56s
93f0739160
`check-docs-drift.sh` matches on the `PUNKTFUNK_*` shape, which cannot tell an
environment variable from a cbindgen-exported ABI constant — so exporting
`PUNKTFUNK_CLIENT_CAP_KEEP_HOST_AUDIO` read as a new undocumented knob and
turned the job red. Every sibling is already listed for exactly this reason:
the four other `CLIENT_CAP_*`, all eight `HOST_CAP_*`, all eight
`VIDEO_CAP_*`. This one goes beside them, in sort order.

It is not documentation debt being waved through. The bit's user-facing half
is the "Keep host audio playing" row, already written up in client-settings.md
and pointed at from the `PUNKTFUNK_AUDIO_OUTPUT_MODE` table; the embedder's
half is the doc comment cbindgen carries into the header. There is no
configuration surface here to document, because there is no variable.
enricobuehler merged commit a3e073fd3a into main 2026-08-27 23:26:45 +00:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: unom/punktfunk#423