fegger 67eee23137 fix(app): try every discovered receiver address in preference order
The sender used the first address a receiver resolved to, which on
the Pi was a 6to4 2002:: address that is unreachable between LAN
peers (the router runs a tunnel) — signaling could not connect, no
RTP ever flowed, and the receiver showed a black screen with an
empty journal while the user's earlier discovery looked healthy.

Discovery now keeps all of a receiver's addresses and the sender
tries them sorted by reachability preference (private IPv4, public
IPv4, ULA, global IPv6, 6to4, link-local) until the signaling
connection succeeds; --discover lists them in the same order.
Verification against the real Pi: it lists both addresses with
192.168.178.131 first, the probe negotiated over it, and 100
synthetic frames streamed to the negotiated RTP port.
2026-09-07 14:07:40 +02:00

screen_cast

A native Linux peer-to-peer screencast application.

  • Send your desktop or a window to another Linux machine.
  • Receive a stream and render it in a window.
  • Discover receivers on the LAN via mDNS/Avahi; negotiate sessions with JSON signaling; stream H.264 over RTP/UDP.

Built with C++20, Meson, PipeWire, FFmpeg, and SDL3.

Quick start

Requirements:

  • C++20 compiler with <format> (GCC 13+, Clang 18+)
  • Meson >= 0.63, Ninja
  • FFmpeg development packages (libavcodec, libavutil, libswscale)
  • SDL3 development package (sdl3)
  • nlohmann JSON (nlohmann_json) and Avahi client (avahi-client)
  • For the sender only: PipeWire dev (libpipewire-0.3) and libportal

Build and run tests:

meson setup build
meson compile -C build
meson test -C build --print-errorlogs

Stream between two machines:

screencast --receive        # machine A: announces itself, opens a window
screencast --send          # machine B: discovers A, negotiates, streams

See docs/RUNBOOK.md for all modes, flags, and validation procedures.

Receiver on a small ARM board (e.g. Raspberry Pi Zero 2 W)

The receiver does not need the sender's PipeWire/portal capture stack. On the board, run:

sudo ./scripts/install-receiver.sh
screencast --receive

The script installs the dependencies, builds a receiver-only binary (-Dsender=false), runs the test suite, and installs to /usr/local/bin (override with SC_RECEIVER_INSTALL_DIR). It needs Raspberry Pi OS Trixie or newer (GCC 13+ for C++20 <format>), builds SDL3 from source when the distribution does not package it, and enables avahi-daemon. It also installs and enables a systemd service so the receiver starts at boot — systemctl status screencast-receiver to check on it.

Performance note: decoding is software H.264; on very small boards expect smooth playback for modest resolutions and reduced frame rates at high resolutions. Hardware decode is planned for Phase 7. On a headless console the receiver runs fullscreen automatically with aspect-preserving letterboxing.

Architecture

See docs/ARCHITECTURE.md for module boundaries and design rules.

Roadmap

Development is split into phases in docs/PHASES.md.

Current phase: Phase 7 — Resilience and polish.

License

MIT — see LICENSE (to be added).

S
Description
No description provided
Readme 1.2 MiB
Languages
C++ 60.6%
Swift 18%
Kotlin 15.2%
Shell 3.9%
Meson 2%
Other 0.2%