Skip to content

feat: add /player/output to reopen audio output live - #336

Open
palchrb wants to merge 2 commits into
devgianlu:masterfrom
palchrb:claude/go-librespot-output-recovery-iiq3po
Open

feat: add /player/output to reopen audio output live#336
palchrb wants to merge 2 commits into
devgianlu:masterfrom
palchrb:claude/go-librespot-output-recovery-iiq3po

Conversation

@palchrb

@palchrb palchrb commented Jul 21, 2026

Copy link
Copy Markdown

Proposal to allow restoring audio stream without restarting go-librespot. Supports both restoring after your audio connection has failed - or just live-switching between audio outputs without having to restart go-librespot.

Add an endpoint and player command to reopen the audio output on a different device without touching the Spotify session, preserving the current track, playback position, paused state and volume.

The player now tracks the current output device (initialised from the configured AudioDevice) and exposes ReopenOutput, backed by a new playerCmdReopenOutput handled in the manage loop. Reopening flushes and closes the old output before opening the new one — some backends (e.g. pulseaudio) start reading the source as soon as the output is constructed, so two live outputs would corrupt the stream — then restores the paused/playing state. When nothing is playing the device is just recorded for the next output open.

POST /player/output {"device": "..."} drives this from the API; an empty device selects the configured default.

claude added 2 commits July 21, 2026 06:35
Add an endpoint and player command to reopen the audio output on a
different device without touching the Spotify session, preserving the
current track, playback position, paused state and volume.

The player now tracks the current output device (initialised from the
configured AudioDevice) and exposes ReopenOutput, backed by a new
playerCmdReopenOutput handled in the manage loop. Reopening flushes and
closes the old output before opening the new one — some backends (e.g.
pulseaudio) start reading the source as soon as the output is
constructed, so two live outputs would corrupt the stream — then
restores the paused/playing state. When nothing is playing the device is
just recorded for the next output open.

POST /player/output {"device": "..."} drives this from the API; an empty
device selects the configured default.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019FHWG4ossSBydy7jbVFWho
…open

A long-running daemon resolves PCM names against alsa-lib's in-process
configuration cache. When /etc/asound.conf is rewritten to point an
alias at a different device — a client swapping which bluetooth speaker
an alias like "tapbox_bt" means — the cached tree can keep winning:
alsa-lib's change detection compares file identity, timestamps and
size, which misses in-place rewrites that preserve the size (two
bluealsa MAC strings are the same length). Observed in the field as
every open and live reopen reaching the departed speaker's MAC ("PCM
not found" / "No such device") for minutes, until a process restart.

Free the global configuration cache before snd_pcm_open, so every
output creation and /player/output reopen re-parses the configuration
files and resolves the alias as it is now. Opens are rare (the output
persists across track changes), so the re-parse cost is irrelevant.
The subsequent hw params negotiation already exercises the resolved
device end-to-end, so a successful (re)open is a trustworthy signal.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019FHWG4ossSBydy7jbVFWho
@palchrb

palchrb commented Jul 27, 2026

Copy link
Copy Markdown
Author

Added a second commit from field testing on a Raspberry Pi Zero 2 W with bluealsa: a long-running daemon resolves ALSA device aliases against alsa-lib’s in-process config cache, so a reopen could hit a stale device definition after asound.conf changed. The fix frees the global config cache before each PCM open, making the reopen (and any output open) resolve names against the current configuration. Cheap, since outputs are only opened on playback start and reopen.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants