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