Skip to main content

thedes_tui_core/audio/device/
native.rs

1use std::{borrow::Cow, fmt, io::Cursor};
2
3use crate::audio::device::{
4    AudioDevice,
5    AudioSinkDevice,
6    CheckPlayStatusError,
7    ClearSinkError,
8    OpenSinkError,
9    PauseSinkError,
10    PlayNowError,
11    ResumeSinkError,
12    SetVolumeError,
13};
14
15pub fn open() -> Box<dyn AudioDevice> {
16    Box::new(NativeAudioDevice { stream: None })
17}
18
19struct NativeAudioDevice {
20    stream: Option<rodio::OutputStream>,
21}
22
23impl AudioDevice for NativeAudioDevice {
24    fn open_sink(&mut self) -> Result<Box<dyn AudioSinkDevice>, OpenSinkError> {
25        let stream = match self.stream.take() {
26            Some(stream) => stream,
27            None => {
28                let mut stream =
29                    rodio::OutputStreamBuilder::open_default_stream()
30                        .map_err(|e| OpenSinkError::Stream(e.to_string()))?;
31                stream.log_on_drop(false);
32                stream
33            },
34        };
35        let sink = rodio::Sink::connect_new(&stream.mixer());
36        self.stream = Some(stream);
37        Ok(Box::new(NativeAudioSinkDevice { inner: sink }))
38    }
39}
40
41impl fmt::Debug for NativeAudioDevice {
42    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
43        f.debug_struct("NativeAudioDevice")
44            .field("stream", &(&self.stream as *const _))
45            .finish()
46    }
47}
48
49struct NativeAudioSinkDevice {
50    inner: rodio::Sink,
51}
52
53impl fmt::Debug for NativeAudioSinkDevice {
54    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55        f.debug_struct("NativeAudioSink")
56            .field("sink", &(&self.inner as *const _))
57            .finish()
58    }
59}
60
61impl AudioSinkDevice for NativeAudioSinkDevice {
62    fn play_now(
63        &mut self,
64        bytes: Cow<'static, [u8]>,
65    ) -> Result<(), PlayNowError> {
66        let reader = Cursor::new(bytes);
67        let source = rodio::Decoder::try_from(reader)
68            .map_err(|e| PlayNowError::Decode(e.to_string()))?;
69
70        self.inner.clear();
71        self.inner.append(source);
72        self.inner.play();
73
74        Ok(())
75    }
76
77    fn set_volume(&mut self, volume: f32) -> Result<(), SetVolumeError> {
78        self.inner.set_volume(volume);
79        Ok(())
80    }
81
82    fn pause(&mut self) -> Result<(), PauseSinkError> {
83        self.inner.pause();
84        Ok(())
85    }
86
87    fn resume(&mut self) -> Result<(), ResumeSinkError> {
88        self.inner.play();
89        Ok(())
90    }
91
92    fn clear(&mut self) -> Result<(), ClearSinkError> {
93        self.inner.clear();
94        Ok(())
95    }
96
97    fn is_playing(&self) -> Result<bool, CheckPlayStatusError> {
98        Ok(!self.inner.empty())
99    }
100}
101
102impl Drop for NativeAudioSinkDevice {
103    fn drop(&mut self) {
104        self.inner.clear();
105    }
106}