1use std::sync::Arc;
13
14use parking_lot::RwLock;
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
19pub enum Encoding {
20 I16,
21 I24Packed,
22 I32,
23 Float,
24}
25
26impl Encoding {
27 pub fn bits(self) -> u16 {
31 match self {
32 Self::I16 => 16,
33 Self::I24Packed | Self::I32 | Self::Float => 24,
34 }
35 }
36
37 pub fn bytes(self) -> usize {
39 match self {
40 Self::I16 => 2,
41 Self::I24Packed => 3,
42 Self::I32 | Self::Float => 4,
43 }
44 }
45
46 pub fn aaudio(self) -> i32 {
48 match self {
49 Self::I16 => 1,
50 Self::Float => 2,
51 Self::I24Packed => 3,
52 Self::I32 => 4,
53 }
54 }
55}
56
57#[derive(Debug, Clone, Copy, PartialEq, Eq)]
59pub struct MixerFormat {
60 pub device_id: i32,
62 pub rate: u32,
63 pub channels: u16,
64 pub encoding: Encoding,
65}
66
67pub trait OutputHost: Send + Sync {
71 fn mixer_rate(&self) -> u32;
74 fn offers(&self) -> Vec<MixerFormat>;
78 fn hold(&self, format: MixerFormat) -> bool;
81 fn release(&self);
83}
84
85static HOST: RwLock<Option<Arc<dyn OutputHost>>> = RwLock::new(None);
86
87pub fn set_host(host: Arc<dyn OutputHost>) {
89 *HOST.write() = Some(host);
90}
91
92pub(crate) fn host() -> Option<Arc<dyn OutputHost>> {
93 HOST.read().clone()
94}
95
96pub fn choose(
108 offers: &[MixerFormat],
109 rate: u32,
110 channels: u16,
111 bit_depth: Option<u16>,
112) -> Option<MixerFormat> {
113 let needed = bit_depth.unwrap_or(24);
114 if needed > 24 {
115 return None;
116 }
117 let rank = |e: Encoding| match e {
118 Encoding::I32 => 0,
119 Encoding::I24Packed => 1,
120 Encoding::I16 => 2,
121 Encoding::Float => 3,
122 };
123 offers
124 .iter()
125 .filter(|f| f.rate == rate && f.channels == channels && f.encoding.bits() >= needed)
126 .min_by_key(|f| rank(f.encoding))
127 .copied()
128}
129
130pub fn encode(samples: &[f32], encoding: Encoding, out: &mut [u8]) {
134 match encoding {
135 Encoding::Float => {
136 for (s, o) in samples.iter().zip(out.as_chunks_mut::<4>().0) {
137 o.copy_from_slice(&s.to_ne_bytes());
138 }
139 }
140 Encoding::I16 => {
141 for (s, o) in samples.iter().zip(out.as_chunks_mut::<2>().0) {
142 o.copy_from_slice(&(scale(*s, 15) as i16).to_ne_bytes());
143 }
144 }
145 Encoding::I24Packed => {
146 for (s, o) in samples.iter().zip(out.as_chunks_mut::<3>().0) {
147 let v = scale(*s, 23) as i32;
148 o.copy_from_slice(&v.to_le_bytes()[..3]);
149 }
150 }
151 Encoding::I32 => {
152 for (s, o) in samples.iter().zip(out.as_chunks_mut::<4>().0) {
153 o.copy_from_slice(&(scale(*s, 31) as i32).to_ne_bytes());
154 }
155 }
156 }
157}
158
159fn scale(s: f32, bits: u32) -> i64 {
161 let full = (1i64 << bits) as f64;
162 ((s as f64) * full).round().clamp(-full, full - 1.0) as i64
163}
164
165#[cfg(test)]
166mod tests {
167 use super::*;
168
169 fn offer(rate: u32, channels: u16, encoding: Encoding) -> MixerFormat {
170 MixerFormat {
171 device_id: 7,
172 rate,
173 channels,
174 encoding,
175 }
176 }
177
178 #[test]
179 fn nothing_offered_is_the_mixer() {
180 assert_eq!(choose(&[], 44100, 2, Some(16)), None);
181 }
182
183 #[test]
184 fn only_the_source_rate_and_channels_will_do() {
185 let offers = [
186 offer(48000, 2, Encoding::I24Packed),
187 offer(44100, 1, Encoding::I24Packed),
188 ];
189 assert_eq!(choose(&offers, 44100, 2, Some(16)), None);
190 }
191
192 #[test]
193 fn the_widest_integer_encoding_so_a_deeper_track_still_fits() {
194 let all = [
195 offer(44100, 2, Encoding::I16),
196 offer(44100, 2, Encoding::Float),
197 offer(44100, 2, Encoding::I24Packed),
198 offer(44100, 2, Encoding::I32),
199 ];
200 let chosen = |offers: &[MixerFormat]| choose(offers, 44100, 2, Some(16)).unwrap().encoding;
201 assert_eq!(chosen(&all), Encoding::I32);
202 assert_eq!(chosen(&all[..3]), Encoding::I24Packed);
203 assert_eq!(chosen(&all[..1]), Encoding::I16);
204 }
205
206 #[test]
207 fn a_32_bit_source_is_never_bit_perfect() {
208 let offers = [offer(44100, 2, Encoding::I32)];
209 assert_eq!(choose(&offers, 44100, 2, Some(32)), None);
210 }
211
212 #[test]
213 fn sixteen_bits_cannot_carry_twenty_four() {
214 let offers = [offer(96000, 2, Encoding::I16)];
215 assert_eq!(choose(&offers, 96000, 2, Some(24)), None);
216 }
217
218 #[test]
219 fn a_float_mixer_serves_when_no_integer_one_will() {
220 let offers = [
221 offer(96000, 2, Encoding::I16),
222 offer(96000, 2, Encoding::Float),
223 ];
224 assert_eq!(
225 choose(&offers, 96000, 2, Some(24)).unwrap().encoding,
226 Encoding::Float
227 );
228 }
229
230 #[test]
231 fn a_source_without_a_bit_depth_needs_twenty_four() {
232 let offers = [
233 offer(48000, 2, Encoding::I16),
234 offer(48000, 2, Encoding::I24Packed),
235 ];
236 assert_eq!(
237 choose(&offers, 48000, 2, None).unwrap().encoding,
238 Encoding::I24Packed
239 );
240 assert_eq!(choose(&offers[..1], 48000, 2, None), None);
241 }
242
243 #[test]
244 fn encoding_gives_back_the_integers_the_decoder_scaled() {
245 for &n in &[-8_388_608i32, -1, 0, 1, 4_660_803, 8_388_607] {
246 let s = n as f32 / 8_388_608.0;
247 let mut out = [0u8; 3];
248 encode(&[s], Encoding::I24Packed, &mut out);
249 let back = i32::from_le_bytes([
250 out[0],
251 out[1],
252 out[2],
253 if out[2] & 0x80 != 0 { 0xff } else { 0 },
254 ]);
255 assert_eq!(back, n);
256
257 let mut out = [0u8; 4];
258 encode(&[s], Encoding::I32, &mut out);
259 assert_eq!(i32::from_ne_bytes(out), n << 8);
260 }
261 for &n in &[-32768i16, -1, 0, 1, 12345, 32767] {
262 let mut out = [0u8; 2];
263 encode(&[n as f32 / 32768.0], Encoding::I16, &mut out);
264 assert_eq!(i16::from_ne_bytes(out), n);
265 }
266 }
267
268 #[test]
269 fn full_scale_clamps_rather_than_wraps() {
270 let mut out = [0u8; 2];
271 encode(&[1.0], Encoding::I16, &mut out);
272 assert_eq!(i16::from_ne_bytes(out), i16::MAX);
273 }
274}