4.2 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 polish.
- PLI keyframe feedback over signaling (receiver asks, sender re-encodes a keyframe; validated end-to-end with an induced loss).
- Jitter/reorder window on the receiver (16 packets / 60 ms).
- Hardware H.264 decode probe with software fallback (h264_v4l2m2m — the Pi's VideoCore path; --swdecode opts out).
- GTK4 sender GUI behind
meson -Dgui=true+ a waybar widget (requested; plan approved scope: sender panel, state file,screencast waybarsubcommand). - VAAPI hardware encode probe on the sender (deferred: software encode is not the bottleneck).
- Deferred: .desktop file, packaging.
Validation: sustained streaming under packet loss; hardware accel smoke where available. PLI + jitter validated on the desktop (induced-loss probe); hardware decode validated as clean-fallback on the desktop, hardware path pending a run on the Pi.
Current phase
Phase 7 — Resilience and Polish.