dango_core/music_player/
music_output.rs

1use std::result;
2
3use symphonia::core::audio::{AudioBufferRef, SignalSpec, RawSample, SampleBuffer};
4use symphonia::core::conv::{ConvertibleSample, IntoSample};
5use symphonia::core::units::Duration;
6
7use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
8use cpal::{self, SizedSample};
9
10use rb::*;
11
12pub trait AudioStream {
13    fn write(&mut self, decoded: AudioBufferRef<'_>) -> Result<()>;
14    fn flush(&mut self);
15}
16
17#[derive(Debug)]
18pub enum AudioOutputError {
19    OpenStreamError,
20    PlayStreamError,
21    StreamClosedError,
22}
23
24pub type Result<T> = result::Result<T, AudioOutputError>;
25
26pub trait OutputSample: SizedSample + IntoSample<f64> +cpal::Sample + ConvertibleSample + RawSample + std::marker::Send + 'static {}
27
28pub struct AudioOutput<T>
29where T: OutputSample,
30{
31    ring_buf_producer: rb::Producer<T>,
32    sample_buf: SampleBuffer<T>,
33    stream: cpal::Stream,
34    resampler: Option<T>,
35}
36impl OutputSample for i8 {}
37impl OutputSample for i16 {}
38impl OutputSample for i32 {}
39//impl OutputSample for i64 {}
40impl OutputSample for u8 {}
41impl OutputSample for u16 {}
42impl OutputSample for u32 {}
43//impl OutputSample for u64 {}
44impl OutputSample for f32 {}
45impl OutputSample for f64 {}
46//create a new trait with functions, then impl that somehow
47
48pub fn open_stream(spec: SignalSpec, duration: Duration) -> Result<Box<dyn AudioStream>> {
49        let host = cpal::default_host();
50        
51        // Uses default audio device
52        let device = match host.default_output_device() {
53            Some(device) => device,
54            _ => return Err(AudioOutputError::OpenStreamError),
55        };
56        
57        let config = match device.default_output_config() {
58            Ok(config) => config,
59            Err(err) => return Err(AudioOutputError::OpenStreamError),
60        };
61        
62        return match config.sample_format(){
63            cpal::SampleFormat::I8 => AudioOutput::<i8>::create_stream(spec, &device, &config.into(), duration),
64            cpal::SampleFormat::I16 => AudioOutput::<i16>::create_stream(spec, &device, &config.into(), duration),
65            cpal::SampleFormat::I32 => AudioOutput::<i32>::create_stream(spec, &device, &config.into(), duration),
66            //cpal::SampleFormat::I64 => AudioOutput::<i64>::create_stream(spec, &device, &config.into(), duration),
67            cpal::SampleFormat::U8 => AudioOutput::<u8>::create_stream(spec, &device, &config.into(), duration),
68            cpal::SampleFormat::U16 => AudioOutput::<u16>::create_stream(spec, &device, &config.into(), duration),
69            cpal::SampleFormat::U32 => AudioOutput::<u32>::create_stream(spec, &device, &config.into(), duration),
70            //cpal::SampleFormat::U64 => AudioOutput::<u64>::create_stream(spec, &device, &config.into(), duration),
71            cpal::SampleFormat::F32 => AudioOutput::<f32>::create_stream(spec, &device, &config.into(), duration),
72            cpal::SampleFormat::F64 => AudioOutput::<f64>::create_stream(spec, &device, &config.into(), duration),
73            _ => todo!(),
74        };
75    }
76
77
78impl<T: OutputSample> AudioOutput<T> {
79    // Creates the stream (TODO: Merge w/open_stream?)
80    fn create_stream(spec: SignalSpec, device: &cpal::Device, config: &cpal::StreamConfig, duration: Duration) -> Result<Box<dyn AudioStream>> {
81        let num_channels = config.channels as usize;
82        
83        // Ring buffer is created with 200ms audio capacity
84        let ring_len = ((200 * config.sample_rate.0 as usize) / 1000) * num_channels;
85        let ring_buf= rb::SpscRb::new(ring_len);
86        
87        let ring_buf_producer = ring_buf.producer();
88        let ring_buf_consumer = ring_buf.consumer();
89        
90        let stream_result = device.build_output_stream(
91            config, 
92            move |data: &mut [T], _: &cpal::OutputCallbackInfo| {
93                // Writes samples in the ring buffer to the audio output
94                let written = ring_buf_consumer.read(data).unwrap_or(0);
95                
96                // Mutes non-written samples
97                data[written..].iter_mut().for_each(|sample| *sample = T::MID);
98            },
99            //TODO: Handle error here properly
100            move |err| println!("Yeah we erroring out here"),
101            None
102        );
103        
104        if let Err(err) = stream_result {
105            return Err(AudioOutputError::OpenStreamError);
106        }
107        
108        let stream = stream_result.unwrap();
109        
110        //Start output stream
111        if let Err(err) = stream.play() {
112            return Err(AudioOutputError::PlayStreamError);
113        }
114        
115        let sample_buf = SampleBuffer::<T>::new(duration, spec);
116        
117        let resampler: Option<T> = None;
118        
119        Ok(Box::new(AudioOutput { ring_buf_producer, sample_buf, stream, resampler}))
120    }
121}
122
123impl<T: OutputSample> AudioStream for AudioOutput<T> {
124    // Writes given samples to ring buffer
125    fn write(&mut self, decoded: AudioBufferRef<'_>) -> Result<()> {
126        if decoded.frames() == 0 {
127            return Ok(());
128        }
129        
130        let mut samples: &[T] = if let Some(resampler) = &mut self.resampler {
131            // TODO: implement resampler
132            println!("this should not print");
133            return Ok(())
134        } else {
135            self.sample_buf.copy_interleaved_ref(decoded);
136            self.sample_buf.samples()
137        };
138        
139        // Write samples into ring buffer
140        while let Some(written) = self.ring_buf_producer.write_blocking(samples) {
141            samples = &samples[written..];
142        }
143        
144        Ok(())
145    }
146    
147    // Flushes resampler if needed
148    fn flush(&mut self) {
149        if let Some(resampler) = &mut self.resampler {
150            // TODO: implement resampler
151        }
152        
153        let _ = self.stream.pause();
154    }
155}