Files
screen_cast/docs/PHASES.md
T
fegger d2736b8a94 fix(render): keep the whole SDL lifecycle on the render thread
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.
2026-09-07 11:17:35 +02:00

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.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 WebSocket signaling.
  • Extend CLI with --peer-address or --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.
  • .desktop file, icon, packaging notes.

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

Current phase

Phase 6 — LAN Signaling and Discovery.