aboutsummaryrefslogtreecommitdiffstats
path: root/src/daemon.rs
diff options
context:
space:
mode:
authorsalmonik <raisersoft@proton.me>2026-05-05 21:37:44 +0200
committersalmonik <raisersoft@proton.me>2026-05-05 21:37:44 +0200
commit1f320d9771bac2780e5a09d6a3bc063b35cf58de (patch)
treeb56506dcdf15b767d3eeb5857453583b76340d17 /src/daemon.rs
parentfix(daemon): robust auto-advance; ensure next track starts even if playback f... (diff)
downloadrsplayer-1f320d9771bac2780e5a09d6a3bc063b35cf58de.tar.gz
rsplayer-1f320d9771bac2780e5a09d6a3bc063b35cf58de.zip
fix(audio): resolve deadlock preventing auto-advance to next track
The audio callback deadlocked when trying to lock audio_data twice, preventing track_ended from being set and breaking auto-advance. Also removed erroneous track_ended.store(true) calls from error paths that were causing incorrect queue advancement when playback failed.
Diffstat (limited to '')
-rw-r--r--src/daemon.rs47
1 files changed, 43 insertions, 4 deletions
diff --git a/src/daemon.rs b/src/daemon.rs
index 8ac3a89..9fa5cea 100644
--- a/src/daemon.rs
+++ b/src/daemon.rs
@@ -150,18 +150,57 @@ pub fn start_daemon() -> Result<(), Box<dyn std::error::Error>> {
150 150
151 // Accept connections until shutdown 151 // Accept connections until shutdown
152 listener.set_nonblocking(true)?; 152 listener.set_nonblocking(true)?;
153 // Helper: poll until a specific track actually starts playing or timeout
154 fn wait_for_start(audio: &AudioEngine, target: &PathBuf, timeout_ms: u64) -> bool {
155 use std::time::{Duration, Instant};
156 let start = Instant::now();
157 while start.elapsed() < Duration::from_millis(timeout_ms) {
158 // If playing and the current track matches, assume started
159 if audio.is_playing() {
160 if let Some(cur) = audio.current_track() {
161 if &cur == target {
162 return true;
163 }
164 }
165 }
166 std::thread::sleep(Duration::from_millis(10));
167 }
168 false
169 }
153 loop { 170 loop {
154 // Check for shutdown signal 171 // Check for shutdown signal
155 if shutdown_flag.load(Ordering::SeqCst) { 172 if shutdown_flag.load(Ordering::SeqCst) {
156 break; 173 break;
157 } 174 }
158 175
159 // Check if track ended and play next 176 // Check if track ended and play next (robust with startup feedback)
160 if audio_engine.poll_track_ended() { 177 if audio_engine.poll_track_ended() {
161 if let Ok(mut q) = queue.lock() { 178 if let Ok(mut q) = queue.lock() {
162 if let Some(next_track) = q.next() { 179 // Save the current position in case we need to revert
163 audio_engine.play(next_track); 180 let original_position = q.position;
164 } else { 181 // Try a handful of next candidates until one starts
182 let mut started = false;
183 // We'll attempt up to 4 candidates ahead
184 let max_trials = 4usize;
185 for _ in 0..max_trials {
186 if let Some(next_track) = q.next() {
187 audio_engine.play(next_track.clone());
188 // Wait a short time to see if playback actually starts
189 if wait_for_start(&audio_engine, &next_track, 500) {
190 started = true;
191 break;
192 } else {
193 // Try next candidate - q.next() already advanced position
194 continue;
195 }
196 } else {
197 break;
198 }
199 }
200 if !started {
201 // Revert position since we couldn't start any track
202 q.position = original_position;
203 // No candidate started; stop playback safely
165 audio_engine.stop(); 204 audio_engine.stop();
166 } 205 }
167 } 206 }