Two related gaps on the headless kiosk: no way to restart the wall short
of a full reboot, and no way to see why a stream keeps flapping (the
daemon's stderr goes to sway on tty1, and mpv's stderr was discarded).
Restart in place:
- `rtsp-streamer restart` sends a control-socket command; the daemon
tears down its mpv children and syscall.Exec's the on-disk binary.
Same PID, same parent (sway), same env — keeps WAYLAND_DISPLAY/
SWAYSOCK and comes back up on the new binary, no reboot. Handles the
os.Executable() "(deleted)" sentinel from make install's rename.
- sway config now launches the daemon in a relaunch loop, so a crash (or
the restart) auto-recovers instead of leaving a black screen.
- `make deploy` now does `install` + `restart` instead of restarting
getty@tty1 (which left stale duplicate sessions and forced reboots).
Retrievable logs:
- New internal/logbuf ring; the daemon tees slog output into it and
serves the tail over the socket via `rtsp-streamer logs [-n N]` —
readable over SSH, no file wrangling, no reboot.
- Capture the tail of each mpv's stderr and log its last line when the
process exits, so "mpv exited, will restart" now carries the reason
(connection refused, unsupported codec, 401, ...). This is the
diagnostic for a single tile going unhealthy repeatedly.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Diagnosis: individual tiles flickered when their stream died and mpv
relaunched (confirmed via status: a PID dropping to 0 and coming back).
The restarted window mapped at the video's native size wherever sway
dropped it, and the corrective loop only snapped it into its cell on the
next tick — up to 2s later on the relaxed cadence.
Fix, at the source instead of racing the map:
- Pre-install a per-slot for_window rule (matched on each mpv's unique
window title, anchored so slot-1 never matches slot-10) so sway
positions and sizes the window synchronously the moment it maps.
- Pass --geometry=WxH per tile so mpv opens at the tile size rather
than resizing itself to the video's native size on load.
The placeLoop remains as a corrective backstop for mid-life drift.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Skip stream restarts when a reload resolves to the identical wall
(same URLs, tile geometry, player settings) — saving an unrelated
config edit no longer blanks the screen.
- Replace per-tile placement polling (a swaymsg fork per tile per second,
plus 150ms get_tree polling per tile at startup) with one shared loop:
a single get_tree snapshot per tick, re-placing only drifted windows,
relaxing to a 2s tick once settled.
- Mute streams by default (--no-audio) to skip an audio decoder per
stream; opt back in with player.audio: true.
- Graceful, parallel mpv teardown via cmd.Cancel/WaitDelay, fixing the
double-Wait race between Stop and Supervise and cutting worst-case
layout switches from ~2s x N streams to ~2s total.
- status: probe mpv IPC outside the daemon mutex so a slow probe can't
block layout switches.
- View sync: reuse the Protect session across ticks (re-login only on
expiry) and pick up view_refresh_seconds changes without a restart.
- Health strikes keyed by player, not slot, so they never carry across
layout switches; prune stale entries.
- New `rtsp-streamer reload` CLI; fix dead sort in `layout ls`; back off
on persistent control-socket accept errors; fsync config before the
atomic rename (SD-card power-cut safety); bump IPC client deadline;
gofmt stragglers.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
views ls/dump/import copy a Protect live view (cameras + grid) into a
layout; grid inferred from slot count (asymmetric presets TBD, see
views dump). Imported layouts link back via protect_view.
Daemon re-syncs the active linked view every view_refresh_seconds (0=
off), so Protect-side edits appear on the wall. Needs the controller
password at runtime; off by default keeps the wall credential-free.
Shared viewmap package used by CLI and daemon.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Document the grid+tiles model, mouse/quality editing, git-based deploy
(run as your user, reboot not getty), Pi 4 hwdec/H.265/substream notes,
and the real troubleshooting lessons. Add a Roadmap incl. importing
pre-made UniFi Protect views.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Cameras carry multiple stream URLs (streams: high/medium/low); each
tile picks one via Quality (auto/high/low). Small tiles can pull the
low substream to cut Pi decode load. discover --enable-rtsp takes a
comma list (high,low), enables each channel, records all enabled ones.
TUI: q cycles a tile quality (shown in the tile); discover enables
high+low. Player: --framedrop + low-delay demuxer flags; player.max_fps.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Enable mouse in the Bubble Tea program. In the layout grid editor:
click a cell to assign a camera, or press on a tile and drag to
resize its span (grid-snapped). Click-to-select on the menu/list
screens and the camera picker. Works over SSH; edits the config,
so it never fights the daemon geometry.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add --keepaspect-window=no so mpv stops reshaping its window to the
video aspect (which pushed a 4:3 camera below its tile and hid the
bottom behind the neighbour). Combined with keepaspect=yes the video
is letterboxed to fit the tile for any camera type.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ldflags inject version, commit, and build date; a version subcommand
also reports go version and platform. Ends the which-binary-is-this
guessing after deploys.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Probe mpv-version (always present) instead of time-pos, which live
streams with caching off can report unavailable while playing fine —
that produced false unhealthy verdicts. Also require 3 consecutive
misses (~60s) before force-restarting a hung stream.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
mpv 0.35 rejects --auto-window-resize, which crash-looped every player.
Drop that flag and re-assert each tile geometry on a 1s timer in the
daemon, overriding mpv auto-resize on any mpv version.
Add make install (auto-sudo, native build + copy to /usr/local/bin)
and make deploy (install + restart the kiosk getty unit).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>