2 months ago
7a9d0a5The output stream was built once and then parked on for the life of the process, and the cpal error callback only printed to stderr - not even through tracing, so a disconnect never reached the log file. Pulling a Bluetooth speaker or switching the TV input left the app silent with no recovery short of restarting it, which is a routine event for home karaoke. Turn the park loop into a supervisor: the error callback flags device loss, the loop drops the dead stream and rebuilds against whatever the default output device is now. Rebuilding rather than pausing-and-prompting is the smaller change *and* the better behaviour, because the stream owns none of the playback state - position, stem lockstep, EQ and crossfade all live in PlaybackController. The acceptance criteria about position and lockstep are therefore free: those values are not in the object being replaced. build_output_stream already bumps the output-format generation on every construction, the "device restart" case its own comments describe. Rebuild failures back off at 1s and keep retrying so replugging recovers on its own, and log once per outage rather than per attempt. Ceiling, recorded in the code: this recovers from disconnects cpal reports through the error callback. A device that keeps the stream nominally alive but stops producing sound needs a platform device-change listener, which is a separate change. Closes #250
Parent793cbe9