Files
clipbin-desktop/scripts/rig/headless-wayland.sh
T
harry 263e7a964e feat: detect lost sources, stalled writes and low disk space
PipeWire capture keeps its size and last frame after its stream stops, so the
recorder follows the stream state OBS logs. Recording fails when the segment
on disk stops growing (OBS kept counting bytes into a dead muxer and missed a
full disk) and stops while enough space remains to finalise the last segment.
Failures stay visible after the output stops.

Adds a check command that verifies keyframe-aligned segments and a remux
across segment boundaries, and gives the rig desktop audio.
2026-10-08 14:19:57 +02:00

103 lines
3.8 KiB
Bash
Executable File

#!/usr/bin/env bash
# Run a command inside a disposable headless Wayland desktop for capture tests.
#
# scripts/rig/headless-wayland.sh <command> [args...]
#
# Starts a private D-Bus session with PipeWire, WirePlumber, headless Sway and
# xdg-desktop-portal-wlr (auto-selecting the only output), plus a 60 FPS test
# pattern standing in for a game. Everything is torn down when the command exits.
#
# This rig exercises the PipeWire/portal path on a machine without a display.
# It does not replace validation on real hardware (Hyprland, X11, Windows).
set -euo pipefail
if [[ $# -eq 0 ]]; then
echo "usage: $0 <command> [args...]" >&2
exit 2
fi
if [[ -z "${CLIPBIN_RIG_INNER:-}" ]]; then
exec env CLIPBIN_RIG_INNER=1 dbus-run-session -- "$0" "$@"
fi
rig_dir="$(mktemp -d "${TMPDIR:-/tmp}/clipbin-rig.XXXXXX")"
pids=()
cleanup() {
for pid in "${pids[@]}"; do kill "${pid}" 2>/dev/null || true; done
wait 2>/dev/null || true
# The D-Bus-activated document portal mounts a FUSE filesystem here.
fusermount3 -u "${XDG_RUNTIME_DIR}/doc" 2>/dev/null || true
rm -rf "${rig_dir}"
}
trap cleanup EXIT
export XDG_RUNTIME_DIR="${rig_dir}/runtime"
export XDG_CONFIG_HOME="${rig_dir}/config"
export XDG_CURRENT_DESKTOP=sway
export XDG_SESSION_TYPE=wayland
mkdir -p "${XDG_RUNTIME_DIR}" "${XDG_CONFIG_HOME}/xdg-desktop-portal-wlr" "${XDG_CONFIG_HOME}/sway"
chmod 700 "${XDG_RUNTIME_DIR}"
width="${CLIPBIN_RIG_WIDTH:-1920}"
height="${CLIPBIN_RIG_HEIGHT:-1080}"
cat > "${XDG_CONFIG_HOME}/sway/config" <<EOF
output HEADLESS-1 resolution ${width}x${height}@60Hz
default_border none
EOF
cat > "${XDG_CONFIG_HOME}/xdg-desktop-portal-wlr/config" <<EOF
[screencast]
chooser_type=none
output_name=HEADLESS-1
max_fps=60
EOF
wait_for() {
local what="$1" check="$2"
for _ in $(seq 100); do
if eval "${check}"; then return 0; fi
sleep 0.1
done
echo "rig: ${what} did not start; logs in ${rig_dir}" >&2
exit 1
}
pipewire > "${rig_dir}/pipewire.log" 2>&1 & pids+=($!)
wait_for pipewire '[[ -S "${XDG_RUNTIME_DIR}/pipewire-0" ]]'
wireplumber > "${rig_dir}/wireplumber.log" 2>&1 & pids+=($!)
pipewire-pulse > "${rig_dir}/pipewire-pulse.log" 2>&1 & pids+=($!)
wait_for pipewire-pulse '[[ -S "${XDG_RUNTIME_DIR}/pulse/native" ]]'
# No sound card here: route playback to a virtual sink whose monitor OBS
# records as desktop audio.
pactl load-module module-null-sink sink_name=clipbin-rig-sink > /dev/null
pactl set-default-sink clipbin-rig-sink
WLR_BACKENDS=headless WLR_LIBINPUT_NO_DEVICES=1 WLR_HEADLESS_OUTPUTS=1 \
sway --config "${XDG_CONFIG_HOME}/sway/config" > "${rig_dir}/sway.log" 2>&1 & pids+=($!)
wait_for sway 'compgen -G "${XDG_RUNTIME_DIR}/wayland-*" > /dev/null'
WAYLAND_DISPLAY="$(basename "$(compgen -G "${XDG_RUNTIME_DIR}/wayland-*" | grep -v lock | head -1)")"
export WAYLAND_DISPLAY
SWAYSOCK="$(compgen -G "${XDG_RUNTIME_DIR}/sway-ipc.*" | head -1)"
export SWAYSOCK
dbus-update-activation-environment WAYLAND_DISPLAY XDG_CURRENT_DESKTOP XDG_RUNTIME_DIR XDG_CONFIG_HOME SWAYSOCK
/usr/lib/xdg-desktop-portal-wlr > "${rig_dir}/xdpw.log" 2>&1 & pids+=($!)
echo "${pids[-1]}" > "${rig_dir}/xdpw.pid"
/usr/lib/xdg-desktop-portal -r > "${rig_dir}/xdp.log" 2>&1 & pids+=($!)
# A moving 60 FPS picture with a 440 Hz tone, standing in for a game.
SDL_VIDEODRIVER=wayland ffplay -loglevel error -fs -window_title clipbin-test-game \
-f lavfi "testsrc2=size=${width}x${height}:rate=60,format=yuv420p[out0];sine=frequency=440:sample_rate=48000[out1]" \
> "${rig_dir}/game.log" 2>&1 & pids+=($!)
echo "${pids[-1]}" > "${rig_dir}/game.pid"
sleep 1
export CLIPBIN_RIG_DIR="${rig_dir}"
echo "rig: ready (WAYLAND_DISPLAY=${WAYLAND_DISPLAY}, logs in ${rig_dir})" >&2
status=0
"$@" || status=$?
if [[ -n "${CLIPBIN_RIG_KEEP_LOGS:-}" ]]; then
mkdir -p "${CLIPBIN_RIG_KEEP_LOGS}" && cp "${rig_dir}"/*.log "${CLIPBIN_RIG_KEEP_LOGS}/"
fi
exit "${status}"