First-run host launch now offers a one-time upstream measurement
against speed.cloudflare.com/__up via ureq (~5 MB POST, ~5s). The
result lives at ~/.config/pixelpass/config.toml under [bandwidth]
and feeds the default --max-viewers calculation on subsequent runs.
Sticky semantics for the dialog:
- Unmeasured: first-run prompt (Run / Skip)
- Measured / Skipped: silent — never re-prompts
- Failed: ask again on next launch (Retry / give up → Skipped)
`pixelpass --reconfigure` re-runs the test unconditionally for users
whose connection has changed (new ISP, moved house, etc.).
--max-viewers is now Option<u32>. When unset, host startup loads the
saved measurement, runs recommended_max_viewers(safe_mbps, bitrate),
and surfaces the source in the banner: "max viewers : N (auto: X.X
Mbps measured upstream)" — or user-specified / default fallback.
User verified end-to-end on 2026-05-21 16:54 EDT: first-run dialog,
skip path, run path, --reconfigure refresh, and banner integration
all work as expected.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
One gst capture pipeline now fans out to N concurrent viewers via a
tokio::sync::broadcast<Arc<Vec<u8>>>. The HTTP listener accepts forever;
each accepted connection spawns a sender task draining its own
broadcast::Receiver. Slow consumers see Lagged and skip ahead — MPEG-TS
resyncs at the next keyframe.
Host runtime is now lazy + sticky: a supervisor task owns the capture
handle and viewer count. First viewer triggers capture::spawn; last
viewer triggers shutdown. Subsequent reconnects re-trigger the portal
dialog as expected. --max-viewers (default 2) caps concurrent viewers;
additional connections get a "host is full" refusal and are dropped.
Banner updated to reflect the new lifecycle and viewer cap.
NOT YET RUNTIME-VERIFIED. cargo build is clean and the pipeline-level
smoke test still passes, but the multi-viewer behavior (cap enforcement,
lazy-sticky restart, concurrent fanout) requires manual end-to-end
testing with the portal dialog + multiple mpv instances.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Bare `pixelpass` now opens a dialoguer-driven Host/View menu instead of
going straight to host mode. Host path copies the ticket to the system
clipboard via arboard with silent print-only fallback. View path
prompts for the ticket, then after the local listener binds prompts
mpv-vs-VLC and spawns it detached (setsid + null stdio) so the player
survives pixelpass exiting.
Headless invocations (`pixelpass <ticket>`, `pixelpass --repair`)
unchanged. Per spec at ~/Documents/pixelpass-interactive-mode-spec.md.