1use xuko_core::bytes::Bytes;
4
5pub use std::time::Duration;
6
7pub(crate) fn decode<B: AsRef<[u8]>>(buffer: B) -> Result<impl rodio::Source, AudioError> {
8 let cursor = std::io::BufReader::new(std::io::Cursor::new(buffer.as_ref().to_vec()));
9 let source = rodio::Decoder::try_from(cursor)?;
10 Ok(source)
11}
12
13#[derive(Debug, thiserror::Error)]
15pub enum AudioError {
16 #[error("IO Error: {0}")]
18 IOError(#[from] std::io::Error),
19
20 #[error("Stream error: {0}")]
22 StreamError(#[from] rodio::StreamError),
23
24 #[error("Decoder error: {0}")]
26 DecoderError(#[from] rodio::decoder::DecoderError),
27
28 #[error("Play error: {0}")]
30 PlayError(#[from] rodio::PlayError),
31
32 #[error("Seek error: {0}")]
34 SeekError(#[from] rodio::source::SeekError),
35}
36
37pub struct AudioPlayer {
39 buffer: Bytes,
40}
41
42impl AudioPlayer {
43 pub fn new<B: AsRef<[u8]>>(buffer: B) -> Self {
45 Self {
46 buffer: Bytes::from(buffer),
47 }
48 }
49
50 pub fn spawn(&self, settings: PlaybackSettings) -> Result<AudioSink, AudioError> {
52 AudioSink::new(&self.buffer, settings)
53 }
54}
55
56pub struct AudioSink {
58 sink: rodio::Sink,
59 _stream_handle: rodio::OutputStream,
60}
61
62impl AudioSink {
63 pub(crate) fn new(buffer: &[u8], settings: PlaybackSettings) -> Result<Self, AudioError> {
64 let mut stream_handle = rodio::OutputStreamBuilder::open_default_stream()?;
65 stream_handle.log_on_drop(false);
66
67 let sink = rodio::Sink::connect_new(stream_handle.mixer());
68 sink.append(decode(buffer.to_vec())?);
69 sink.pause();
70 let _ = sink.try_seek(Duration::new(0, 0));
71
72 let s = Self {
73 sink,
74 _stream_handle: stream_handle,
75 };
76 settings.apply(&s);
77
78 Ok(s)
79 }
80
81 pub fn add(&mut self, buffer: &[u8]) -> Result<(), AudioError> {
83 self.sink.append(decode(buffer.to_vec())?);
84 Ok(())
85 }
86
87 pub fn seek(&self, pos: Duration) -> Result<(), AudioError> {
89 self.sink.try_seek(pos).map_err(AudioError::SeekError)
90 }
91
92 pub fn get_pos(&self) -> Duration {
94 self.sink.get_pos()
95 }
96
97 pub fn play(&self) {
99 self.sink.play();
100 }
101
102 pub fn pause(&self) {
104 self.sink.pause();
105 }
106
107 pub fn is_paused(&self) -> bool {
109 self.sink.is_paused()
110 }
111
112 pub fn pause_play(&self) {
114 if self.sink.is_paused() {
115 self.sink.play();
116 } else {
117 self.sink.pause();
118 }
119 }
120
121 pub fn sleep_until_end(&self) {
123 self.sink.sleep_until_end();
124 }
125
126 pub fn volume(&self) -> f32 {
128 Volume::linear_to_decibels(self.sink.volume())
129 }
130
131 pub fn set_volume(&self, value: Volume) -> f32 {
133 let previous = self.volume();
134 self.sink.set_volume(value.to_linear());
135 previous
136 }
137
138 pub fn speed(&self) -> f32 {
140 self.sink.speed()
141 }
142
143 pub fn set_speed(&self, value: f32) -> f32 {
145 let previous = self.speed();
146 self.sink.set_speed(value);
147 previous
148 }
149
150 pub fn stop(&self) {
152 self.sink.stop();
153 }
154}
155
156#[derive(Default, Clone, Copy, PartialEq, PartialOrd)]
158pub enum Volume {
159 #[default]
160 Muted,
162 Decibels(f32),
164}
165
166impl Volume {
167 pub fn linear_to_decibels(x: f32) -> f32 {
169 20.0 * x.abs().log10()
170 }
171
172 pub fn decibels_to_linear(x: f32) -> f32 {
174 10.0f32.powf(x / 20.0)
175 }
176
177 pub fn to_linear(&self) -> f32 {
179 match self {
180 Self::Muted => Self::decibels_to_linear(f32::NEG_INFINITY),
181 Self::Decibels(d) => Self::decibels_to_linear(*d),
182 }
183 }
184}
185
186#[derive(Clone, Copy)]
188pub struct PlaybackSettings {
189 pub volume: Volume,
191 pub speed: f32,
193}
194
195impl PlaybackSettings {
196 pub fn apply(&self, sink: &AudioSink) {
198 sink.set_volume(self.volume);
199 sink.set_speed(self.speed);
200 }
201}
202
203impl Default for PlaybackSettings {
204 fn default() -> Self {
205 Self {
206 volume: Volume::Decibels(0.0),
207 speed: 1.0,
208 }
209 }
210}