From 3e7727d1d23bcb73711c97d0d8a888b60be0e59c Mon Sep 17 00:00:00 2001 From: Cocoon-Break <54054995+kuishou68@users.noreply.github.com> Date: Thu, 16 Apr 2026 16:54:31 +0800 Subject: [PATCH] fix: keep cpal Stream alive until playback completes (Closes #404) (#405) The cpal Stream was created and play() called but then immediately dropped when play_to_device() returned. When a cpal Stream is dropped, audio output stops immediately. This caused silent playback. Fix: add a spin-wait loop that holds the Stream in scope until all samples have been consumed (or stop_flag is set). --- tauri/src-tauri/src/audio_output.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/tauri/src-tauri/src/audio_output.rs b/tauri/src-tauri/src/audio_output.rs index d2b2c63c..b31c89bf 100644 --- a/tauri/src-tauri/src/audio_output.rs +++ b/tauri/src-tauri/src/audio_output.rs @@ -401,9 +401,25 @@ impl AudioOutputState { eprintln!("play_to_device: Failed to play stream: {}", e); format!("Failed to play stream: {}", e) })?; - + eprintln!("play_to_device: Stream started successfully"); + // Keep the stream alive until playback finishes. + // Previously the stream was dropped immediately on function return, + // causing silent playback (cpal stops output when its Stream is dropped). + let total_samples = { + buffer.lock().unwrap().len() + }; + loop { + let pos = position.load(std::sync::atomic::Ordering::Relaxed); + if pos >= total_samples || stop_flag.load(std::sync::atomic::Ordering::Relaxed) { + break; + } + std::thread::sleep(std::time::Duration::from_millis(10)); + } + + // stream is dropped here, after audio has finished playing + drop(stream); eprintln!("play_to_device: Function completed successfully"); Ok(()) }