mediapi/scripts/mediapi-session.sh

79 lines
2.6 KiB
Bash
Raw Permalink Normal View History

#!/bin/sh
#
# mediapi X session -- the X client launched by xinit from mediapi-mpv.service.
#
# Mirrors every extra HDMI output onto the first, then runs ONE fullscreen mpv.
#
# Why an X server at all (we used to run mpv straight on DRM/KMS for fast boot):
# DRM "master" is exclusive per card. The Pi 4's two HDMI connectors live on a
# single vc4 card, so two independent mpv processes cannot both modeset -- the
# second gets "Failed to acquire DRM master: Permission denied" and shows
# nothing. A single X server is the one DRM master and drives BOTH connectors;
# `xrandr --same-as` clones the first output's framebuffer onto the others, so
# one mpv appears on every screen. See git history for the full diagnosis.
#
set -u
RUNTIME_DIR="${MEDIAPI_RUNTIME_DIR:-/run/mediapi}"
SOCKET="${MEDIAPI_MPV_SOCKET:-$RUNTIME_DIR/mpv.sock}"
# Always-on car display: never blank or DPMS-off.
xset -dpms 2>/dev/null || true
xset s off 2>/dev/null || true
connected() { xrandr --query 2>/dev/null | awk '/ connected/{print $1}'; }
# Cold-boot race: the second HDMI connector may not be probed as "connected"
# when X starts. Wait for connected outputs to appear, then let the set settle
# so a screen that lights up a beat later is still mirrored (bounded so a
# genuinely single-screen setup doesn't hang the boot).
deadline=$(( $(date +%s) + 30 ))
outs="$(connected)"
while [ -z "$outs" ] && [ "$(date +%s)" -lt "$deadline" ]; do
sleep 1
outs="$(connected)"
done
stable=0
settle_end=$(( $(date +%s) + 8 ))
while [ "$(date +%s)" -lt "$settle_end" ]; do
sleep 1
cur="$(connected)"
if [ "$cur" != "$outs" ]; then
outs="$cur"
stable=0
else
stable=$(( stable + 1 ))
[ "$stable" -ge 2 ] && break
fi
done
primary=""
rest=""
for o in $outs; do
if [ -z "$primary" ]; then primary="$o"; else rest="$rest $o"; fi
done
echo "mediapi-session: connected outputs:$outs (primary=${primary:-none})"
for o in $rest; do
echo "mediapi-session: mirroring $o onto $primary"
xrandr --output "$o" --same-as "$primary" || true
done
# Single mpv, on X (so one DRM master drives every mirrored connector). Carries
# audio and the app's IPC socket; the app talks only to this one socket now.
# hwdec=v4l2m2m-copy uses the Pi's hardware H.264/HEVC decoder (falls back to
# software for codecs it can't handle). Roughly a third of the CPU of software
# decoding 1080p -- important for an always-on player in a warm car. The single
# mpv has the HW decoder to itself now, so there's no contention.
exec mpv \
--idle=yes \
--vo=gpu-next \
--gpu-context=x11egl \
--hwdec=v4l2m2m-copy \
--fullscreen \
--no-terminal \
--keep-open=no \
--input-ipc-server="$SOCKET" \
--ao=alsa