thedes_tui_core/audio/device/
native.rs1use 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}