69 lines
2.6 KiB
Bash
Executable File
69 lines
2.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Start and stop the Moonlight streaming stack on demand.
|
|
#
|
|
# It is not left running because it costs ~220 MiB of VRAM on the 3060 (sway
|
|
# ~112, Sunshine ~108) and that card also holds the local LLM. With an 11.3 GB
|
|
# model resident on a 12 GB card, 220 MiB is roughly a fifth of the remaining
|
|
# headroom — enough to matter for KV cache growth.
|
|
set -euo pipefail
|
|
|
|
UNIT=sway-headless.service
|
|
IDLE_MINUTES="${STREAM_IDLE_MINUTES:-15}"
|
|
STAMP="${XDG_RUNTIME_DIR:-/tmp}/stream.lastseen"
|
|
|
|
# The TCP ports are only held while a session is being launched; once it is
|
|
# streaming, everything is UDP on unconnected sockets that ss cannot attribute
|
|
# to a peer. A live NVENC session is what shows a stream in progress.
|
|
clients_connected() {
|
|
ss -Htn state established '( sport = :47984 or sport = :47989 or sport = :48010 )' 2>/dev/null | grep -q . && return 0
|
|
local sessions
|
|
sessions=$(nvidia-smi --query-gpu=encoder.stats.sessionCount --format=csv,noheader,nounits 2>/dev/null | head -n1)
|
|
(( ${sessions:-0} > 0 ))
|
|
}
|
|
|
|
vram() {
|
|
local used total
|
|
read -r used total < <(nvidia-smi --query-gpu=memory.used,memory.total \
|
|
--format=csv,noheader,nounits 2>/dev/null | tr -d ',')
|
|
printf '%s MiB used of %s, %s free' "$used" "$total" "$((total - used))"
|
|
}
|
|
|
|
case "${1:-status}" in
|
|
on|start)
|
|
systemctl --user start "$UNIT"
|
|
sleep 6
|
|
date +%s > "$STAMP"
|
|
printf 'streaming up — pair or connect at https://%s:47990\n' "$(uname -n)"
|
|
printf 'GPU: %s\n' "$(vram)"
|
|
;;
|
|
off|stop)
|
|
systemctl --user stop "$UNIT"
|
|
sleep 3
|
|
rm -f "$STAMP"
|
|
printf 'streaming down\nGPU: %s\n' "$(vram)"
|
|
;;
|
|
status)
|
|
printf 'compositor: %s\nsunshine: %s\nclients: %s\nGPU: %s\n' \
|
|
"$(systemctl --user is-active "$UNIT")" \
|
|
"$(systemctl --user is-active sunshine.service)" \
|
|
"$(clients_connected && echo connected || echo none)" \
|
|
"$(vram)"
|
|
;;
|
|
--idle-check)
|
|
# Called from sunshine-idle-stop.timer. Releases the GPU when nobody has
|
|
# been connected for IDLE_MINUTES, so a forgotten session does not sit on
|
|
# VRAM the inference stack wants.
|
|
systemctl --user is-active --quiet "$UNIT" || exit 0
|
|
if clients_connected; then date +%s > "$STAMP"; exit 0; fi
|
|
last=$(cat "$STAMP" 2>/dev/null || echo 0)
|
|
if (( last == 0 )); then date +%s > "$STAMP"; exit 0; fi
|
|
if (( ($(date +%s) - last) >= IDLE_MINUTES * 60 )); then
|
|
echo "no Moonlight client for ${IDLE_MINUTES}m; stopping to free the GPU"
|
|
systemctl --user stop "$UNIT"
|
|
rm -f "$STAMP"
|
|
fi
|
|
;;
|
|
*)
|
|
echo "usage: stream [on|off|status]" >&2; exit 2 ;;
|
|
esac
|