Files
Classroom_Desktop/tests/test-classroom-audio.sh
T
ekklesiaandClaude Opus 5 2ff9d47be9 feat: decide the classroom's audio output from what is plugged in
The room that prompted this had a television on HDMI with working PCM
audio and nothing in the analog jack, and WirePlumber chose analog. A
teacher who corrected it by hand then had to restart the browser before
any sound came out.

The policy is a pure function so it can be tested against that room
rather than against a machine: an unavailable port is not a candidate,
an analog port merely existing is not evidence of a cable, and an
explicit AUDIO_OUTPUT overrides the lot. Twelve cases, the real room
among them.

The daemon follows PipeWire's own event stream rather than polling, and
moves streams that are already playing, which is the part that stops a
teacher having to close and reopen the browser.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-10 08:47:28 -05:00

128 lines
4.6 KiB
Bash
Executable File

#!/bin/bash
set -uo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
PYTHONPATH="$ROOT/lib" python3 - <<'PY'
from classroom_audio import ANALOG_ONLY, AUTO, HDMI, candidates, choose, profile_for
passed = failed = 0
def check(label, condition, detail=""):
global passed, failed
if condition:
print(f" ok {label}")
passed += 1
else:
print(f" FAIL {label}")
if detail:
print(f" {detail}")
failed += 1
def card(name, ports):
return {
"name": name,
"index": 0,
"ports": {
port: {
"availability": availability,
"priority": priority,
"direction": "Output",
"profiles": profiles,
}
for port, availability, priority, profiles in ports
},
}
# The room this policy was written for. A Samsung television on HDMI with
# working PCM audio, and an onboard analog jack with nothing in it that
# reports itself unavailable. WirePlumber chose analog.
THE_ROOM = [card("alsa_card.pci-0000_00_1f.3", [
("analog-output-lineout", "not available", 9900,
["output:analog-stereo", "output:analog-stereo+input:analog-stereo"]),
("hdmi-output-0", "available", 5900,
["output:hdmi-stereo", "output:hdmi-surround"]),
])]
print("1. the classroom that went to analog")
chosen = choose(THE_ROOM, AUTO)
check("auto picks the television, not the empty jack",
chosen and chosen["port"] == "hdmi-output-0",
f"chose {chosen and chosen['port']}")
check("and a stereo output profile for it",
profile_for(chosen) == "output:hdmi-stereo",
f"chose {profile_for(chosen)}")
print("2. an unavailable digital port is not a candidate")
TV_OFF = [card("alsa_card.pci", [
("analog-output-lineout", "available", 9900, ["output:analog-stereo"]),
("hdmi-output-0", "not available", 5900, ["output:hdmi-stereo"]),
])]
chosen = choose(TV_OFF, AUTO)
check("auto falls back to analog with the television off",
chosen and chosen["port"] == "analog-output-lineout",
f"chose {chosen and chosen['port']}")
print("3. availability is not always reported")
UNKNOWN = [card("alsa_card.pci", [
("analog-output-lineout", "", 9900, ["output:analog-stereo"]),
("hdmi-output-0", "", 5900, ["output:hdmi-stereo"]),
])]
chosen = choose(UNKNOWN, AUTO)
check("a silent card still prefers the digital output",
chosen and chosen["port"] == "hdmi-output-0",
f"chose {chosen and chosen['port']}")
print("4. an available analog jack does not outrank a live television")
BOTH = [card("alsa_card.pci", [
("analog-output-lineout", "available", 9900, ["output:analog-stereo"]),
("hdmi-output-0", "available", 5900, ["output:hdmi-stereo"]),
])]
chosen = choose(BOTH, AUTO)
check("auto still picks HDMI when both are connected",
chosen and chosen["port"] == "hdmi-output-0",
f"chose {chosen and chosen['port']}")
print("5. explicit overrides")
check("analog forces the jack even with a live television",
choose(BOTH, ANALOG_ONLY)["port"] == "analog-output-lineout")
check("hdmi forces the television even when it is off",
choose(TV_OFF, HDMI)["port"] == "hdmi-output-0")
check("hdmi still falls back rather than leaving the room silent",
choose([card("alsa_card.pci", [
("analog-output-lineout", "available", 9900, ["output:analog-stereo"]),
])], HDMI)["port"] == "analog-output-lineout")
print("6. two displays")
TWO = [card("alsa_card.pci", [
("hdmi-output-0", "not available", 5900, ["output:hdmi-stereo"]),
("hdmi-output-1", "available", 5800, ["output:hdmi-stereo-extra1"]),
])]
chosen = choose(TWO, AUTO)
check("the one that is switched on wins, whatever its priority",
chosen and chosen["port"] == "hdmi-output-1",
f"chose {chosen and chosen['port']}")
print("7. nothing at all")
check("a machine with no sound card decides nothing rather than crashing",
choose([], AUTO) is None)
check("and a card with only inputs is not an output",
choose([{"name": "c", "index": 0, "ports": {
"analog-input-mic": {"direction": "Input", "availability": "available",
"priority": 100, "profiles": ["input:analog-stereo"]}}}],
AUTO) is None)
print("8. ports that are not outputs of interest are ignored")
check("a bluetooth headset port is not mistaken for a display",
not [item for item in candidates([card("bt", [
("headset-output", "available", 100, ["headset-head-unit"])])])
if item["kind"] == HDMI])
print()
print(f"{passed} passed, {failed} failed")
raise SystemExit(1 if failed else 0)
PY