**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`.
84 lines
3.9 KiB
Bash
Executable File
84 lines
3.9 KiB
Bash
Executable File
#!/bin/sh
|
|
# ~/.local/bin/gnome-kiosk-script — the mirror kiosk application.
|
|
#
|
|
# Installed by docs/kiosk-silverblue/install-kiosk.sh; see that runbook.
|
|
#
|
|
# `gnome-kiosk-script-session` runs this file as the kiosk user inside the
|
|
# kiosk session, and this script re-execs itself forever (the upstream example
|
|
# does the same). That has two consequences worth designing around:
|
|
#
|
|
# 1. Never launch unconditionally. The loop comes back every few seconds, so
|
|
# an unguarded launch opens a new window every few seconds.
|
|
# 2. Never exit. `org.gnome.Kiosk.Script.service` has
|
|
# `OnSuccess=gnome-session-shutdown.target`, so leaving this script logs
|
|
# the kiosk out and the screen goes back to the GDM greeter.
|
|
#
|
|
# So: poll, (re)launch only when firefox is gone, and keep the loop alive.
|
|
|
|
# Source the per-client config FIRST, then derive everything from it, so the
|
|
# payload file can stay byte-identical on every client and the kiosk.conf under
|
|
# ~/.config/mirror is the only thing that differs. Deriving before the source
|
|
# is a real trap: the script silently runs on the built-in default URL forever.
|
|
CONF="${MIRROR_KIOSK_CONF:-$HOME/.config/mirror/kiosk.conf}"
|
|
if [ -r "$CONF" ]; then
|
|
# shellcheck source=/dev/null
|
|
. "$CONF"
|
|
fi
|
|
|
|
URL="${MIRROR_KIOSK_URL:-https://mirror.reeseapps.com/watch}"
|
|
PROFILE="${MIRROR_KIOSK_PROFILE:-$HOME/.mirror-kiosk}"
|
|
LOG="${MIRROR_KIOSK_LOG:-${XDG_STATE_HOME:-$HOME/.local/state}/mirror-kiosk.log}"
|
|
POLL="${MIRROR_KIOSK_POLL:-5}"
|
|
|
|
log() {
|
|
[ -n "$LOG" ] || return 0
|
|
# Cap the log: this script runs forever on a machine nobody logs into.
|
|
if [ -f "$LOG" ] && [ "$(stat -c %s "$LOG" 2>/dev/null || echo 0)" -gt 1048576 ]; then
|
|
tail -c 65536 "$LOG" >"$LOG.tmp" 2>/dev/null && mv -f "$LOG.tmp" "$LOG" 2>/dev/null
|
|
fi
|
|
printf '%s %s\n' "$(date '+%Y-%m-%dT%H:%M:%S%z' 2>/dev/null || echo -)" "$*" >>"$LOG" 2>/dev/null || :
|
|
}
|
|
|
|
# Keep the screen on. This has to happen here, inside the session, and not at
|
|
# install time: gsettings only commits when it can reach a D-Bus session bus,
|
|
# so `sudo -u kiosk gsettings set ...` over SSH warns "Cannot autolaunch D-Bus
|
|
# without X11" and silently leaves the default. It also cannot go in
|
|
# /etc/dconf/db/local.d, because /usr/bin/gnome-kiosk sets
|
|
# DCONF_PROFILE=gnomekiosk and that profile is `user-db:user` plus the shipped
|
|
# compiled defaults — it never reads a system db.
|
|
#
|
|
# $XDG_RUNTIME_DIR is per-login, so this runs once per kiosk start and still
|
|
# re-applies if someone changes the setting by hand.
|
|
GSETTINGS_STAMP="${XDG_RUNTIME_DIR:-/tmp}/mirror-kiosk-gsettings.done"
|
|
if [ ! -f "$GSETTINGS_STAMP" ]; then
|
|
gsettings set org.gnome.desktop.session idle-delay 0 >/dev/null 2>&1
|
|
gsettings set org.gnome.desktop.screensaver lock-enabled false >/dev/null 2>&1
|
|
gsettings set org.gnome.desktop.interface enable-animations false >/dev/null 2>&1
|
|
log "applied idle/lock gsettings"
|
|
: >"$GSETTINGS_STAMP" 2>/dev/null || :
|
|
fi
|
|
|
|
if pgrep -u "$(id -u)" -x firefox >/dev/null 2>&1; then
|
|
# Up already. Nothing to do but check again in a moment.
|
|
:
|
|
elif command -v curl >/dev/null 2>&1 && ! curl -fsSL -m 10 -o /dev/null "$URL" 2>/dev/null; then
|
|
# Don't park a "server not found" page on a wall display: keep polling and
|
|
# load the page the moment the mirror server answers again. This is what
|
|
# covers a reboot where the network has not come up yet.
|
|
log "target not reachable yet: $URL"
|
|
else
|
|
mkdir -p "$PROFILE" 2>/dev/null
|
|
log "launching: firefox --kiosk $URL"
|
|
# --kiosk : fullscreen, no chrome, no exit affordances
|
|
# --profile: our own dir, so the kiosk never collides with another profile
|
|
# lock and never inherits anyone's history
|
|
# `pgrep -x firefox` above can only be false here if a launch failed
|
|
# outright, so a foreground run cannot wedge the loop.
|
|
/usr/bin/firefox --kiosk --no-remote --profile "$PROFILE" "$URL" >>"$LOG" 2>&1
|
|
rc=$?
|
|
log "firefox exited rc=$rc"
|
|
fi
|
|
|
|
sleep "$POLL"
|
|
exec "$0" "$@"
|