diff options
| author | salmonik <raisersoft@proton.me> | 2026-05-09 17:14:39 +0200 |
|---|---|---|
| committer | salmonik <raisersoft@proton.me> | 2026-05-09 17:14:39 +0200 |
| commit | 898ebd930e0c5bb8b3f092d4c462bc38130adccf (patch) | |
| tree | ba5c53dfcd11af604ccad47e5166753acd4d72c5 /src | |
| parent | Major rewrite: play command, queue display, and shuffle modes (diff) | |
| download | rsplayer-898ebd930e0c5bb8b3f092d4c462bc38130adccf.tar.gz rsplayer-898ebd930e0c5bb8b3f092d4c462bc38130adccf.zip | |
Fix buffer underrun - pre-decode samples before playback
Diffstat (limited to '')
| -rw-r--r-- | src/audio.rs | 31 | ||||
| -rw-r--r-- | src/daemon.rs | 9 |
2 files changed, 35 insertions, 5 deletions
diff --git a/src/audio.rs b/src/audio.rs index 7218f84..386c041 100644 --- a/src/audio.rs +++ b/src/audio.rs | |||
| @@ -197,6 +197,37 @@ fn audio_thread( | |||
| 197 | Some(device_sample_rate as f64 / data.sample_rate as f64); | 197 | Some(device_sample_rate as f64 / data.sample_rate as f64); |
| 198 | } | 198 | } |
| 199 | 199 | ||
| 200 | // Pre-decode some samples before starting playback to prevent buffer underrun | ||
| 201 | let channels = data.channels as usize; | ||
| 202 | for _ in 0..50 { | ||
| 203 | match data.format.next_packet() { | ||
| 204 | Ok(packet) => { | ||
| 205 | match data.decoder.decode(&packet) { | ||
| 206 | Ok(decoded) => { | ||
| 207 | let spec = *decoded.spec(); | ||
| 208 | let mut sample_buf = | ||
| 209 | symphonia::core::audio::SampleBuffer::<f32>::new( | ||
| 210 | decoded.capacity() as u64, spec | ||
| 211 | ); | ||
| 212 | sample_buf.copy_interleaved_ref(decoded); | ||
| 213 | let samples = sample_buf.samples(); | ||
| 214 | |||
| 215 | let resampled = if let Some(ratio) = data.resample_ratio { | ||
| 216 | resample_linear(samples, ratio, channels) | ||
| 217 | } else { | ||
| 218 | samples.to_vec() | ||
| 219 | }; | ||
| 220 | |||
| 221 | data.sample_buffer.extend(resampled); | ||
| 222 | } | ||
| 223 | Err(_) => break, | ||
| 224 | } | ||
| 225 | } | ||
| 226 | Err(_) => break, | ||
| 227 | } | ||
| 228 | } | ||
| 229 | data.buffer_pos = 0; | ||
| 230 | |||
| 200 | let stream_config: cpal::StreamConfig = | 231 | let stream_config: cpal::StreamConfig = |
| 201 | device.default_output_config().unwrap().into(); | 232 | device.default_output_config().unwrap().into(); |
| 202 | 233 | ||
diff --git a/src/daemon.rs b/src/daemon.rs index f4a72b7..7488fc2 100644 --- a/src/daemon.rs +++ b/src/daemon.rs | |||
| @@ -400,8 +400,9 @@ fn process_command( | |||
| 400 | } | 400 | } |
| 401 | _ => { | 401 | _ => { |
| 402 | let was_empty = q.is_empty(); | 402 | let was_empty = q.is_empty(); |
| 403 | let was_playing = audio.is_playing(); | ||
| 403 | q.add_track(path.clone()); | 404 | q.add_track(path.clone()); |
| 404 | if was_empty && audio.is_playing() { | 405 | if was_empty && !was_playing { |
| 405 | let track = Track::from_path(path.clone()); | 406 | let track = Track::from_path(path.clone()); |
| 406 | audio.play(path); | 407 | audio.play(path); |
| 407 | notification::notify_track(&track); | 408 | notification::notify_track(&track); |
| @@ -449,13 +450,11 @@ fn process_command( | |||
| 449 | ) | 450 | ) |
| 450 | } | 451 | } |
| 451 | _ => { | 452 | _ => { |
| 453 | let was_playing = audio.is_playing(); | ||
| 452 | for file in &files { | 454 | for file in &files { |
| 453 | q.add_track(file.clone()); | 455 | q.add_track(file.clone()); |
| 454 | } | 456 | } |
| 455 | if was_empty | 457 | if was_empty && !was_playing && let Some(track) = q.current() { |
| 456 | && audio.is_playing() | ||
| 457 | && let Some(track) = q.current() | ||
| 458 | { | ||
| 459 | audio.play(track.path.clone()); | 458 | audio.play(track.path.clone()); |
| 460 | notification::notify_track(track); | 459 | notification::notify_track(track); |
| 461 | } | 460 | } |
