rich_sdl2_rust/audio/
spec.rs

1//! Provides tools to make a specification to require what an audio device is.
2
3use bitflags::bitflags;
4use std::{
5    ffi::c_void,
6    marker::PhantomData,
7    os::raw::c_int,
8    sync::{Arc, Mutex},
9};
10use typed_builder::TypedBuilder;
11
12use crate::bind;
13
14use super::format::AudioFormat;
15
16/// A builder to build an information representing what specification is required for an audio device.
17#[derive(TypedBuilder)]
18pub struct AudioSpecBuilder<'callback, T: AudioCallback<'callback>> {
19    #[builder(default = 44100)]
20    sample_freq: u32,
21    #[builder(default = AudioFormat::signed32_lsb())]
22    format: AudioFormat,
23    #[builder(default = 2)]
24    channels: u8,
25    #[builder(default = 4096)]
26    samples: u16,
27    #[builder(default, setter(strip_option))]
28    callback: Option<&'callback mut T>,
29}
30
31/// A type of the callback to interact with the raw audio buffer.
32pub trait AudioCallback<'callback>: FnMut(&mut [u8]) + 'callback {}
33
34/// A specification to require what an audio device is.
35pub struct AudioSpec<'callback, T> {
36    raw: bind::SDL_AudioSpec,
37    _phantom: PhantomData<&'callback mut T>,
38}
39
40impl<T> std::fmt::Debug for AudioSpec<'_, T> {
41    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
42        f.debug_struct("AudioSpec").finish_non_exhaustive()
43    }
44}
45
46impl<'callback, T: AudioCallback<'callback>> AudioSpec<'callback, T> {
47    /// Constructs an audio specification with the optional callback.
48    #[must_use]
49    pub fn new(mut builder: AudioSpecBuilder<'callback, T>) -> Self {
50        Self {
51            raw: bind::SDL_AudioSpec {
52                freq: builder.sample_freq as c_int,
53                format: builder.format.as_raw(),
54                channels: builder.channels,
55                silence: 0,
56                samples: builder.samples,
57                padding: 0,
58                size: 0,
59                callback: builder
60                    .callback
61                    .as_ref()
62                    .map(|_| audio_spec_wrap_handler::<T> as _),
63                userdata: builder
64                    .callback
65                    .map_or(std::ptr::null_mut(), |callback| (callback as *mut T).cast()),
66            },
67            _phantom: PhantomData,
68        }
69    }
70
71    pub(super) fn raw(&self) -> &bind::SDL_AudioSpec {
72        &self.raw
73    }
74
75    pub(super) fn raw_mut(&mut self) -> &mut bind::SDL_AudioSpec {
76        &mut self.raw
77    }
78}
79
80unsafe extern "C" fn audio_spec_wrap_handler<'callback, T: AudioCallback<'callback>>(
81    userdata: *mut c_void,
82    stream: *mut u8,
83    len: c_int,
84) {
85    if userdata.is_null() {
86        return;
87    }
88    let func = &mut *userdata.cast::<T>();
89    let slice = std::slice::from_raw_parts_mut(stream, len as usize);
90    slice.fill(0);
91    func(slice);
92}
93
94bitflags! {
95    /// A flag what component may fallback into an actual audio device.
96    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
97    pub struct FallbackFlag : u32 {
98        /// Allows to fallback frequencies.
99        const FREQUENCY = 1 << 0;
100        /// Allows to fallback a format.
101        const FORMAT = 1 << 0;
102        /// Allows to fallback numbers of channels.
103        const CHANNELS = 1 << 0;
104        /// Allows to fallback sample rates.
105        const SAMPLES = 1 << 0;
106    }
107}