Was der Server sendet, läuft. Wer anhält, fällt aus dem Gleichlauf und müsste den Rückstand hinterher mit erhöhtem Tempo aufholen. Statt der Browser-Steuerung gibt es jetzt eine eigene Leiste: Lautstärke, Stumm und Vollbild. Pausieren, Spulen und Geschwindigkeit fehlen darin. Abgedeckt sind alle Wege zum Anhalten, weil jeder davon ein pause-Ereignis auslöst: Rechtsklick-Menü, Bild-in-Bild, Medientasten der Tastatur. Die Leertaste wird zusätzlich abgefangen, sie käme sonst dem Video zuvor. Der Ton startet stumm, sonst verweigert der Browser die automatische Wiedergabe. Ein Klick auf "Ton einschalten" gilt als Geste und schaltet ihn frei. Beim Tonweg zwei Fehler behoben: - Der Loopback zum Mithören nahm das Ende der aufrufenden Shell mit. Mitten im Film hörte dann niemand mehr etwas. setsid löst ihn davon. - Der Lautstärkeregler fasst seit der Umstellung die neue Senke an, nicht mehr das Ausgabegerät. Stand das auf halber Kraft, war bei "voll aufgedreht" Schluss bei der Hälfte. Jetzt geht das Gerät auf Anschlag und die Senke übernimmt den gewohnten Pegel. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013XVnRop5c3or3B8xE2hpgZ
110 lines
3.7 KiB
Bash
Executable File
110 lines
3.7 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Legt den Tonweg für den Stream an und räumt ihn wieder ab.
|
|
#
|
|
# Bluetooth-Ausgaben haben eine eigene, ungenaue Uhr und laufen mit 44,1 kHz.
|
|
# Nimmt OBS deren Monitor auf, wandert der Ton mit der Zeit vom Bild weg —
|
|
# nach fünf Minuten sind es Sekunden. Eine Null-Senke hängt an der Systemuhr
|
|
# und liefert 48 kHz, also genau das, was der Encoder erwartet.
|
|
#
|
|
# ton.sh auf Senke anlegen, zum Standard machen, Mithören einrichten
|
|
# ton.sh ab Standard zurückstellen, Senke entfernen
|
|
set -euo pipefail
|
|
|
|
SENKE="filmabend"
|
|
MERKER="/tmp/filmabend-vorheriger-ausgang"
|
|
|
|
# wpctl zeigt Beschreibungen, keine Knotennamen — die ID kommt aus pw-dump
|
|
id_von() {
|
|
pw-dump | python3 -c "
|
|
import json, sys
|
|
name = sys.argv[1]
|
|
for o in json.load(sys.stdin):
|
|
if o.get('info', {}).get('props', {}).get('node.name') == name:
|
|
print(o['id']); break
|
|
" "$1"
|
|
}
|
|
|
|
lautstaerke_von() {
|
|
wpctl get-volume "$1" 2>/dev/null | awk '{print $2}'
|
|
}
|
|
|
|
name_des_standards() {
|
|
wpctl inspect @DEFAULT_AUDIO_SINK@ 2>/dev/null |
|
|
sed -n 's/.*node\.name = "\([^"]*\)".*/\1/p' | head -1
|
|
}
|
|
|
|
case "${1:-auf}" in
|
|
auf)
|
|
# Zuerst lesen: WirePlumber macht eine frisch angelegte Senke sofort
|
|
# zum Standard, danach wäre der alte Ausgang nicht mehr zu erfahren
|
|
VORHER="$(name_des_standards)"
|
|
[ -n "$VORHER" ] && [ "$VORHER" != "$SENKE" ] && echo "$VORHER" > "$MERKER"
|
|
ZURUECK="$(cat "$MERKER" 2>/dev/null || true)"
|
|
|
|
if [ -z "$ZURUECK" ]; then
|
|
echo "Kein voriger Ausgang bekannt — bitte einmal 'scripts/ton.sh ab' laufen lassen."
|
|
exit 1
|
|
fi
|
|
|
|
if [ -z "$(id_von "$SENKE")" ]; then
|
|
pw-cli create-node adapter "{
|
|
factory.name=support.null-audio-sink
|
|
node.name=$SENKE node.description=Filmabend
|
|
media.class=Audio/Sink object.linger=true
|
|
audio.rate=48000 audio.position=[FL,FR]
|
|
}" > /dev/null
|
|
sleep 1
|
|
fi
|
|
|
|
# Damit du selbst weiter über dein gewohntes Gerät hörst.
|
|
# setsid, sonst nimmt der Prozess das Ende dieser Shell mit und du
|
|
# hörst mitten im Film nichts mehr.
|
|
if ! pgrep -f "node.name=filmabend-mithoeren" > /dev/null; then
|
|
setsid pw-loopback -m '[FL FR]' \
|
|
--capture-props="stream.capture.sink=true target.object=$SENKE node.name=filmabend-mithoeren" \
|
|
--playback-props="target.object=$ZURUECK node.name=filmabend-ausgabe" \
|
|
> /dev/null 2>&1 < /dev/null &
|
|
sleep 1
|
|
fi
|
|
|
|
# Dein Lautstärkeregler fasst ab jetzt die neue Senke an, nicht mehr das
|
|
# Ausgabegerät. Stünde das weiter auf halber Kraft, wäre bei "voll
|
|
# aufgedreht" Schluss bei der Hälfte. Also: Gerät auf Anschlag, und die
|
|
# neue Senke übernimmt den Pegel, den du gewohnt bist.
|
|
ZIEL_ID="$(id_von "$ZURUECK")"
|
|
if [ -n "$ZIEL_ID" ]; then
|
|
ALTER_PEGEL="$(lautstaerke_von "$ZIEL_ID")"
|
|
[ -n "$ALTER_PEGEL" ] && echo "$ALTER_PEGEL" > "$MERKER.pegel"
|
|
wpctl set-volume "$ZIEL_ID" 1.0
|
|
[ -n "$ALTER_PEGEL" ] && wpctl set-volume "$(id_von "$SENKE")" "$ALTER_PEGEL"
|
|
fi
|
|
|
|
# Ab jetzt landet aller Ton in der Senke — und von dort bei dir und im Stream
|
|
wpctl set-default "$(id_von "$SENKE")"
|
|
echo "Ton läuft über die Senke Filmabend, du hörst weiter über $ZURUECK."
|
|
;;
|
|
|
|
ab)
|
|
ZURUECK="$(cat "$MERKER" 2>/dev/null || true)"
|
|
if [ -n "$ZURUECK" ]; then
|
|
ID="$(id_von "$ZURUECK")"
|
|
if [ -n "$ID" ]; then
|
|
wpctl set-default "$ID"
|
|
PEGEL="$(cat "$MERKER.pegel" 2>/dev/null || true)"
|
|
[ -n "$PEGEL" ] && wpctl set-volume "$ID" "$PEGEL"
|
|
fi
|
|
fi
|
|
rm -f "$MERKER.pegel"
|
|
pkill -f "node.name=filmabend-mithoeren" 2>/dev/null || true
|
|
ID="$(id_von "$SENKE")"
|
|
[ -n "$ID" ] && pw-cli destroy "$ID" > /dev/null 2>&1 || true
|
|
rm -f "$MERKER"
|
|
echo "Ton zurück auf ${ZURUECK:-dein Gerät}."
|
|
;;
|
|
|
|
*)
|
|
echo "Aufruf: ton.sh auf|ab"
|
|
exit 1
|
|
;;
|
|
esac
|