diff --git a/docs/RUNBOOK.md b/docs/RUNBOOK.md index f7e9bef..ca847b5 100644 --- a/docs/RUNBOOK.md +++ b/docs/RUNBOOK.md @@ -90,6 +90,22 @@ Verified behavior: `systemctl stop` results in a clean exit (success, no restart) and the mDNS announcement is withdrawn — senders stop finding the receiver immediately. +## Headless receiver (no window manager) + +The receiver does not need X11, Wayland, or any window manager: SDL3's +KMSDRM backend renders straight to the kernel display pipeline. This is +the recommended setup for small boards (Raspberry Pi OS **Lite**): + +1. `sudo raspi-config` → System Options → Boot → **Console Autologin**. +2. No desktop may be enabled — a running compositor holds the DRM master + and the receiver cannot take it (the two modes are mutually exclusive). +3. Disable console blanking: append `consoleblank=0` to + `/boot/firmware/cmdline.txt` and reboot. + +A window manager only comes with the desktop-session alternative, where +the receiver runs inside it (uncomment the `Environment=` lines in the +service file as described above). + ## Sender / receiver loopback (Phase 5, manual) Two terminals on the same desktop session: diff --git a/scripts/install-receiver.sh b/scripts/install-receiver.sh index ce7ad6f..4b08cd9 100755 --- a/scripts/install-receiver.sh +++ b/scripts/install-receiver.sh @@ -138,13 +138,17 @@ The receiver is installed and starts automatically at boot. sudo systemctl disable --now screencast-receiver # turn autostart off Notes for small boards (e.g. Pi Zero 2 W): + - No window manager is required: the receiver renders directly to the + kernel display pipeline (SDL KMSDRM). Use Raspberry Pi OS Lite with + Console Autologin (raspi-config) and no desktop enabled — a running + compositor would own the display and the receiver could not start. + - Disable console blanking so the picture never goes dark: add + consoleblank=0 to /boot/firmware/cmdline.txt and reboot. - Decoding is software H.264; expect smooth playback for small streams and a lower frame rate at high resolutions. - Stop the receiver via systemctl (never kill -9; stale mDNS records would break discovery for ~75 minutes). - - The service runs on the headless console via KMSDRM. On a desktop - session instead, edit /etc/systemd/system/screencast-receiver.service: - uncomment the Environment lines and point XDG_RUNTIME_DIR at the - session owner's /run/user/ (see the comments in that file). + - On a desktop session instead, edit the installed service file and + uncomment the Environment lines for XDG_RUNTIME_DIR/WAYLAND_DISPLAY. - avahi-daemon must stay enabled; it is what senders discover. EOF \ No newline at end of file diff --git a/systemd/screencast-receiver.service b/systemd/screencast-receiver.service index d055c40..2e9675f 100644 --- a/systemd/screencast-receiver.service +++ b/systemd/screencast-receiver.service @@ -27,6 +27,11 @@ StartLimitBurst=10 Type=simple User=__SC_RECEIVER_USER__ ExecStart=__SC_RECEIVER_BIN__ --receive +# SDL's KMSDRM backend (headless console) expects a controlling terminal +# for its VT handling; system services have none by default. Harmless in +# desktop mode, where the process never touches the tty. +StandardInput=tty +TTYPath=/dev/tty1 # SIGTERM (systemctl stop) shuts the receiver down gracefully, which # withdraws its mDNS announcement. Never SIGKILL it; the systemd default # KillMode escalates only after the graceful timeout. @@ -43,4 +48,12 @@ PrivateTmp=true #Environment=DISPLAY=:0 [Install] -WantedBy=multi-user.target \ No newline at end of file +WantedBy=multi-user.target + +# Headless console recipe (no window manager needed — SDL renders directly +# to the kernel via KMSDRM): +# * Raspberry Pi OS Lite, no desktop enabled (a running compositor would +# hold the DRM master and the receiver could not take it) +# * raspi-config → System Options → Boot → Console Autologin +# * disable console blanking: add consoleblank=0 to +# /boot/firmware/cmdline.txt \ No newline at end of file