1use crate::format::{Format, SampleSize, SampleType};
6use flex_fuchsia_audio_device as fadevice;
7use flex_fuchsia_hardware_audio as fhaudio;
8use itertools::iproduct;
9use std::num::NonZeroU32;
10
11#[derive(Default, Debug, Clone, PartialEq)]
12pub struct PcmFormatSet {
13 pub channel_sets: Vec<ChannelSet>,
14 pub sample_types: Vec<SampleType>,
15 pub frame_rates: Vec<u32>,
16}
17
18impl PcmFormatSet {
19 pub fn supports(&self, format: &Format) -> bool {
20 let channels_ok = self
21 .channel_sets
22 .iter()
23 .any(|channel_set| channel_set.channels() as u32 == format.channels);
24 let sample_type_ok = self.sample_types.contains(&format.sample_type);
25 let frame_rate_ok = self.frame_rates.contains(&format.frames_per_second);
26 channels_ok && sample_type_ok && frame_rate_ok
27 }
28}
29
30impl TryFrom<fhaudio::PcmSupportedFormats> for PcmFormatSet {
31 type Error = String;
32
33 fn try_from(value: fhaudio::PcmSupportedFormats) -> Result<Self, Self::Error> {
34 let channel_sets = value.channel_sets.ok_or_else(|| "missing channel_sets".to_string())?;
35 let sample_formats =
36 value.sample_formats.ok_or_else(|| "missing sample_formats".to_string())?;
37 let bytes_per_sample =
38 value.bytes_per_sample.ok_or_else(|| "missing bytes_per_sample".to_string())?;
39 let valid_bits_per_sample = value
40 .valid_bits_per_sample
41 .ok_or_else(|| "missing valid_bits_per_sample".to_string())?;
42 let frame_rates = value.frame_rates.ok_or_else(|| "missing frame_rates".to_string())?;
43
44 let channel_sets: Vec<ChannelSet> =
45 channel_sets.into_iter().map(ChannelSet::try_from).collect::<Result<Vec<_>, _>>()?;
46
47 let sample_sizes = iproduct!(bytes_per_sample.iter(), valid_bits_per_sample.iter())
53 .filter_map(|(bytes, valid_bits)| {
54 let total_bits = NonZeroU32::new(*bytes as u32 * 8)?;
55 let valid_bits = NonZeroU32::new(*valid_bits as u32)?;
56 SampleSize::from_partial_bits(valid_bits, total_bits)
57 });
58 let sample_types: Vec<SampleType> = iproduct!(sample_formats, sample_sizes)
60 .map(SampleType::try_from)
61 .collect::<Result<Vec<_>, _>>()?;
62
63 Ok(Self { channel_sets, sample_types, frame_rates })
64 }
65}
66
67impl TryFrom<fhaudio::SupportedFormats> for PcmFormatSet {
68 type Error = String;
69
70 fn try_from(value: fhaudio::SupportedFormats) -> Result<Self, Self::Error> {
71 let pcm_supported_formats = value
72 .pcm_supported_formats
73 .ok_or_else(|| "missing pcm_supported_formats".to_string())?;
74 Self::try_from(pcm_supported_formats)
75 }
76}
77
78impl From<PcmFormatSet> for fhaudio::PcmSupportedFormats {
79 fn from(value: PcmFormatSet) -> Self {
80 let channel_sets = value.channel_sets.into_iter().map(Into::into).collect();
81 let sample_formats = value.sample_types.iter().copied().map(Into::into).collect();
82
83 let sample_sizes: Vec<SampleSize> =
84 value.sample_types.iter().map(|sample_type| sample_type.size()).collect();
85
86 let mut bytes_per_sample: Vec<u8> =
87 sample_sizes.iter().map(|sample_size| sample_size.total_bytes().get() as u8).collect();
88 bytes_per_sample.sort();
89
90 let mut valid_bits_per_sample: Vec<u8> =
91 sample_sizes.iter().map(|sample_size| sample_size.valid_bits().get() as u8).collect();
92 valid_bits_per_sample.sort();
93
94 let mut frame_rates = value.frame_rates;
95 frame_rates.sort();
96
97 Self {
98 channel_sets: Some(channel_sets),
99 sample_formats: Some(sample_formats),
100 bytes_per_sample: Some(bytes_per_sample),
101 valid_bits_per_sample: Some(valid_bits_per_sample),
102 frame_rates: Some(frame_rates),
103 ..Default::default()
104 }
105 }
106}
107
108impl From<PcmFormatSet> for fhaudio::SupportedFormats {
109 fn from(value: PcmFormatSet) -> Self {
110 Self { pcm_supported_formats: Some(value.into()), ..Default::default() }
111 }
112}
113
114impl TryFrom<fadevice::PcmFormatSet> for PcmFormatSet {
115 type Error = String;
116
117 fn try_from(value: fadevice::PcmFormatSet) -> Result<Self, Self::Error> {
118 let channel_sets = value.channel_sets.ok_or_else(|| "missing channel_sets".to_string())?;
119 let sample_types = value.sample_types.ok_or_else(|| "missing sample_types".to_string())?;
120 let frame_rates = value.frame_rates.ok_or_else(|| "missing frame_rates".to_string())?;
121
122 let channel_sets: Vec<ChannelSet> =
123 channel_sets.into_iter().map(ChannelSet::try_from).collect::<Result<Vec<_>, _>>()?;
124 let sample_types: Vec<SampleType> =
125 sample_types.into_iter().map(SampleType::try_from).collect::<Result<Vec<_>, _>>()?;
126
127 Ok(Self { channel_sets, sample_types, frame_rates })
128 }
129}
130
131#[derive(Default, Debug, Clone, PartialEq)]
132pub struct ChannelAttributes {
133 pub min_frequency: Option<u32>,
135 pub max_frequency: Option<u32>,
137}
138
139impl From<fadevice::ChannelAttributes> for ChannelAttributes {
140 fn from(value: fadevice::ChannelAttributes) -> Self {
141 Self { min_frequency: value.min_frequency, max_frequency: value.max_frequency }
142 }
143}
144
145impl From<ChannelAttributes> for fadevice::ChannelAttributes {
146 fn from(value: ChannelAttributes) -> Self {
147 fadevice::ChannelAttributes {
148 min_frequency: value.min_frequency,
149 max_frequency: value.max_frequency,
150 ..Default::default()
151 }
152 }
153}
154
155impl From<fhaudio::ChannelAttributes> for ChannelAttributes {
156 fn from(value: fhaudio::ChannelAttributes) -> Self {
157 Self { min_frequency: value.min_frequency, max_frequency: value.max_frequency }
158 }
159}
160
161impl From<ChannelAttributes> for fhaudio::ChannelAttributes {
162 fn from(value: ChannelAttributes) -> Self {
163 Self {
164 min_frequency: value.min_frequency,
165 max_frequency: value.max_frequency,
166 ..Default::default()
167 }
168 }
169}
170
171#[derive(Default, Debug, Clone, PartialEq)]
172pub struct ChannelSet {
173 pub attributes: Vec<ChannelAttributes>,
174}
175
176impl ChannelSet {
177 pub fn channels(&self) -> usize {
179 self.attributes.len()
180 }
181}
182
183impl TryFrom<Vec<ChannelAttributes>> for ChannelSet {
184 type Error = String;
185
186 fn try_from(value: Vec<ChannelAttributes>) -> Result<Self, Self::Error> {
187 if value.is_empty() {
188 return Err("channel attributes must contain at least one entry".to_string());
189 }
190 Ok(Self { attributes: value })
191 }
192}
193
194impl TryFrom<fadevice::ChannelSet> for ChannelSet {
195 type Error = String;
196
197 fn try_from(value: fadevice::ChannelSet) -> Result<Self, Self::Error> {
198 let attributes: Vec<ChannelAttributes> = value
199 .attributes
200 .ok_or_else(|| "missing attributes".to_string())?
201 .into_iter()
202 .map(Into::into)
203 .collect();
204 Self::try_from(attributes)
205 }
206}
207
208impl From<ChannelSet> for fadevice::ChannelSet {
209 fn from(value: ChannelSet) -> Self {
210 Self {
211 attributes: Some(value.attributes.into_iter().map(Into::into).collect()),
212 ..Default::default()
213 }
214 }
215}
216
217impl TryFrom<fhaudio::ChannelSet> for ChannelSet {
218 type Error = String;
219
220 fn try_from(value: fhaudio::ChannelSet) -> Result<Self, Self::Error> {
221 let attributes: Vec<ChannelAttributes> = value
222 .attributes
223 .ok_or_else(|| "missing attributes".to_string())?
224 .into_iter()
225 .map(Into::into)
226 .collect();
227 Self::try_from(attributes)
228 }
229}
230
231impl From<ChannelSet> for fhaudio::ChannelSet {
232 fn from(value: ChannelSet) -> Self {
233 Self {
234 attributes: Some(value.attributes.into_iter().map(Into::into).collect()),
235 ..Default::default()
236 }
237 }
238}
239
240#[cfg(test)]
241pub mod test {
242 use super::*;
243 use test_case::test_case;
244
245 #[test_case(
246 PcmFormatSet {
247 channel_sets: vec![ChannelSet::try_from(vec![
248 ChannelAttributes::default(),
249 ChannelAttributes::default(),
250 ])
251 .unwrap()],
252 sample_types: vec![SampleType::Uint8],
253 frame_rates: vec![48000],
254 };
255 "exact"
256 )]
257 #[test_case(
258 PcmFormatSet {
259 channel_sets: vec![
260 ChannelSet::try_from(vec![
261 ChannelAttributes::default(),
262 ]).unwrap(),
263 ChannelSet::try_from(vec![
264 ChannelAttributes::default(),
265 ChannelAttributes::default(),
266 ]).unwrap(),
267 ],
268 sample_types: vec![SampleType::Uint8, SampleType::Int16],
269 frame_rates: vec![16000, 22050, 32000, 44100, 48000, 88200, 96000],
270 };
271 "multiple"
272 )]
273 fn test_pcm_format_set_supports(format_set: PcmFormatSet) {
274 let format =
275 Format { frames_per_second: 48000, sample_type: SampleType::Uint8, channels: 2 };
276 assert!(format_set.supports(&format));
277 }
278
279 #[test_case(PcmFormatSet::default(); "empty set")]
280 #[test_case(
281 PcmFormatSet {
282 channel_sets: vec![
284 ChannelSet::try_from(vec![
285 ChannelAttributes::default(),
286 ]).unwrap(),
287 ],
288 sample_types: vec![SampleType::Uint8, SampleType::Int16],
289 frame_rates: vec![16000, 22050, 32000, 44100, 48000, 88200, 96000],
290 };
291 "missing channel set"
292 )]
293 #[test_case(
294 PcmFormatSet {
295 channel_sets: vec![
296 ChannelSet::try_from(vec![
297 ChannelAttributes::default(),
298 ]).unwrap(),
299 ChannelSet::try_from(vec![
300 ChannelAttributes::default(),
301 ChannelAttributes::default(),
302 ]).unwrap(),
303 ],
304 sample_types: vec![SampleType::Int16],
306 frame_rates: vec![16000, 22050, 32000, 44100, 48000, 88200, 96000],
307 };
308 "missing sample type"
309 )]
310 #[test_case(
311 PcmFormatSet {
312 channel_sets: vec![
313 ChannelSet::try_from(vec![
314 ChannelAttributes::default(),
315 ]).unwrap(),
316 ChannelSet::try_from(vec![
317 ChannelAttributes::default(),
318 ChannelAttributes::default(),
319 ]).unwrap(),
320 ],
321 sample_types: vec![SampleType::Uint8, SampleType::Int16],
322 frame_rates: vec![16000, 22050, 32000, 44100, 88200, 96000],
324 };
325 "missing frame rate"
326 )]
327 fn test_pcm_format_set_does_not_support(format_set: PcmFormatSet) {
328 let format =
329 Format { frames_per_second: 48000, sample_type: SampleType::Uint8, channels: 2 };
330 assert!(!format_set.supports(&format));
331 }
332
333 #[test]
334 fn test_pcm_format_set_from_hw_supported_formats() {
335 let hw_supported_formats = fhaudio::SupportedFormats {
336 pcm_supported_formats: Some(fhaudio::PcmSupportedFormats {
337 channel_sets: Some(vec![
338 fhaudio::ChannelSet {
339 attributes: Some(vec![fhaudio::ChannelAttributes::default()]),
340 ..Default::default()
341 },
342 fhaudio::ChannelSet {
343 attributes: Some(vec![
344 fhaudio::ChannelAttributes::default(),
345 fhaudio::ChannelAttributes::default(),
346 ]),
347 ..Default::default()
348 },
349 ]),
350 sample_formats: Some(vec![fhaudio::SampleFormat::PcmSigned]),
351 bytes_per_sample: Some(vec![2]),
352 valid_bits_per_sample: Some(vec![16]),
353 frame_rates: Some(vec![16000, 22050, 32000, 44100, 48000, 88200, 96000]),
354 ..Default::default()
355 }),
356 ..Default::default()
357 };
358 let format_set = PcmFormatSet {
359 channel_sets: vec![
360 ChannelSet::try_from(vec![ChannelAttributes::default()]).unwrap(),
361 ChannelSet::try_from(vec![
362 ChannelAttributes::default(),
363 ChannelAttributes::default(),
364 ])
365 .unwrap(),
366 ],
367 sample_types: vec![SampleType::Int16],
368 frame_rates: vec![16000, 22050, 32000, 44100, 48000, 88200, 96000],
369 };
370 assert_eq!(format_set, PcmFormatSet::try_from(hw_supported_formats).unwrap());
371 }
372}