audio_device/wasapi/
sample.rs

1use std::mem;
2use windows_sys::Windows::Win32::CoreAudio as core;
3use windows_sys::Windows::Win32::Multimedia as mm;
4
5use super::ClientConfig;
6
7/// Trait implemented for types which can be used to feed the output device.
8pub unsafe trait Sample: Copy {
9    /// The mid level (silent) level of a sample.
10    const MID: Self;
11
12    /// Construct a wave format specification compatible with the current sample
13    /// type.
14    fn mix_format(config: ClientConfig) -> mm::WAVEFORMATEXTENSIBLE;
15
16    /// Test if the current sample type is compatible.
17    unsafe fn is_compatible_with(mix_format: *const mm::WAVEFORMATEX) -> bool;
18}
19
20unsafe impl Sample for i16 {
21    const MID: Self = 0;
22
23    fn mix_format(config: ClientConfig) -> mm::WAVEFORMATEXTENSIBLE {
24        let avg_bytes_per_sec =
25            config.channels as u32 * config.sample_rate * mem::size_of::<Self>() as u32;
26        let bits_per_sample = mem::size_of::<Self>() as u16 * 8;
27        let block_align = config.channels as u16 * mem::size_of::<Self>() as u16;
28
29        mm::WAVEFORMATEXTENSIBLE {
30            Format: mm::WAVEFORMATEX {
31                wFormatTag: mm::WAVE_FORMAT_PCM as u16,
32                nChannels: config.channels,
33                nSamplesPerSec: config.sample_rate,
34                nAvgBytesPerSec: avg_bytes_per_sec,
35                nBlockAlign: block_align,
36                wBitsPerSample: bits_per_sample,
37                cbSize: 0,
38            },
39            Samples: mm::WAVEFORMATEXTENSIBLE_0 {
40                wValidBitsPerSample: 0,
41            },
42            dwChannelMask: 0,
43            SubFormat: windows::Guid::zeroed(),
44        }
45    }
46
47    unsafe fn is_compatible_with(mix_format: *const mm::WAVEFORMATEX) -> bool {
48        let bits_per_sample = (*mix_format).wBitsPerSample;
49
50        match (*mix_format).wFormatTag as u32 {
51            mm::WAVE_FORMAT_PCM => {
52                assert!((*mix_format).cbSize == 0);
53                bits_per_sample == 16
54            }
55            _ => false,
56        }
57    }
58}
59
60unsafe impl Sample for f32 {
61    const MID: Self = 0.0;
62
63    fn mix_format(config: ClientConfig) -> mm::WAVEFORMATEXTENSIBLE {
64        let avg_bytes_per_sec =
65            config.channels as u32 * config.sample_rate * mem::size_of::<Self>() as u32;
66        let bits_per_sample = mem::size_of::<Self>() as u16 * 8;
67        let block_align = config.channels as u16 * mem::size_of::<Self>() as u16;
68        let cb_size = mem::size_of::<mm::WAVEFORMATEXTENSIBLE>() as u16
69            - mem::size_of::<mm::WAVEFORMATEX>() as u16;
70
71        mm::WAVEFORMATEXTENSIBLE {
72            Format: mm::WAVEFORMATEX {
73                wFormatTag: core::WAVE_FORMAT_EXTENSIBLE as u16,
74                nChannels: config.channels,
75                nSamplesPerSec: config.sample_rate,
76                nAvgBytesPerSec: avg_bytes_per_sec,
77                nBlockAlign: block_align,
78                wBitsPerSample: bits_per_sample,
79                cbSize: cb_size,
80            },
81            Samples: mm::WAVEFORMATEXTENSIBLE_0 {
82                wValidBitsPerSample: bits_per_sample,
83            },
84            dwChannelMask: 0,
85            SubFormat: mm::KSDATAFORMAT_SUBTYPE_IEEE_FLOAT,
86        }
87    }
88
89    unsafe fn is_compatible_with(mix_format: *const mm::WAVEFORMATEX) -> bool {
90        let bits_per_sample = (*mix_format).wBitsPerSample;
91
92        match (*mix_format).wFormatTag as u32 {
93            core::WAVE_FORMAT_EXTENSIBLE => {
94                debug_assert_eq! {
95                    (*mix_format).cbSize as usize,
96                    mem::size_of::<mm::WAVEFORMATEXTENSIBLE>() - mem::size_of::<mm::WAVEFORMATEX>()
97                };
98
99                let mix_format = mix_format as *const mm::WAVEFORMATEXTENSIBLE;
100                bits_per_sample == 32
101                    && matches!((*mix_format).SubFormat, mm::KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)
102            }
103            _ => false,
104        }
105    }
106}