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