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 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        // Convert each combination of values from `bytes_per_sample` and `valid_bits_per_sample`
47        // into a [SampleSize], ignoring any invalid combinations, e.g. when:
48        //     * A value is zero, so [NonZeroU32::new] returns `None`
49        //     * Valid bits per sample is greater than bytes (total bits) per sample, so
50        //       [SampleSize::from_partial_bits] returns `None`.
51        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        // Convert each combination of sample format and [SampleSize] into a [SampleType].
58        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    /// Minimum frequency, in hertz.
133    pub min_frequency: Option<u32>,
134    /// Maximum frequency, in hertz.
135    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    /// Returns the number of channels supported by this ChannelSet.
177    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            // No channel set with two channels
282            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            // No SampleType:Uint8
304            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            // No 48000
322            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}