Files
screen_cast/docs/PHASES.md
T
fegger 7be8d59d07 feat(network): implement Phase 6 LAN discovery and session signaling
Add mDNS/DNS-SD discovery and JSON session negotiation so two peers on
a LAN connect without hard-coded addresses.

- Discovery (Avahi threaded-poll client): the receiver announces
  _screencast._tcp with its signaling port; senders browse and resolve
  peers. Strict lock ordering (poll lock before state mutex) keeps the
  callbacks deadlock-free; name collisions rename via
  avahi_alternative_service_name.
- Signaling: one JSON object per newline-terminated TCP line. The
  receiver hosts a server (port 5005) and answers session offers with
  its RTP port; senders connect, offer, and stream to the negotiated
  endpoint. WebSocket was deferred: no WS library is installed, the
  skill permits plain TCP, and the wire format is transport-agnostic.
- Dual-stack transports: this machine resolves its own services over
  IPv6, so getaddrinfo now runs AF_UNSPEC and listeners bind IPv6 with
  IPV6_V6ONLY=0 (IPv4 fallback), covering UDP and TCP alike. The
  signaling client shutdown now uses shutdown() so a reader blocked in
  recv() cannot hang the join (a plain close() does not wake it).
- CLI: --discover lists receivers (deduped to one entry per host);
  --send auto-disovers when exactly one receiver is found; --peer
  targets a receiver directly; --signaling-port overrides the default.

Validation: meson test 5/5 (new signaling round-trip test), valgrind
clean. End-to-end over loopback: --discover finds the announced
receiver, a probe negotiated a session and streamed 60 frames over
both IPv4 and IPv6, and the receiver reported stream started. mDNS
resolution was verified against avahi-browse as an independent
reference.
2026-09-07 12:16:34 +02:00

3.4 KiB

Development Phases

This file breaks the project into incremental milestones. Each phase produces a working, testable slice of functionality. Do not start a phase until the previous one is validated.

Phase 1 — Project Skeleton

Goal: configure, compile, and run tests with no real dependencies.

  • Meson build files (meson.build, meson_options.txt).
  • Public module headers with namespace sc.
  • Unit test that exercises a trivial utility function.
  • README.md with build instructions.

Validation: meson setup build && meson compile -C build && meson test -C build.

Phase 2 — Software H.264 Encode / Decode

Goal: encode raw pixel buffers to H.264 and decode them back, purely with FFmpeg software paths.

  • Add libavcodec, libavutil, libswscale dependencies.
  • Implement EncoderFactory::create() and Encoder::encode().
  • Implement DecoderFactory::create() and Decoder::decode().
  • Round-trip test: synthetic RGB frames → H.264 → decoded RGB.

Validation: unit test produces visually/structurally correct round-trip frames.

Phase 3 — PipeWire Screen Capture

Goal: capture the desktop and feed frames into the encoder.

  • Add libpipewire-0.3 dependency.
  • Implement CaptureFactory::create() using the xdg-desktop-portal.
  • Wire CaptureSession::next_frame()Encoder::encode() in a local smoke test that just writes a few encoded frames to disk.

Validation: manual run on a real Linux desktop session produces a valid H.264 bitstream.

Phase 4 — RTP Framing

Goal: packetize NAL units into RTP and depacketize them.

  • Implement RtpHeader and RtpPacket serialize/parse.
  • Add H.264 NAL splitting and FU-A fragmentation.
  • Unit test for serialization, fragmentation, and reassembly.

Validation: unit tests cover single-NAL and fragmented packet paths.

Phase 5 — Local UDP Sender → Receiver Loopback

Goal: send RTP packets over UDP and render the result locally.

  • Implement RtpTransport with ASIO or raw UDP sockets.
  • Wire sender pipeline: capture → encode → RTP → localhost UDP.
  • Wire receiver pipeline: localhost UDP → RTP → decode → renderer.
  • Add SDL2/SDL3 dependency and a minimal Renderer.

Validation: screencast --send and screencast --receive on the same machine show the captured desktop in a window.

Phase 6 — LAN Signaling and Discovery

Goal: two peers on the same LAN can find each other and negotiate a session.

  • Implement mDNS/DNS-SD discovery with Avahi.
  • Implement JSON signaling (newline-delimited JSON over TCP for now; the WebSocket transport is deferred to Phase 7 with its dependency).
  • Extend CLI with --peer and --discover.

Validation: two peers connect without hard-coded IP addresses. Validated end-to-end over loopback: discovery finds the announced receiver, the sender negotiates a session over the signaling channel, and streams to the negotiated endpoint over both IPv4 and IPv6.

Phase 7 — Resilience and Polish

Goal: loss recovery, hardware acceleration, and packaging.

  • NACK / PLI feedback loop.
  • Jitter buffer on the receiver.
  • VAAPI/NVENC hardware encode probes and fallback.
  • Optional GUI target behind meson -Dgui=true.
  • .desktop file, icon, packaging notes.

Validation: sustained streaming under packet loss; hardware accel smoke where available.

Current phase

Phase 7 — Resilience and Polish.