archy/image-recipe/configs/archipelago-audio-router.service
archipelago 8a450bb8f8 feat(audio): HDMI audio works out of the box — pipewire in ISO + router daemon + ELD boot-race heal
Root cause of silent HDMI on kiosk TVs (framework-pt, LG TV):
1) fresh ISOs installed NO audio stack even though the kiosk launcher
   expects PipeWire-Pulse — add pipewire/pipewire-pulse/pipewire-alsa/
   wireplumber/alsa-utils to the rootfs and put the archipelago user in
   'audio' (linger user manager gets no logind seat ACLs on /dev/snd);
2) the kiosk's boot-time Xorg modeset races the i915→HDA audio-component
   bind, the ELD notify is lost, and every HDMI profile stays
   'available: no' forever. Verified live: one off/on modeset re-delivers
   the ELD and WirePlumber immediately switches to HDMI.

New archipelago-audio-router daemon (same splice-from-configs pattern as
the kiosk, ISO + include_str! self-heal): routes the card to the best
available HDMI profile, keeps the default sink on it, migrates live
streams on hot-plug, unmutes (HDMI forced 100% — the TV owns volume), and
re-modesets a connected external output once when no ELD reports a
monitor. bootstrap::ensure_audio_stack() installs packages + router on
already-deployed kiosk nodes via OTA (apt through systemd-run — the
service sandbox keeps /usr and dpkg read-only). main.rs also spawns the
pine satellite keeper.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 15:28:47 -04:00

21 lines
688 B
Desktop File

[Unit]
Description=Archipelago audio router (HDMI hot-plug follow + ELD boot-race heal)
# Talks to the archipelago user's PipeWire (running under the lingering user
# manager) and pokes the kiosk X server for the ELD re-modeset nudge; start
# after both are plausibly up. Missing/inactive units here are harmless.
After=user@1000.service archipelago-kiosk.service
Wants=user@1000.service
ConditionPathExists=/usr/local/bin/archipelago-audio-router
[Service]
Type=simple
User=archipelago
ExecStart=/usr/local/bin/archipelago-audio-router
Restart=always
RestartSec=10
# Polls a few pactl calls every 5s — keep it invisible to the scheduler.
Nice=10
[Install]
WantedBy=multi-user.target