1#![warn(missing_docs)]
2#![doc(issue_tracker_base_url = "https://gitlab.101100.ca/veda/playback-rs/-/issues")]
3#![doc = include_str!("../docs.md")]
4#![feature(c_variadic)]
5
6use std::collections::VecDeque;
7use std::num::Wrapping;
8use std::sync::atomic::{AtomicU64, Ordering};
9use std::sync::mpsc::{self, TryRecvError};
10use std::sync::{Arc, Mutex, RwLock};
11use std::thread;
12use std::time::Duration;
13
14use color_eyre::eyre::{Report, Result, ensure};
15use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
16use cpal::{
17 Device, FrameCount, FromSample, HostId, OutputCallbackInfo, Sample, SampleFormat, SizedSample,
18 Stream, StreamConfig, StreamError, SupportedBufferSize, SupportedStreamConfigRange,
19};
20use log::{debug, error, info, warn};
21use rubato::{
22 Resampler, SincFixedOut, SincInterpolationParameters, SincInterpolationType, WindowFunction,
23};
24use symphonia::core::audio::SampleBuffer;
25use symphonia::core::codecs::DecoderOptions;
26use symphonia::core::errors::Error as SymphoniaError;
27use symphonia::core::formats::FormatOptions;
28use symphonia::core::io::{MediaSource, MediaSourceStream, MediaSourceStreamOptions};
29use symphonia::core::meta::MetadataOptions;
30use symphonia::default;
31
32pub use symphonia::core::probe::Hint;
33
34#[derive(Debug, Clone, Copy, PartialEq)]
35struct SampleRequest {
36 frame: Option<(Duration, Wrapping<u8>)>,
37 speed: f64,
38}
39
40#[derive(Debug, Clone, PartialEq)]
41struct SampleResult {
42 samples: Vec<f32>,
43 end_pos: Duration,
44 skip_count: Wrapping<u8>,
45 done: bool,
46}
47
48#[derive(Debug)]
49struct DecodingSong {
50 song_length: Duration,
51 channel_count: usize,
52
53 requests_channel: mpsc::SyncSender<SampleRequest>,
54 samples_channel: Mutex<mpsc::Receiver<SampleResult>>,
55 frames_per_resample: usize,
56
57 buffer: VecDeque<f32>,
58 pending_requests: usize,
59 done: bool,
60 had_output: bool,
61 expected_pos: Duration,
62 skip_count: Wrapping<u8>,
63}
64
65const MAXIMUM_SPEED_ADJUSTMENT_FACTOR: f64 = 2.0;
66const MINIMUM_PLAYBACK_SPEED: f64 = 1.0 / MAXIMUM_SPEED_ADJUSTMENT_FACTOR;
67const MAXIMUM_PLAYBACK_SPEED: f64 = 1.0 * MAXIMUM_SPEED_ADJUSTMENT_FACTOR;
68
69impl DecodingSong {
70 fn new(
71 song: &Song,
72 initial_pos: Duration,
73 player_sample_rate: usize,
74 player_channel_count: usize,
75 expected_buffer_size: usize,
76 initial_playback_speed: f64,
77 ) -> Result<DecodingSong> {
78 let frames = song.samples.clone();
79 let song_channel_count = song.channel_count;
80 if player_channel_count != song_channel_count {
81 warn!(
82 "Playing song with {song_channel_count} channels while the player has {player_channel_count} channels"
83 );
84 }
85 let total_frames = frames[0].len();
86 let frames_per_resample = expected_buffer_size / player_channel_count;
87 let volume_adjustment = song.volume_adjustment;
88
89 let (rtx, rrx) = mpsc::sync_channel::<SampleRequest>(10);
90 let (stx, srx) = mpsc::channel();
91 let song_sample_rate = song.sample_rate as u64;
92 let song_length = Self::frame_to_duration(total_frames, song_sample_rate);
93 let resample_ratio = player_sample_rate as f64 / song.sample_rate as f64;
94 let (etx, erx) = mpsc::channel();
95 thread::spawn(move || {
96 let sinc_len = 128;
97 let f_cutoff = 0.925_914_65;
98 let params = SincInterpolationParameters {
99 sinc_len,
100 f_cutoff,
101 interpolation: SincInterpolationType::Linear,
102 oversampling_factor: 2048,
103 window: WindowFunction::Blackman2,
104 };
105 let mut resampler = match SincFixedOut::<f32>::new(
106 resample_ratio,
107 MAXIMUM_SPEED_ADJUSTMENT_FACTOR,
108 params,
109 frames_per_resample, player_channel_count,
111 ) {
112 Ok(resampler) => {
113 etx.send(Ok(())).unwrap();
114 resampler
115 }
116 Err(e) => {
117 etx.send(Err(e)).unwrap();
118 return;
119 }
120 };
121 let mut input_buffer = resampler.input_buffer_allocate(true);
122 let mut output_buffer = resampler.output_buffer_allocate(true);
123
124 let mut current_frame = 0;
125 let mut skip_count = Wrapping(0);
126 let mut last_request_speed = 1.0;
127 loop {
128 let request = match rrx.recv() {
129 Ok(request) => request,
130 Err(_) => {
131 debug!("Ending resampling thread.");
132 break;
133 }
134 };
135
136 if let Some((new_pos, new_skip_count)) = request.frame {
138 let new_frame = (song_sample_rate * new_pos.as_secs()
139 + song_sample_rate * new_pos.subsec_nanos() as u64 / 1_000_000_000)
140 as usize;
141 current_frame = new_frame.min(total_frames);
142 skip_count = new_skip_count;
143 }
144
145 if request.speed != last_request_speed {
147 resampler
148 .set_resample_ratio_relative(1.0 / request.speed, false)
149 .unwrap();
150 last_request_speed = request.speed;
151 }
152
153 let frames_wanted_by_resampler = resampler.input_frames_next();
155 let last_frame = (current_frame + frames_wanted_by_resampler).min(total_frames);
156 let frames_we_have = last_frame - current_frame;
157 for i in 0..player_channel_count {
158 input_buffer[i].clear();
159 for j in 0..frames_wanted_by_resampler {
160 if current_frame + j < total_frames {
161 input_buffer[i].push(frames[i % song_channel_count][current_frame + j]);
162 } else {
163 input_buffer[i].push(0.0);
164 }
165 }
166 }
167 current_frame = last_frame;
168 let end_pos = Self::frame_to_duration(current_frame, song_sample_rate);
169
170 let processed_samples =
172 match resampler.process_into_buffer(&input_buffer, &mut output_buffer, None) {
173 Ok((_, frame_count)) => {
174 let mut samples = vec![0.0; player_channel_count * frame_count];
175 for chan in 0..player_channel_count {
176 if chan < 2 || chan < output_buffer.len() {
177 for sample in 0..frame_count {
178 samples[sample * player_channel_count + chan] =
179 output_buffer[chan % output_buffer.len()][sample]
180 * volume_adjustment
181 }
182 };
183 }
184 samples
185 }
186 Err(e) => {
187 error!("Error converting sample rate: {e}");
188 vec![0.0; expected_buffer_size]
189 }
190 };
191
192 if stx
195 .send(SampleResult {
196 samples: processed_samples,
197 skip_count,
198 end_pos,
199 done: frames_we_have < frames_wanted_by_resampler,
200 })
201 .is_err()
202 {
203 debug!("Ending resampling thread.");
204 break;
205 }
206 }
207 });
208 erx.recv()??;
209 let skip_count = Wrapping(0);
210 rtx.send(SampleRequest {
211 speed: initial_playback_speed,
212 frame: Some((initial_pos, skip_count)),
213 })?;
214 Ok(DecodingSong {
215 song_length,
216 channel_count: player_channel_count,
217 requests_channel: rtx,
218 samples_channel: Mutex::new(srx),
219 frames_per_resample,
220 buffer: VecDeque::new(),
221 pending_requests: 1,
222 done: false,
223 had_output: false,
224 expected_pos: initial_pos,
225 skip_count,
226 })
227 }
228 fn read_samples(
229 &mut self,
230 pos: Duration,
231 count: usize,
232 playback_speed: f64,
233 ) -> (Vec<f32>, Duration, bool) {
234 if pos != self.expected_pos {
236 self.had_output = false;
237 self.done = false;
238 self.buffer.clear();
239 self.skip_count += 1;
240 self.requests_channel
241 .send(SampleRequest {
242 speed: playback_speed,
243 frame: Some((pos, self.skip_count)),
244 })
245 .unwrap(); self.pending_requests = 1;
247 }
248
249 while count
250 > self.buffer.len()
251 + self.pending_requests * self.frames_per_resample * self.channel_count
252 {
253 if self
254 .requests_channel
255 .send(SampleRequest {
256 speed: playback_speed,
257 frame: None,
258 })
259 .is_err()
260 {
261 break;
262 }
263
264 self.pending_requests += 1;
265 }
266 let channel = self.samples_channel.lock().unwrap();
267 if !self.done {
268 let mut sent_warning = !self.had_output;
270 loop {
271 let got = channel.try_recv();
272 match got {
273 Ok(SampleResult {
274 samples,
275 skip_count,
276 end_pos,
277 done,
278 }) => {
279 if self.skip_count == skip_count {
280 self.pending_requests -= 1;
281 self.buffer.append(&mut VecDeque::from(samples));
282 self.expected_pos = end_pos;
283 if done {
284 self.done = true;
285 break;
286 }
287 if self.buffer.len() >= count {
288 break;
289 }
290 }
291 }
292 Err(TryRecvError::Disconnected) => {
293 self.done = true;
294 break;
295 }
296 Err(TryRecvError::Empty) => {
297 if self.buffer.len() >= count {
298 break;
299 } else if !sent_warning {
300 warn!(
301 "Waiting on resampler, this could cause audio choppyness. If you are a developer and this happens repeatedly in release mode please file an issue on playback-rs."
302 );
303 sent_warning = true;
304 }
305 }
306 }
307 }
308 }
309 let mut vec = Vec::new();
310 let mut done = false;
311 for _i in 0..count {
312 if let Some(sample) = self.buffer.pop_front() {
313 vec.push(sample);
314 } else {
315 done = true;
316 break;
317 }
318 }
319
320 (vec, self.expected_pos, done)
321 }
322 fn frame_to_duration(frame: usize, song_sample_rate: u64) -> Duration {
323 let sub_second_samples = frame as u64 % song_sample_rate;
324 Duration::new(
325 frame as u64 / song_sample_rate,
326 (1_000_000_000 * sub_second_samples / song_sample_rate) as u32,
327 )
328 }
329}
330
331type PlaybackState = (DecodingSong, Duration);
332
333#[derive(Clone)]
334struct PlayerState {
335 playback: Arc<RwLock<Option<PlaybackState>>>,
336 next_samples: Arc<RwLock<Option<PlaybackState>>>,
337 playing: Arc<RwLock<bool>>,
338 channel_count: usize,
339 sample_rate: usize,
340 buffer_size: u32,
341 playback_speed: Arc<RwLock<f64>>,
342}
343
344impl PlayerState {
345 fn new(channel_count: u32, sample_rate: u32, buffer_size: FrameCount) -> Result<PlayerState> {
346 Ok(PlayerState {
347 playback: Arc::new(RwLock::new(None)),
348 next_samples: Arc::new(RwLock::new(None)),
349 playing: Arc::new(RwLock::new(true)),
350 channel_count: channel_count as usize,
351 sample_rate: sample_rate as usize,
352 buffer_size,
353 playback_speed: Arc::new(RwLock::new(1.0)),
354 })
355 }
356 fn write_samples<T>(&self, data: &mut [T], _info: &OutputCallbackInfo)
357 where
358 T: Sample + FromSample<f32>,
359 {
360 for sample in data.iter_mut() {
361 *sample = Sample::EQUILIBRIUM;
362 }
363 if *self.playing.read().unwrap() {
364 let playback_speed = *self.playback_speed.read().unwrap();
365 let mut playback = self.playback.write().unwrap();
366 if playback.is_none()
367 && let Some((new_samples, new_pos)) = self.next_samples.write().unwrap().take()
368 {
369 *playback = Some((new_samples, new_pos));
370 }
371 let mut done = false;
372 if let Some((decoding_song, sample_pos)) = playback.as_mut() {
373 let mut neg_offset = 0;
374 let data_len = data.len();
375 let (mut samples, mut new_pos, mut is_final) =
376 decoding_song.read_samples(*sample_pos, data_len, playback_speed);
377 for (i, sample) in data.iter_mut().enumerate() {
378 if i >= samples.len() {
379 if let Some((next_samples, next_pos)) =
380 self.next_samples.write().unwrap().take()
381 {
382 *decoding_song = next_samples;
383 neg_offset = i;
384 *sample_pos = next_pos;
385 (samples, new_pos, is_final) = decoding_song.read_samples(
386 *sample_pos,
387 data_len - neg_offset,
388 playback_speed,
389 );
390 } else {
391 break;
392 }
393 }
394 *sample = T::from_sample(samples[i - neg_offset]);
395 }
396 *sample_pos = new_pos;
397 done = is_final;
398 }
399 if done {
400 *playback = None;
401 }
402 }
403 }
404 fn decode_song(&self, song: &Song, initial_pos: Duration) -> Result<DecodingSong> {
405 DecodingSong::new(
406 song,
407 initial_pos,
408 self.sample_rate,
409 self.channel_count,
410 self.buffer_size as usize,
411 *self.playback_speed.read().unwrap(),
412 )
413 }
414 fn set_playback_speed(&self, speed: f64) {
415 *self.playback_speed.write().unwrap() =
416 speed.clamp(MINIMUM_PLAYBACK_SPEED, MAXIMUM_PLAYBACK_SPEED);
417 }
418 fn stop(&self) {
419 *self.next_samples.write().unwrap() = None;
420 *self.playback.write().unwrap() = None;
421 }
422 fn skip(&self) {
423 *self.playback.write().unwrap() = None;
424 }
425 fn play_song(&self, song: &Song, time: Option<Duration>) -> Result<()> {
426 let initial_pos = time.unwrap_or_default();
427 let samples = self.decode_song(song, initial_pos)?;
428 *self.next_samples.write().unwrap() = Some((samples, initial_pos));
429 Ok(())
430 }
431 fn set_playing(&self, playing: bool) {
432 *self.playing.write().unwrap() = playing;
433 }
434 fn get_position(&self) -> Option<(Duration, Duration)> {
435 self.playback
436 .read()
437 .unwrap()
438 .as_ref()
439 .map(|(samples, pos)| (*pos, samples.song_length))
440 }
441 fn seek(&self, time: Duration) -> bool {
442 let (mut playback, mut next_song) = (
443 self.playback.write().unwrap(),
444 self.next_samples.write().unwrap(),
445 );
446 if let Some((_, pos)) = playback.as_mut() {
447 *pos = time;
448 true
449 } else if let Some((_, pos)) = next_song.as_mut() {
450 *pos = time;
451 true
452 } else {
453 false
454 }
455 }
456 fn force_remove_next_song(&self) {
457 let (mut playback, mut next_song) = (
458 self.playback.write().unwrap(),
459 self.next_samples.write().unwrap(),
460 );
461 if next_song.is_some() {
462 *next_song = None;
463 } else {
464 *playback = None;
465 }
466 }
467}
468
469pub struct Player {
471 _stream: Box<dyn StreamTrait>,
472 error_receiver: mpsc::Receiver<Report>,
473 error_count: Arc<AtomicU64>,
474 player_state: PlayerState,
475}
476
477impl Player {
478 pub fn new(preferred_sampling_rates: Option<Vec<u32>>) -> Result<Player> {
487 let device = {
488 let mut selected_host = cpal::default_host();
489 for host in cpal::available_hosts() {
490 if host.name().to_lowercase().contains("jack") {
491 selected_host = cpal::host_from_id(host)?;
492 }
493 }
494 info!("Selected Host: {:?}", selected_host.id());
495 #[cfg(any(
496 target_os = "linux",
497 target_os = "dragonfly",
498 target_os = "freebsd",
499 target_os = "netbsd"
500 ))]
501 {
502 if selected_host.id() == HostId::Alsa {
503 block_alsa_output();
504 }
505 }
506 let mut selected_device = selected_host
507 .default_output_device()
508 .ok_or_else(|| Report::msg("No output device found."))?;
509 for device in selected_host.output_devices()? {
510 if let Ok(name) = device.description().map(|s| s.name().to_lowercase())
511 && (name.contains("pipewire")
512 || name.contains("pulse")
513 || name.contains("jack"))
514 {
515 selected_device = device;
516 }
517 }
518 info!(
519 "Selected device: {}, {}",
520 selected_device
521 .id()
522 .map(|di| format!("host: '{}', unique ID: '{}'", di.0, di.1))
523 .unwrap_or_else(|_| "no ID".to_string()),
524 selected_device
525 .description()
526 .map(|dd| format!("description: '{}'", dd.name()))
527 .unwrap_or_else(|_| "no description".to_string()),
528 );
529 selected_device
530 };
531 let mut supported_configs = device.supported_output_configs()?.collect::<Vec<_>>();
532 let preferred_sampling_rates = preferred_sampling_rates
533 .filter(|given_rates| !given_rates.is_empty())
534 .unwrap_or(vec![48000, 44100]);
535 let preferred_sampling_rate = preferred_sampling_rates[0];
536 let rank_supported_config = |config: &SupportedStreamConfigRange| {
537 let chans = config.channels() as u32;
538 let channel_rank = match chans {
539 0 => 0,
540 1 => 1,
541 2 => 4,
542 4 => 3,
543 _ => 2,
544 };
545 let min_sample_rank = if config.min_sample_rate() <= preferred_sampling_rate {
546 3
547 } else {
548 0
549 };
550 let max_sample_rank = if config.max_sample_rate() >= preferred_sampling_rate {
551 3
552 } else {
553 0
554 };
555 let sample_format_rank = if config.sample_format() == SampleFormat::F32 {
556 4
557 } else {
558 0
559 };
560 channel_rank + min_sample_rank + max_sample_rank + sample_format_rank
561 };
562 supported_configs.sort_by_key(|c_2| std::cmp::Reverse(rank_supported_config(c_2)));
563
564 let supported_config = supported_configs
565 .into_iter()
566 .next()
567 .ok_or_else(|| Report::msg("No supported output config."))?;
568
569 let sample_rate_range =
570 supported_config.min_sample_rate()..supported_config.max_sample_rate();
571 let supported_config = if let Some(selected_rate) = preferred_sampling_rates
572 .into_iter()
573 .find(|rate| sample_rate_range.contains(rate))
574 {
575 supported_config.with_sample_rate(selected_rate)
576 } else if sample_rate_range.end <= preferred_sampling_rate {
577 supported_config.with_sample_rate(sample_rate_range.end)
578 } else {
579 supported_config.with_sample_rate(sample_rate_range.start)
580 };
581 let sample_format = supported_config.sample_format();
582 let sample_rate = supported_config.sample_rate();
583 let channel_count = supported_config.channels();
584 let buffer_size = match supported_config.buffer_size() {
585 SupportedBufferSize::Range { min, .. } => (*min).max(1024) * 2,
586 SupportedBufferSize::Unknown => 1024 * 2,
587 };
588 let config = supported_config.into();
589 let player_state = PlayerState::new(channel_count as u32, sample_rate, buffer_size)?;
590 info!(
591 "SR, CC, SF: {}, {}, {:?}",
592 sample_rate, channel_count, sample_format
593 );
594
595 let error_count = Arc::new(AtomicU64::new(0));
596 let (error_sender, error_receiver) = mpsc::channel();
597 fn build_stream<T>(
598 device: &Device,
599 config: &StreamConfig,
600 player_state: PlayerState,
601 error_sender: mpsc::Sender<Report>,
602 error_count: Arc<AtomicU64>,
603 ) -> Result<Stream>
604 where
605 T: SizedSample + FromSample<f32>,
606 {
607 let err_fn = move |err: StreamError| {
608 if error_count.fetch_add(1, Ordering::Relaxed) < 5 {
610 error!("A playback error has occurred! {}", err);
611 let _ = error_sender.send(err.clone().into());
612 }
613 };
614 let stream = device.build_output_stream(
615 config,
616 move |data, info| player_state.write_samples::<T>(data, info),
617 err_fn,
618 None,
619 )?;
620 stream.play()?;
622 Ok(stream)
623 }
624 let stream = {
625 let player_state = player_state.clone();
626 match sample_format {
627 SampleFormat::I8 => build_stream::<i8>(
628 &device,
629 &config,
630 player_state,
631 error_sender,
632 error_count.clone(),
633 )?,
634 SampleFormat::I16 => build_stream::<i16>(
635 &device,
636 &config,
637 player_state,
638 error_sender,
639 error_count.clone(),
640 )?,
641 SampleFormat::I32 => build_stream::<i32>(
642 &device,
643 &config,
644 player_state,
645 error_sender,
646 error_count.clone(),
647 )?,
648 SampleFormat::I64 => build_stream::<i64>(
649 &device,
650 &config,
651 player_state,
652 error_sender,
653 error_count.clone(),
654 )?,
655 SampleFormat::U8 => build_stream::<u8>(
656 &device,
657 &config,
658 player_state,
659 error_sender,
660 error_count.clone(),
661 )?,
662 SampleFormat::U16 => build_stream::<u16>(
663 &device,
664 &config,
665 player_state,
666 error_sender,
667 error_count.clone(),
668 )?,
669 SampleFormat::U32 => build_stream::<u32>(
670 &device,
671 &config,
672 player_state,
673 error_sender,
674 error_count.clone(),
675 )?,
676 SampleFormat::U64 => build_stream::<u64>(
677 &device,
678 &config,
679 player_state,
680 error_sender,
681 error_count.clone(),
682 )?,
683 SampleFormat::F32 => build_stream::<f32>(
684 &device,
685 &config,
686 player_state,
687 error_sender,
688 error_count.clone(),
689 )?,
690 SampleFormat::F64 => build_stream::<f64>(
691 &device,
692 &config,
693 player_state,
694 error_sender,
695 error_count.clone(),
696 )?,
697 sample_format => Err(Report::msg(format!(
698 "Unsupported sample format '{sample_format}'"
699 )))?,
700 }
701 };
702 Ok(Player {
703 _stream: Box::new(stream),
704 error_receiver,
705 error_count,
706 player_state,
707 })
708 }
709 pub fn set_playback_speed(&self, speed: f64) {
711 self.player_state.set_playback_speed(speed);
712 }
713 pub fn play_song_next(&self, song: &Song, start_time: Option<Duration>) -> Result<()> {
715 self.player_state.play_song(song, start_time)
716 }
717 pub fn play_song_now(&self, song: &Song, start_time: Option<Duration>) -> Result<()> {
719 self.player_state.stop();
720 self.player_state.play_song(song, start_time)?;
721 Ok(())
722 }
723 pub fn force_replace_next_song(&self, song: &Song, start_time: Option<Duration>) -> Result<()> {
728 self.player_state.force_remove_next_song();
729 self.player_state.play_song(song, start_time)?;
730 Ok(())
731 }
732 pub fn force_remove_next_song(&self) -> Result<()> {
737 self.player_state.force_remove_next_song();
738 Ok(())
739 }
740 pub fn stop(&self) {
744 self.player_state.stop();
745 }
746 pub fn skip(&self) {
750 self.player_state.skip();
751 }
752 pub fn get_playback_position(&self) -> Option<(Duration, Duration)> {
756 self.player_state.get_position()
757 }
758 pub fn seek(&self, time: Duration) -> bool {
765 self.player_state.seek(time)
766 }
767 pub fn set_playing(&self, playing: bool) {
771 self.player_state.set_playing(playing);
772 }
773 pub fn is_playing(&self) -> bool {
777 *self.player_state.playing.read().unwrap()
778 }
779 pub fn has_next_song(&self) -> bool {
784 self.player_state
785 .next_samples
786 .read()
787 .expect("Next song mutex poisoned.")
788 .is_some()
789 }
790 pub fn has_current_song(&self) -> bool {
794 self.player_state
795 .playback
796 .read()
797 .expect("Current song mutex poisoned.")
798 .is_some()
799 || self
800 .player_state
801 .next_samples
802 .read()
803 .expect("Next song mutex poisoned.")
804 .is_some()
805 }
806 pub fn get_errors(&self) -> (Vec<Report>, u64) {
810 let mut errors = Vec::new();
811 while let Ok(err) = self.error_receiver.try_recv() {
812 errors.push(err);
813 }
814 let errors_count = self.error_count.load(Ordering::Relaxed);
815 (errors, errors_count)
816 }
817 pub fn reset_errors(&self) -> u64 {
821 while self.error_receiver.try_recv().is_ok() {}
823 self.error_count.swap(0, Ordering::Relaxed)
824 }
825}
826
827#[derive(Debug, Clone)]
831pub struct Song {
832 samples: Arc<Vec<Vec<f32>>>,
833 sample_rate: u32,
834 channel_count: usize,
835 volume_adjustment: f32,
836}
837
838impl Song {
839 pub fn new(
841 reader: Box<dyn MediaSource>,
842 hint: &Hint,
843 volume_adjustment: Option<f32>,
844 ) -> Result<Song> {
845 let media_source_stream =
846 MediaSourceStream::new(reader, MediaSourceStreamOptions::default());
847 let mut probe_result = default::get_probe().format(
848 hint,
849 media_source_stream,
850 &FormatOptions {
851 enable_gapless: true,
852 ..FormatOptions::default()
853 },
854 &MetadataOptions::default(),
855 )?;
856 let mut decoder = default::get_codecs().make(
857 &probe_result
858 .format
859 .default_track()
860 .ok_or_else(|| Report::msg("No default track in media file."))?
861 .codec_params,
862 &DecoderOptions::default(),
863 )?;
864 let mut song: Option<(Vec<Vec<f32>>, u32, usize)> = None;
865 let mut bad_packet = false;
866 loop {
867 match probe_result.format.next_packet() {
868 Ok(packet) => {
869 let decoded = match decoder.decode(&packet) {
870 Ok(decoded) => decoded,
871 Err(symphonia::core::errors::Error::DecodeError(err)) => {
872 if !bad_packet {
875 bad_packet = true;
876 warn!("Bad packet: {err:?}");
877 }
878 continue;
879 }
880 Err(err) => {
881 return Err(Report::new(err));
882 }
883 };
884 let spec = *decoded.spec();
885 let song_samples =
886 if let Some((samples, sample_rate, channel_count)) = &mut song {
887 ensure!(
888 spec.rate == *sample_rate,
889 "Sample rate of decoded does not match previous sample rate."
890 );
891 ensure!(
892 spec.channels.count() == *channel_count,
893 "Channel count of decoded does not match previous channel count."
894 );
895 samples
896 } else {
897 song = Some((
898 vec![Vec::new(); spec.channels.count()],
899 spec.rate,
900 spec.channels.count(),
901 ));
902 &mut song.as_mut().unwrap().0
903 };
904 if decoded.frames() > 0 {
905 let mut samples = SampleBuffer::new(decoded.frames() as u64, spec);
906 samples.copy_interleaved_ref(decoded);
907 for frame in samples.samples().chunks(spec.channels.count()) {
908 for (chan, sample) in frame.iter().enumerate() {
909 song_samples[chan].push(*sample)
910 }
911 }
912 } else {
913 warn!("Empty packet encountered while loading song!");
914 }
915 }
916 Err(SymphoniaError::IoError(_)) => break,
917 Err(e) => return Err(e.into()),
918 }
919 }
920 song.map(|(samples, sample_rate, channel_count)| Song {
921 samples: Arc::new(samples),
922 sample_rate,
923 channel_count,
924 volume_adjustment: volume_adjustment.unwrap_or(1.0),
925 })
926 .ok_or_else(|| Report::msg("No song data decoded."))
927 }
928 pub fn from_file<P: AsRef<std::path::Path>>(
930 path: P,
931 volume_adjustment: Option<f32>,
932 ) -> Result<Song> {
933 let mut hint = Hint::new();
934 if let Some(extension) = path.as_ref().extension().and_then(|s| s.to_str()) {
935 hint.with_extension(extension);
936 }
937 Self::new(
938 Box::new(std::fs::File::open(path)?),
939 &hint,
940 volume_adjustment,
941 )
942 }
943 pub fn with_volume_adjustment(&self, volume_adjustment: f32) -> Self {
947 Self {
948 samples: self.samples.clone(),
949 sample_rate: self.sample_rate,
950 channel_count: self.channel_count,
951 volume_adjustment,
952 }
953 }
954}
955
956#[cfg(any(
957 target_os = "linux",
958 target_os = "dragonfly",
959 target_os = "freebsd",
960 target_os = "netbsd"
961))]
962fn block_alsa_output() {
963 use std::os::raw::{c_char, c_int};
964
965 use alsa_sys::snd_lib_error_set_handler;
966 use log::trace;
967
968 unsafe extern "C" fn error_handler(
969 file: *const c_char,
970 line: c_int,
971 function: *const c_char,
972 err: c_int,
973 format: *const c_char,
974 mut format_args: ...
975 ) {
976 unsafe {
977 use std::ffi::CStr;
978 let file = String::from_utf8_lossy(CStr::from_ptr(file).to_bytes());
979 let function = String::from_utf8_lossy(CStr::from_ptr(function).to_bytes());
980 let format = String::from_utf8_lossy(CStr::from_ptr(format).to_bytes());
981 let mut last_m = 0;
983 let formatted: String = format
984 .match_indices("%s")
985 .flat_map(|(m, s)| {
986 let res = [
987 format[last_m..m].to_string(),
988 String::from_utf8_lossy(
989 CStr::from_ptr(format_args.arg::<*const c_char>()).to_bytes(),
990 )
991 .to_string(),
992 ];
993 last_m = m + s.len();
994 res
995 })
996 .collect();
997 trace!("ALSA Error: {err}: {file} ({line}): {function}: {formatted}");
998 }
999 }
1000
1001 unsafe {
1002 snd_lib_error_set_handler(Some(error_handler));
1003 }
1004}