Skip to main content

fuchsia_audio/
format_set.rs

1// Copyright 2024 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use 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        // Convert each combination of values from `bytes_per_sample` and `valid_bits_per_sample`
48        // into a [SampleSize], ignoring any invalid combinations, e.g. when:
49        //     * A value is zero, so [NonZeroU32::new] returns `None`
50        //     * Valid bits per sample is greater than bytes (total bits) per sample, so
51        //       [SampleSize::from_partial_bits] returns `None`.
52        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        // Convert each combination of sample format and [SampleSize] into a [SampleType].
59        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    /// Minimum frequency, in hertz.
134    pub min_frequency: Option<u32>,
135    /// Maximum frequency, in hertz.
136    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    /// Returns the number of channels supported by this ChannelSet.
178    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            // No channel set with two channels
283            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            // No SampleType:Uint8
305            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            // No 48000
323            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}