From f939441e315c2ae4247eaaee9469fbdf428fc9d1 Mon Sep 17 00:00:00 2001 From: Mollusk Date: Thu, 21 May 2026 17:00:58 -0400 Subject: [PATCH] README: document multi-viewer + bandwidth pre-flight Updates the status section to move multi-viewer out of "not yet working", adds a Configuration section pointing at the new TOML config at ~/.config/pixelpass/config.toml, and a Multi-viewer section covering the lazy-sticky lifecycle, the --max-viewers cap, the bandwidth-bitrate tradeoff, and how to fit more viewers by dropping --bitrate. Known-limitations section gains "late joiners see ~2 s of garbage" (expected behavior) and drops the now-stale "single viewer per host" line. Co-Authored-By: Claude Opus 4.7 --- README.md | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 51 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 09ea0d3..e523d71 100644 --- a/README.md +++ b/README.md @@ -22,11 +22,15 @@ Working: - iroh QUIC bi-stream tunnel, direct-UDP and relay paths both verified - Interactive Host/View menu with clipboard auto-copy and mpv/VLC picker - Headless mode for scripts (`pixelpass `) +- Multi-viewer fanout (default 2, configurable via `--max-viewers`; + shared gst pipeline, one broadcast channel per host) +- First-run upstream bandwidth pre-flight, persisted to + `~/.config/pixelpass/config.toml` and used to auto-size the default + viewer cap Not yet working: - X11 capture (stubbed, returns an error) - Per-app audio routing (`--app ` is a flag stub) -- Multi-viewer (single viewer per host by design right now) - `--repair` (PipeWire orphan cleanup) is a stub ## Quick start @@ -39,7 +43,14 @@ pixelpass On the host machine: pick "Host", share a monitor via the portal dialog, the ticket lands on your clipboard. Send it to your viewer however you -like (chat, email, paste in a note). +like (chat, email, paste in a note). The same ticket works for multiple +viewers up to your `--max-viewers` cap. + +The very first host launch offers a one-time upstream bandwidth test +(~5 s, ~5 MB to Cloudflare's open speed-test endpoint) so it can pick +a sensible default for the viewer cap. You can skip it and a +conservative default (2 viewers) is used; re-run it later with +`pixelpass --reconfigure`. On the viewer machine: run `pixelpass`, pick "View", paste the ticket, pick mpv or VLC. The player launches detached and the stream starts. @@ -154,6 +165,42 @@ relay path otherwise. Both have been verified end-to-end. - **VAAPI H.264 over x264**: ~5% of one CPU core instead of ~50% on the host's hardware. +## Configuration + +`pixelpass` keeps a small TOML config at `~/.config/pixelpass/config.toml` +(or the XDG equivalent). Right now it only stores the result of the +bandwidth pre-flight: + +```toml +[bandwidth] +status = "measured" # measured | skipped | failed | unmeasured +upstream_mbps = 8.78 # safe estimate (raw * 0.8) +measured_at = "2026-05-21T20:41:16Z" +``` + +- `pixelpass --reconfigure` re-runs the test (e.g. after an ISP change). +- Deleting the file resets pixelpass to first-run state. +- Skip is sticky — once you skip the test, pixelpass won't ask again + unless you reconfigure. + +## Multi-viewer + +One gst capture pipeline fans out to N concurrent viewers via a +`tokio::sync::broadcast` channel. The same ticket is reusable: as long +as a viewer is connected, capture stays alive; when the last one +leaves, the pipeline tears down and the portal stops streaming. A new +viewer connecting after that re-triggers the portal dialog. + +Capacity is bounded by upstream bandwidth (each viewer is its own +encrypted egress). The default cap comes from the bandwidth pre-flight +result; `--max-viewers ` overrides it. When the cap is hit, +additional connections are politely refused with a "host is full" +message and the host keeps running. + +For more viewers, drop the per-viewer bitrate: e.g. `pixelpass +--bitrate 2500 --max-viewers 4` fits four 2.5 Mbps streams in roughly +12 Mbps of upstream. + ## Known limitations and gotchas - **VLC needs `vlc-plugin-dvb` and `vlc-plugin-ffmpeg`** on Arch-family @@ -164,9 +211,8 @@ relay path otherwise. Both have been verified end-to-end. - **Audio echo** if the host plays the stream through speakers and captures system audio — expected, the mic / monitor picks up the playback. Headphones bypass it. -- **Single viewer per host** by design right now. Restarting the player - against the same URL fails with "connection refused"; restart the - viewer too. +- **Late joiners see ~2 s of garbage** before the next keyframe lets + their decoder lock. Expected behavior, not a bug. - **VAAPI driver must be package-tracked**, not an orphaned `.so` on disk. mpv's `--hwdec=auto` silently falls back to software decode otherwise, which then chokes on a low-power viewer.