fix(player): stop engine before dropping ALSA stream on format change

In the Play and PlayStreaming handlers, the old engine's writer thread
still holds an Arc<AlsaDirectStream> when the stream_opt is dropped and
a new snd_pcm_open() is attempted. This causes EBUSY on track switches
with sample rate changes. Reorder to: stop engine -> drop stream -> open
new stream, matching the Stop handler's correct lifecycle.

cc
This commit is contained in:
vicrodh committed 2026-04-07 11:53:17 -06:00
1 parent 17919cccad
commit 426a4d0dba
1 file changed
+22 -1
+22 -1
View File
@@ -1145,8 +1145,18 @@ impl Player {
} else {
log::info!("Creating initial audio stream");
}
// Drop old stream
// Stop engine FIRST so its writer thread releases its
// Arc<AlsaDirectStream> reference before we drop the stream.
// Without this, snd_pcm_open() races against the old PCM
// handle and fails with EBUSY.
if let Some(engine) = current_engine.take() {
engine.stop();
std::thread::sleep(Duration::from_millis(50));
}
// Now this drop is the last Arc ref — PCM actually closes
drop(stream_opt.take());
// Give kernel time to fully release the ALSA device
std::thread::sleep(Duration::from_millis(50));
}
log::info!(
@@ -1585,7 +1595,18 @@ impl Player {
mode
);
}
// Stop engine FIRST so its writer thread releases its
// Arc<AlsaDirectStream> reference before we drop the stream.
// Without this, snd_pcm_open() races against the old PCM
// handle and fails with EBUSY.
if let Some(engine) = current_engine.take() {
engine.stop();
std::thread::sleep(Duration::from_millis(50));
}
// Now this drop is the last Arc ref — PCM actually closes
drop(stream_opt.take());
// Give kernel time to fully release the ALSA device
std::thread::sleep(Duration::from_millis(50));
}
let stream_result = if let Some(settings) =