From 8619df10d53d3cfd478fc79b85e29222a672a090 Mon Sep 17 00:00:00 2001 From: Mollusk Date: Wed, 20 May 2026 16:04:36 -0400 Subject: [PATCH] Add README MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Covers v0.1 status, quick-start (interactive + headless), system deps, build, architecture diagram, design rationale, and known limitations. No README existed before — this fills the gap now that v0.1 is verified. Co-Authored-By: Claude Opus 4.7 --- README.md | 164 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..3337ea5 --- /dev/null +++ b/README.md @@ -0,0 +1,164 @@ +# pixelpass + +P2P screen sharing CLI for Linux. Single binary, hole-punched over +[iroh](https://www.iroh.computer/) — no port forwarding, no signup, no +server-side accounts. Hardware-encoded H.264 + AAC audio, viewed in +mpv or VLC. + +Built for people who just want to show their screen to a friend +without spinning up a Discord call or fighting with NAT. + +## Status + +**v0.1.0** — verified end-to-end on the public internet (LTE relay path, +~2s latency, real carrier-grade NAT) as of 2026-05-20. + +Working: +- Wayland capture via the screencast portal (KDE Plasma 6 confirmed; other + Wayland compositors with the portal should work but are untested) +- VAAPI H.264 encode in GStreamer (RDNA3 confirmed; other VAAPI-capable + GPUs should work) +- Audio capture of the default sink's monitor +- 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 `) + +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) +- VLC client renders the H.264 stream as a green screen — mpv works +- `--repair` (PipeWire orphan cleanup) is a stub + +## Quick start + +### Interactive (recommended) + +```sh +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). + +On the viewer machine: run `pixelpass`, pick "View", paste the ticket, +pick mpv or VLC. The player launches detached and the stream starts. + +### Headless + +```sh +# host: prints a ticket on stdout, waits for a peer +pixelpass + +# viewer: skips the menu +pixelpass +# then run the printed mpv command in another terminal +``` + +## Requirements + +- Linux (Wayland session for now; X11 stubbed) +- A VAAPI-capable GPU and the right driver: + - AMD: `libva-mesa-driver` + - Intel: `intel-media-driver` (modern iGPUs) or `intel-vaapi-driver` (older) + - NVIDIA: `libva-nvidia-driver` (untested) +- `vainfo` from `libva-utils` should list at least one H.264 entrypoint +- GStreamer with these plugin packages installed: + - `gstreamer`, `gst-plugins-base`, `gst-plugins-good`, `gst-plugins-bad`, + `gst-plugins-ugly`, `gst-libav`, `gst-plugin-va`, `gst-plugin-pipewire` +- A player: `mpv` (recommended) or `vlc` +- PipeWire (for screencast portal + audio capture) + +On Arch / CachyOS: + +```sh +sudo pacman -S gstreamer gst-plugins-base gst-plugins-good gst-plugins-bad \ + gst-plugins-ugly gst-libav gst-plugin-va gst-plugin-pipewire \ + libva-utils mpv +# plus your GPU's VAAPI driver +``` + +If the viewer is running on battery, set the CPU governor to performance +or balanced — power-saver can choke even hardware-decoded 1080p H.264. + +## Build + +```sh +cargo build --release +./target/release/pixelpass --help +``` + +`rustc` 1.95+ / edition 2024. + +## How it works + +``` + Host Viewer + ──── ────── + Wayland portal (ashpd) ──> PipeWire fd + │ + ▼ + gst-launch: pipewiresrc -> videorate -> vah264enc -> + h264parse -> mpegtsmux + (audio: pulsesrc .monitor -> + avenc_aac -> aacparse ─┘) + │ stdout + ▼ + tokio HTTP server (in-process, ~30 lines) + │ + ▼ + iroh QUIC bi-stream (ALPN pixelpass/0) ◄══════════► + │ + ▼ + tokio TcpListener + on 127.0.0.1:rand + │ + ▼ + mpv / VLC HTTP client +``` + +The viewer's player connects to a localhost HTTP server, which is +just one end of the iroh tunnel. The host's HTTP server sits on the +other end and streams GStreamer's stdout (an MPEG-TS containing +hardware-encoded H.264 + AAC) through with no demux or remux. + +iroh handles NAT traversal: direct UDP if hole-punching succeeds, +relay path otherwise. Both have been verified end-to-end. + +## Why these choices + +- **iroh over Holesail / dumbpipe / Tailscale**: single Rust dep, no Node + runtime, no signup, no daemon — fits the "one self-contained binary" + goal. +- **GStreamer for capture/encode, not ffmpeg**: stride/format pitfalls + when bridging raw video between processes; one in-process pipeline + sidesteps them. +- **In-process Rust HTTP server, not ffmpeg-as-server**: ffmpeg's + `-listen 1` is one-shot and probe-budget-sensitive; the Rust task is + pure passthrough with no codec assumptions. +- **MPEG-TS over fragmented MP4**: every player on Linux handles it + out of the box. AV1-in-MPEG-TS was tried and is unworkable through + libavformat — if AV1 ever comes back, it has to ride a different + container. +- **VAAPI H.264 over x264**: ~5% of one CPU core instead of ~50% on + the host's hardware. + +## Known limitations and gotchas + +- **VLC shows a green screen** against a stream mpv handles correctly. + Likely a VLC-specific PCR / PMT / alignment expectation; not yet + diagnosed. Use mpv until this is fixed. +- **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. +- **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. + +## License + +MIT OR Apache-2.0, your pick.