5c39662cc2
A gtkmm-4.0 control panel (behind -Dgui=true, default off): refresh shows discovered receivers (grouped and preference-sorted), a bitrate scale, and start/stop that runs the whole session on a worker thread so the interactive portal picker never blocks the UI. The CLI and the GUI now share the new sc_app_core static library holding the pipelines, session orchestration (negotiation + PLI feedback), and a state store. The sender pipeline publishes its state to $XDG_RUNTIME_DIR/screencast/sender.json (session id, receiver, bitrate, pid, start time; stale files detected by pid liveness) and persists the last session for one-click restarts. The new 'screencast waybar' subcommand prints a waybar module line and its --toggle flag stops a running sender gracefully or spawns a detached restart of the last receiver. Waybar on the dev machine is wired: custom/screencast module with click-to-toggle and right-click panel, plus styles, with a timestamped backup of both config files. Both binaries are installed to /usr/local/bin. Validated: waybar output (idle and streaming states with a synthetic state file), GUI launches on the desktop (window observed via hyprctl), meson test 5/5 in both build configurations, formatting clean.
108 lines
4.3 KiB
Markdown
108 lines
4.3 KiB
Markdown
# 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.
|
|
|
|
- [x] Meson build files (`meson.build`, `meson_options.txt`).
|
|
- [x] Public module headers with `namespace sc`.
|
|
- [x] Unit test that exercises a trivial utility function.
|
|
- [x] `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.
|
|
|
|
- [x] Add `libavcodec`, `libavutil`, `libswscale` dependencies.
|
|
- [x] Implement `EncoderFactory::create()` and `Encoder::encode()`.
|
|
- [x] Implement `DecoderFactory::create()` and `Decoder::decode()`.
|
|
- [x] 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.
|
|
|
|
- [x] Add `libpipewire-0.3` dependency.
|
|
- [x] Implement `CaptureFactory::create()` using the xdg-desktop-portal.
|
|
- [x] 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.
|
|
|
|
- [x] Implement `RtpHeader` and `RtpPacket` serialize/parse.
|
|
- [x] Add H.264 NAL splitting and FU-A fragmentation.
|
|
- [x] 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.
|
|
|
|
- [x] Implement `RtpTransport` with ASIO or raw UDP sockets.
|
|
- [x] Wire sender pipeline: capture → encode → RTP → localhost UDP.
|
|
- [x] Wire receiver pipeline: localhost UDP → RTP → decode → renderer.
|
|
- [x] 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.
|
|
|
|
- [x] Implement mDNS/DNS-SD discovery with Avahi.
|
|
- [x] Implement JSON signaling (newline-delimited JSON over TCP for now;
|
|
the WebSocket transport is deferred to Phase 7 with its dependency).
|
|
- [x] Extend CLI with `--peer` and `--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.
|
|
|
|
- [x] PLI keyframe feedback over signaling (receiver asks, sender
|
|
re-encodes a keyframe; validated end-to-end with an induced loss).
|
|
- [x] Jitter/reorder window on the receiver (16 packets / 60 ms).
|
|
- [x] Hardware H.264 decode probe with software fallback (h264_v4l2m2m —
|
|
the Pi's VideoCore path; --swdecode opts out).
|
|
- [x] GTK4 sender GUI behind `meson -Dgui=true` (gtkmm; receiver list,
|
|
bitrate, start/stop) plus a waybar widget (`screencast waybar`,
|
|
click-to-toggle, right-click opens the panel; state shared via
|
|
$XDG_RUNTIME_DIR/screencast/sender.json).
|
|
- [ ] 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.
|