diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/audio.rs | 14 | ||||
| -rw-r--r-- | src/daemon.rs | 47 |
2 files changed, 50 insertions, 11 deletions
diff --git a/src/audio.rs b/src/audio.rs index 86c88f7..4e26263 100644 --- a/src/audio.rs +++ b/src/audio.rs | |||
| @@ -204,6 +204,8 @@ fn audio_thread( | |||
| 204 | let vol = vol.lock().map(|v| *v).unwrap_or(1.0); | 204 | let vol = vol.lock().map(|v| *v).unwrap_or(1.0); |
| 205 | 205 | ||
| 206 | if let Ok(mut audio_data) = audio_data_clone.lock() { | 206 | if let Ok(mut audio_data) = audio_data_clone.lock() { |
| 207 | let mut should_clear = false; | ||
| 208 | |||
| 207 | if let Some(ref mut state) = *audio_data { | 209 | if let Some(ref mut state) = *audio_data { |
| 208 | let channels = state.channels as usize; | 210 | let channels = state.channels as usize; |
| 209 | let mut offset = 0usize; | 211 | let mut offset = 0usize; |
| @@ -298,16 +300,17 @@ fn audio_thread( | |||
| 298 | if offset == 0 && state.sample_buffer.is_empty() { | 300 | if offset == 0 && state.sample_buffer.is_empty() { |
| 299 | ended.store(true, Ordering::SeqCst); | 301 | ended.store(true, Ordering::SeqCst); |
| 300 | is_playing_clone.store(false, Ordering::SeqCst); | 302 | is_playing_clone.store(false, Ordering::SeqCst); |
| 301 | // Clear audio data so we don't keep triggering ended | 303 | should_clear = true; |
| 302 | if let Ok(mut audio_data) = audio_data_clone.lock() { | ||
| 303 | *audio_data = None; | ||
| 304 | } | ||
| 305 | } | 304 | } |
| 306 | } else { | 305 | } else { |
| 307 | for sample in data.iter_mut() { | 306 | for sample in data.iter_mut() { |
| 308 | *sample = 0.0; | 307 | *sample = 0.0; |
| 309 | } | 308 | } |
| 310 | } | 309 | } |
| 310 | |||
| 311 | if should_clear { | ||
| 312 | *audio_data = None; | ||
| 313 | } | ||
| 311 | } | 314 | } |
| 312 | }, | 315 | }, |
| 313 | |err| { | 316 | |err| { |
| @@ -319,7 +322,6 @@ fn audio_thread( | |||
| 319 | if let Err(e) = stream.play() { | 322 | if let Err(e) = stream.play() { |
| 320 | eprintln!("Failed to start stream: {}", e); | 323 | eprintln!("Failed to start stream: {}", e); |
| 321 | is_playing.store(false, Ordering::SeqCst); | 324 | is_playing.store(false, Ordering::SeqCst); |
| 322 | track_ended.store(true, Ordering::SeqCst); | ||
| 323 | } else { | 325 | } else { |
| 324 | current_stream = Some(stream); | 326 | current_stream = Some(stream); |
| 325 | } | 327 | } |
| @@ -327,14 +329,12 @@ fn audio_thread( | |||
| 327 | Err(e) => { | 329 | Err(e) => { |
| 328 | eprintln!("Failed to create stream: {}", e); | 330 | eprintln!("Failed to create stream: {}", e); |
| 329 | is_playing.store(false, Ordering::SeqCst); | 331 | is_playing.store(false, Ordering::SeqCst); |
| 330 | track_ended.store(true, Ordering::SeqCst); | ||
| 331 | } | 332 | } |
| 332 | } | 333 | } |
| 333 | } | 334 | } |
| 334 | Err(e) => { | 335 | Err(e) => { |
| 335 | eprintln!("Failed to open audio: {}", e); | 336 | eprintln!("Failed to open audio: {}", e); |
| 336 | is_playing.store(false, Ordering::SeqCst); | 337 | is_playing.store(false, Ordering::SeqCst); |
| 337 | track_ended.store(true, Ordering::SeqCst); | ||
| 338 | } | 338 | } |
| 339 | } | 339 | } |
| 340 | } | 340 | } |
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 | } |
