The full chain — mDNS discovery, signaling negotiation, RTP over Wi-Fi, software H.264 decode, and fullscreen KMSDRM letterboxed rendering — is confirmed working on a real two-machine setup (desktop -> Raspberry Pi Zero 2 W headless receiver). The probe gradient appeared on the Pi's display.
3.6 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.mdwith 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,libswscaledependencies. - Implement
EncoderFactory::create()andEncoder::encode(). - Implement
DecoderFactory::create()andDecoder::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.3dependency. - 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
RtpHeaderandRtpPacketserialize/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
RtpTransportwith 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
--peerand--discover.
Validation: two peers connect without hard-coded IP addresses. Validated over loopback AND on real two-machine hardware: a Raspberry Pi Zero 2 W (Wi-Fi, headless KMSDRM, systemd autostart) was discovered, negotiated with, and streamed to from the desktop; the receiver rendered a synthetic feed fullscreen on its display. On that network the LAN's 6to4 addresses are unreachable between peers, so senders try all discovered addresses in reachability order (private IPv4 first).
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. .desktopfile, icon, packaging notes.
Validation: sustained streaming under packet loss; hardware accel smoke where available.
Current phase
Phase 7 — Resilience and Polish.