1use crate::server::Config;
2use eyre::{eyre, Result};
3use serde::{Deserialize, Serialize};
4use std::fmt::{Debug, Formatter};
5use std::path::Path;
6use std::time::Duration;
7
8#[cfg(feature = "rodio")]
9mod rodio;
10
11#[derive(Debug, Copy, Clone, Deserialize, Serialize)]
12#[serde(rename_all = "snake_case")]
13pub enum AudioBackend {
14 None,
15 Inherit,
16 #[cfg(feature = "rodio")]
17 Rodio,
18}
19
20#[derive(Clone)]
21pub enum AudioBuffer {
22 None,
23 #[cfg(feature = "rodio")]
24 Rodio(rodio::Buffer),
25}
26
27pub enum AudioSink {
28 None,
29 #[cfg(feature = "rodio")]
30 Rodio(rodio::Sink),
31}
32
33pub enum AudioDevice {
34 None,
35 #[cfg(feature = "rodio")]
36 Rodio(rodio::Device),
37}
38
39impl AudioDevice {
40 pub fn try_clone(&self) -> Result<Self> {
41 match self {
42 AudioDevice::None => Ok(AudioDevice::None),
43 #[cfg(feature = "rodio")]
44 AudioDevice::Rodio(_) => rodio::Device::new().map(AudioDevice::Rodio),
45 }
46 }
47}
48
49impl Default for AudioBackend {
50 #[inline(always)]
51 fn default() -> Self {
52 AudioBackend::Inherit
53 }
54}
55
56impl AudioBackend {
57 pub fn or(&self, other: &Self) -> Self {
58 if let Self::Inherit = self {
59 *other
60 } else {
61 *self
62 }
63 }
64}
65
66#[derive(Copy, Clone, Deserialize, Serialize)]
67#[serde(untagged)]
68pub enum Volume {
69 Inherit,
70 Value(f32),
71}
72
73impl Default for Volume {
74 #[inline(always)]
75 fn default() -> Self {
76 Volume::Inherit
77 }
78}
79
80impl Debug for Volume {
81 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
82 if let Volume::Value(vol) = self {
83 write!(f, "{vol}")
84 } else {
85 write!(f, "inherit")
86 }
87 }
88}
89
90impl Volume {
91 pub fn and(&self, other: &Self) -> Self {
92 match (self, other) {
93 (&Self::Value(x), &Self::Value(y)) => Self::Value(x * y),
94 (Self::Value(_), _) => *self,
95 (Self::Inherit, _) => *other,
96 }
97 }
98
99 pub fn or(&self, other: &Self) -> Self {
100 if let Self::Inherit = self {
101 *other
102 } else {
103 *self
104 }
105 }
106
107 pub fn value(&self) -> f32 {
108 if let &Self::Value(x) = self {
109 x
110 } else {
111 1.0
112 }
113 }
114}
115
116impl From<f32> for Volume {
117 fn from(v: f32) -> Self {
118 Self::Value(v.max(0.0))
119 }
120}
121
122#[derive(Debug, Copy, Clone, Deserialize, Serialize)]
123#[serde(rename_all = "snake_case")]
124pub enum UseTrigger {
125 Inherit,
126 Yes,
127 No,
128}
129
130impl Default for UseTrigger {
131 #[inline(always)]
132 fn default() -> Self {
133 UseTrigger::Inherit
134 }
135}
136
137impl UseTrigger {
138 pub fn or(&self, other: &Self) -> Self {
139 if let Self::Inherit = self {
140 *other
141 } else {
142 *self
143 }
144 }
145
146 pub fn value(&self) -> bool {
147 !matches!(self, UseTrigger::No)
148 }
149}
150
151#[derive(Debug, Copy, Clone, Deserialize, Serialize)]
152#[serde(rename_all = "snake_case")]
153pub enum TimePrecision {
154 Inherit,
155 RespectIntervals,
156 RespectBoundaries,
157}
158
159impl Default for TimePrecision {
160 #[inline(always)]
161 fn default() -> Self {
162 TimePrecision::Inherit
163 }
164}
165
166impl TimePrecision {
167 pub fn or(&self, other: &Self) -> Self {
168 if let Self::Inherit = self {
169 *other
170 } else {
171 *self
172 }
173 }
174}
175
176#[allow(unused_variables)]
177pub fn audio_from_file(path: &Path, config: &Config) -> Result<AudioBuffer> {
178 match config.audio_backend() {
179 AudioBackend::None => Err(eyre!("Cannot load audio file with backend=None.")),
180 AudioBackend::Inherit => Err(eyre!("Cannot load audio file with backend=Inherit.")),
181 #[cfg(feature = "rodio")]
182 AudioBackend::Rodio => rodio::Buffer::new(path, config).map(AudioBuffer::Rodio),
183 }
184}
185
186impl AudioBuffer {
187 pub fn duration(&self) -> Duration {
188 match self {
189 AudioBuffer::None => Duration::default(),
190 #[cfg(feature = "rodio")]
191 AudioBuffer::Rodio(x) => x.duration(),
192 }
193 }
194
195 pub fn sample_rate(&self) -> u32 {
196 match self {
197 AudioBuffer::None => 0,
198 #[cfg(feature = "rodio")]
199 AudioBuffer::Rodio(x) => x.sample_rate(),
200 }
201 }
202
203 pub fn channels(&self) -> u16 {
204 match self {
205 AudioBuffer::None => 0,
206 #[cfg(feature = "rodio")]
207 AudioBuffer::Rodio(x) => x.channels(),
208 }
209 }
210
211 pub fn interlace(self, other: AudioBuffer) -> Result<AudioBuffer> {
212 match (self, other) {
213 #[cfg(feature = "rodio")]
214 (AudioBuffer::Rodio(x), AudioBuffer::Rodio(y)) => {
215 x.interlace(y).map(AudioBuffer::Rodio)
216 }
217 (_, _) => Err(eyre!("Cannot interlace audio buffers of different types.")),
218 }
219 }
220
221 pub fn drop_last(self) -> Result<AudioBuffer> {
222 match self {
223 AudioBuffer::None => Err(eyre!("Cannot interlace audio buffers of different types.")),
224 #[cfg(feature = "rodio")]
225 AudioBuffer::Rodio(x) => x.drop_last().map(AudioBuffer::Rodio),
226 }
227 }
228}
229
230impl AudioSink {
231 pub fn pause(&mut self) -> Result<()> {
232 match self {
233 AudioSink::None => Err(eyre!("Cannot pause audio sink with backend=None.")),
234 #[cfg(feature = "rodio")]
235 AudioSink::Rodio(sink) => {
236 sink.pause();
237 Ok(())
238 }
239 }
240 }
241
242 #[allow(unused_variables)]
243 pub fn set_volume(&mut self, volume: f32) -> Result<()> {
244 match self {
245 AudioSink::None => Err(eyre!("Cannot pause audio sink with backend=None.")),
246 #[cfg(feature = "rodio")]
247 AudioSink::Rodio(sink) => {
248 sink.set_volume(volume);
249 Ok(())
250 }
251 }
252 }
253
254 pub fn queue(&mut self, buffer: AudioBuffer) -> Result<()> {
255 match (self, buffer) {
256 (AudioSink::None, _) => Err(eyre!("Cannot queue audio on sink=None.")),
257 #[cfg(feature = "rodio")]
258 (AudioSink::Rodio(sink), AudioBuffer::Rodio(buffer)) => {
259 sink.queue(buffer);
260 Ok(())
261 }
262 #[allow(unreachable_patterns)]
263 (_, _) => Err(eyre!("Cannot queue audio on incompatible sink.")),
264 }
265 }
266
267 pub fn repeat(&mut self, buffer: AudioBuffer) -> Result<()> {
268 match (self, buffer) {
269 (AudioSink::None, _) => Err(eyre!("Cannot repeat audio on sink=None.")),
270 #[cfg(feature = "rodio")]
271 (AudioSink::Rodio(sink), AudioBuffer::Rodio(buffer)) => {
272 sink.repeat(buffer);
273 Ok(())
274 }
275 #[allow(unreachable_patterns)]
276 (_, _) => Err(eyre!("Cannot repeat audio on incompatible sink.")),
277 }
278 }
279
280 pub fn play(&mut self) -> Result<()> {
281 match self {
282 AudioSink::None => Err(eyre!("Cannot play audio sink with backend=None.")),
283 #[cfg(feature = "rodio")]
284 AudioSink::Rodio(sink) => {
285 sink.play();
286 Ok(())
287 }
288 }
289 }
290
291 pub fn stop(&mut self) -> Result<()> {
292 match self {
293 AudioSink::None => Err(eyre!("Cannot stop audio sink with backend=None.")),
294 #[cfg(feature = "rodio")]
295 AudioSink::Rodio(sink) => {
296 sink.stop();
297 Ok(())
298 }
299 }
300 }
301
302 pub fn empty(&self) -> Result<bool> {
303 match self {
304 AudioSink::None => Ok(true),
305 #[cfg(feature = "rodio")]
306 AudioSink::Rodio(sink) => Ok(sink.empty()),
307 }
308 }
309
310 pub fn detach(self) -> Result<()> {
311 match self {
312 AudioSink::None => Ok(()),
313 #[cfg(feature = "rodio")]
314 AudioSink::Rodio(sink) => {
315 sink.detach();
316 Ok(())
317 }
318 }
319 }
320}
321
322impl AudioDevice {
323 pub fn new(config: &Config) -> Result<Self> {
324 match config.audio_backend() {
325 AudioBackend::None => Err(eyre!("Cannot obtain audio device with backend=None.")),
326 AudioBackend::Inherit => Err(eyre!("Cannot obtain audio device with backend=None.")),
327 #[cfg(feature = "rodio")]
328 AudioBackend::Rodio => rodio::Device::new().map(Self::Rodio),
329 }
330 }
331
332 pub fn sink(&self) -> Result<AudioSink> {
333 match self {
334 AudioDevice::None => Err(eyre!("Cannot create audio sink with backend=None.")),
335 #[cfg(feature = "rodio")]
336 AudioDevice::Rodio(device) => device.sink().map(AudioSink::Rodio),
337 }
338 }
339}