phase: 03_audio_share
Build and Push Containers / test (push) Successful in 35s
Build and Push Containers / build-and-push-app (push) Successful in 11s

**Phase 03 final verification pass — complete, 100% green.**

- Verified all 4 tasks done in `complete/03_audio_share/`; confirmed implementation in `watch.js` (one composed `MediaStream` per tile, staged-only `setMuted()` policy, `data-audio` state), `share.js` (precise `NotAllowedError` rethrow, 3 honest `#stat-audio` states, mid-share audio republish), conftest flags, and the new `tests/e2e/test_audio_share.py` (11 tests, all **passed** — none skipped).
- **Criteria:** (1) viewer inbound audio `bytesReceived` strictly increases + composed stream 1 video/1 audio track while frames still decode — **passed**; (2) staged-only audio via keyboard `m`, mouse button, and `unstage()` re-mute — **passed**; (3) `shared`/`silent`/`not offered` + mid-share audio loss updates panel, roster and tiles — **passed**; (4) cancelled picker reports cancellation, single attempt — **passed**; (5) SECURITY.md §4 Audio, README platform notes, kiosk doc all describe shipped behaviour incl. Linux/PipeWire reality — **verified**; (6) full gate — **passed** (below).
- **Gates:** `uv run ruff check . && uv run ruff format --check .` → clean; `uv run pyright` → 0 errors; `uv run pytest` → 245 passed, 4 skipped (only the `MIRROR_REALDISPLAY`-gated X11 tests); `MIRROR_REALDISPLAY=1 uv run pytest -m realdisplay` → 3 passed, 1 skipped (real-capture audio: documented skip naming the exact host/flag reason, per task 04).
- **Docs:** README.md reviewed in full against code (env table, CLI flags, routes, kiosk key table, quickstart, audio notes) — consistent, no changes needed. AGENTS.md — all commands/paths/coverage claims verified accurate, no stale statements, no changes needed.
- **Defect fixed (pre-existing):** `docs/kiosk-silverblue.md` + `install-kiosk.sh`, `kiosk.conf`, `gnome-kiosk-script` used `mirror.reeselink.com` while README/SECURITY.md use `mirror.reeseapps.com` (the deployment domain, consistent with the fleet); corrected 7 occurrences in 4 files.
- No live-infrastructure changes; realdisplay suite ran on private Xvfb only.
- **Next pending phase:** `04_reachable_share_cta`.
This commit is contained in:
2026-11-01 22:40:30 -05:00
parent 1da466a412
commit d43eb407f8
39 changed files with 1554 additions and 36 deletions
+27 -4
View File
@@ -107,10 +107,33 @@ the compositor protecting the user, and mirror must not try to work around it.
### Audio
Sharing tab/window audio is opt-in in the browser's own picker. mirror falls back
to silent capture when the source has no audio rather than failing the share, and
viewers start muted (autoplay policy) and must tap to unmute — a deliberate,
user-initiated action.
Audio is user-initiated by design: it never starts on its own, and a
reconnect never revives it.
What audio exists is the browser's decision, not mirror's. The picker offers
it (a "share audio" tickbox in Chrome, tab audio for tabs), and mirror
accepts the track when the source has one — falling back to a *silent*
capture, rather than failing the share, when it does not. A source that
loses its audio mid-share is announced: the sharer's panel flips and every
viewer's tile loses its button, instead of keeping a dead control.
On the wall, **only the staged mirror can be audible**. Every mirror starts
muted, and the one deliberate gesture that unmutes — the tile's audio button
or the `m` key — is always a click or a keypress. Unmuting one mirror mutes
the others, and leaving the stage re-mutes the one you left.
What *system* audio a browser can capture is a platform fact, stated plainly:
* **Chrome on Linux** captures *tab* audio reliably, and whole-screen/
system audio only where the platform offers it — PipeWire/PulseAudio's
loopback, plus the picker's "share audio" tickbox.
* **Firefox's desktop capture does not offer system audio at all on Linux.**
A wall of Firefox tiles is silent by the browser's rule, not mirror's.
mirror neither works around that nor fakes it: when a source has no audio,
the sharer's panel says `silent` (the browser honoured the request; the
source has no track) or `not offered` (the capture only succeeded after the
audio constraint was dropped), and the wall shows no button at all.
## 5. Operational guidance