6e68300d05
Ship systemd/screencast-receiver.service, a template the install script substitutes (binary path, run user) and enables so the receiver starts at boot after the network and avahi-daemon, with restart-on-failure and a raised start limit for slow-booting boards. SIGTERM gives the graceful shutdown that withdraws the mDNS announcement — systemctl stop never triggers the stale-record trap that kill -9 does. Headless consoles render via KMSDRM (the script adds the run user to video/render/input); desktop autologin sessions uncomment two documented Environment lines. The install script gains SC_RECEIVER_SERVICE=0 to opt out. Validated: systemd-analyze verify on the substituted unit (only the expected missing /usr/local/bin path on this dev machine), and a live lifecycle test as a user unit: the service-managed receiver announced itself (--discover found it), systemctl stop produced a clean exit (Result=success, no restart) and the mDNS announcement was withdrawn immediately.
150 lines
6.0 KiB
Bash
Executable File
150 lines
6.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#
|
|
# install-receiver.sh — build and install the screencast RECEIVER on a
|
|
# small ARM board (e.g. a Raspberry Pi Zero 2 W).
|
|
#
|
|
# Why a separate script: the sender pulls in PipeWire and the
|
|
# xdg-desktop-portal capture stack, which a headless receiver board neither
|
|
# has nor needs. This script configures the build with -Dsender=false so
|
|
# only the receiver binary is compiled.
|
|
#
|
|
# Usage (from the repository root, on the target machine):
|
|
#
|
|
# sudo ./scripts/install-receiver.sh
|
|
#
|
|
# Environment overrides:
|
|
# SC_RECEIVER_INSTALL_DIR install target (default /usr/local/bin)
|
|
# SC_RECEIVER_SKIP_TESTS set to 1 to skip the test suite (faster install)
|
|
# SC_RECEIVER_SERVICE set to 0 to skip the systemd service setup
|
|
#
|
|
# Requirements:
|
|
# - Debian/Raspberry Pi OS (apt) with GCC 13 or newer (the code uses
|
|
# C++20 <format>; Raspberry Pi OS Trixie or newer ships a suitable GCC)
|
|
# - a running avahi-daemon (installed and enabled by this script)
|
|
# - a graphical session or KMS console for the receiver window
|
|
|
|
set -euo pipefail
|
|
|
|
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
BUILD_DIR="${REPO_ROOT}/build-receiver"
|
|
INSTALL_DIR="${SC_RECEIVER_INSTALL_DIR:-/usr/local/bin}"
|
|
SKIP_TESTS="${SC_RECEIVER_SKIP_TESTS:-0}"
|
|
ENABLE_SERVICE="${SC_RECEIVER_SERVICE:-1}"
|
|
|
|
log() { printf '\n=== %s\n' "$*"; }
|
|
die() { printf 'install-receiver: error: %s\n' "$*" >&2; exit 1; }
|
|
|
|
[ "$(id -u)" = 0 ] || die "run with sudo (installs to ${INSTALL_DIR})"
|
|
[ -f "${REPO_ROOT}/meson.build" ] || die "run from the screen_cast repository"
|
|
command -v apt-get >/dev/null 2>&1 || die "this script supports apt-based systems only"
|
|
|
|
export DEBIAN_FRONTEND=noninteractive
|
|
|
|
# --- build and runtime dependencies -----------------------------------------
|
|
log "installing build and runtime dependencies (this may take a while)"
|
|
apt-get update -qq || apt-get update
|
|
apt-get install -y --no-install-recommends \
|
|
build-essential \
|
|
meson \
|
|
ninja-build \
|
|
pkg-config \
|
|
libavcodec-dev \
|
|
libavutil-dev \
|
|
libswscale-dev \
|
|
nlohmann-json3-dev \
|
|
libavahi-client-dev \
|
|
avahi-daemon \
|
|
ca-certificates
|
|
|
|
# The receiver renders with SDL3. Older releases do not package it; build a
|
|
# minimal SDL3 from source in that case.
|
|
if ! apt-get install -y --no-install-recommends libsdl3-dev; then
|
|
log "libsdl3-dev is not packaged; building SDL3 from source (15-30 min on small boards)"
|
|
apt-get install -y --no-install-recommends cmake git
|
|
SDL_DIR="$(mktemp -d)"
|
|
trap 'rm -rf "${SDL_DIR}"' EXIT
|
|
git clone --depth 1 --branch release-3.2.x \
|
|
https://github.com/libsdl-org/SDL.git "${SDL_DIR}/SDL"
|
|
cmake -S "${SDL_DIR}/SDL" -B "${SDL_DIR}/build" \
|
|
-DCMAKE_BUILD_TYPE=Release \
|
|
-DSDL_TESTS=OFF \
|
|
-DSDL_INSTALL_DOCS=OFF \
|
|
-DSDL_EXAMPLES=OFF
|
|
cmake --build "${SDL_DIR}/build" --parallel "$(nproc)"
|
|
cmake --install "${SDL_DIR}/build"
|
|
fi
|
|
|
|
# --- compiler sanity check ---------------------------------------------------
|
|
log "checking the compiler for C++20 <format> support"
|
|
if ! printf '#include <format>\nint main() { return 0; }\n' |
|
|
g++ -std=c++20 -x c++ - -o /dev/null 2>/dev/null; then
|
|
die "g++ lacks C++20 <format>; install GCC 13 or newer (Raspberry Pi OS \
|
|
Trixie or newer ships one). Aborting before a long build."
|
|
fi
|
|
|
|
# --- build the receiver ------------------------------------------------------
|
|
log "configuring a receiver-only build in ${BUILD_DIR}"
|
|
rm -rf "${BUILD_DIR}"
|
|
meson setup "${BUILD_DIR}" "${REPO_ROOT}" -Dsender=false
|
|
|
|
log "compiling (this takes a few minutes on small boards)"
|
|
meson compile -C "${BUILD_DIR}"
|
|
|
|
if [ "${SKIP_TESTS}" != "1" ]; then
|
|
log "running the test suite"
|
|
meson test -C "${BUILD_DIR}" --print-errorlogs
|
|
fi
|
|
|
|
# --- install -----------------------------------------------------------------
|
|
log "installing the receiver to ${INSTALL_DIR}"
|
|
install -m 755 "${BUILD_DIR}/src/app/screencast" "${INSTALL_DIR}/screencast"
|
|
|
|
systemctl enable --now avahi-daemon 2>/dev/null || true
|
|
|
|
# --- systemd autostart --------------------------------------------------------
|
|
if [ "${ENABLE_SERVICE}" = "1" ] && command -v systemctl >/dev/null 2>&1; then
|
|
log "installing the systemd service (autostart on boot)"
|
|
RUN_USER="${SUDO_USER:-root}"
|
|
|
|
# Headless KMSDRM rendering needs device access; skip groups that do
|
|
# not exist on this system.
|
|
if [ "${RUN_USER}" != "root" ] && id "${RUN_USER}" >/dev/null 2>&1; then
|
|
for group in video render input; do
|
|
if getent group "${group}" >/dev/null 2>&1; then
|
|
usermod -aG "${group}" "${RUN_USER}" || true
|
|
fi
|
|
done
|
|
fi
|
|
|
|
sed -e "s|__SC_RECEIVER_BIN__|${INSTALL_DIR}/screencast|g" \
|
|
-e "s|__SC_RECEIVER_USER__|${RUN_USER}|g" \
|
|
"${REPO_ROOT}/systemd/screencast-receiver.service" \
|
|
> /etc/systemd/system/screencast-receiver.service
|
|
chmod 644 /etc/systemd/system/screencast-receiver.service
|
|
systemctl daemon-reload
|
|
systemctl enable --now screencast-receiver.service
|
|
else
|
|
log "skipping the systemd service (disabled or systemd not available)"
|
|
fi
|
|
|
|
log "done."
|
|
cat <<'EOF'
|
|
|
|
The receiver is installed and starts automatically at boot.
|
|
|
|
systemctl status screencast-receiver # is it running?
|
|
journalctl -u screencast-receiver -f # follow its logs
|
|
sudo systemctl stop screencast-receiver # stop gracefully (Ctrl-C like)
|
|
sudo systemctl disable --now screencast-receiver # turn autostart off
|
|
|
|
Notes for small boards (e.g. Pi Zero 2 W):
|
|
- 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/<uid> (see the comments in that file).
|
|
- avahi-daemon must stay enabled; it is what senders discover.
|
|
EOF |