The receiver window never appeared on Wayland. Two causes: - The window was created on the main thread while event pumping and presenting ran on the render thread. SDL's Wayland backend requires a window's creation, event processing, drawing, and destruction to happen on one thread; a cross-thread surface simply never maps, with no error reported. The renderer now lives entirely on the render thread, with a condition-variable handshake so ReceiverPipeline:: start() still reports renderer failures and timeouts. - On Wayland a window is invisible until the first render commit, so even a healthy receiver showed nothing while waiting for a stream. The renderer presents one blank frame at init: the window is visible immediately, black until video arrives. Also log 'stream started (WxH)' when the first frame decodes and the first rendering failure, which is what made the remaining debugging observable. Validated headlessly end-to-end: a synthetic solid-color RTP feed drove the real receiver over localhost UDP; the window mapped, reported 'stream started (320x240)', and a grim screenshot of the window region showed the fed color (V=198, SATAVG=74 during the red feed). Phase 5 marked complete in docs/PHASES.md; current phase is now Phase 6.
3.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 WebSocket signaling.
- Extend CLI with
--peer-addressor--discover.
Validation: two machines on the same LAN connect without hard-coded IP addresses.
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 6 — LAN Signaling and Discovery.