fuchsia_audio_device/
types.rs

1// Copyright 2019 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 fidl_fuchsia_hardware_audio::{PcmFormat, SampleFormat};
6
7use std::result;
8use thiserror::Error;
9
10/// Result type alias for brevity.
11pub type Result<T> = result::Result<T, Error>;
12
13/// The Error type of the fuchsia-audio-device
14#[derive(Error, Debug)]
15pub enum Error {
16    /// The value that was received was out of range
17    #[error("Value was out of range")]
18    OutOfRange,
19
20    /// The header was invalid when parsing a message.
21    #[error("Invalid Header for a message")]
22    InvalidHeader,
23
24    /// Can't encode into a buffer
25    #[error("Encoding error")]
26    Encoding,
27
28    /// Encountered an IO error reading
29    #[error("Encountered an IO error reading from the channel: {}", _0)]
30    PeerRead(zx::Status),
31
32    /// Encountered an IO error writing
33    #[error("Encountered an IO error writing to the channel: {}", _0)]
34    PeerWrite(zx::Status),
35
36    /// Other IO Error
37    #[error("Encountered an IO error: {}", _0)]
38    IOError(zx::Status),
39
40    /// Encountered a FIDL error reading a request
41    #[error("Encountered an error on a RequestStream: {}", _0)]
42    RequestStreamError(#[from] fidl::Error),
43
44    /// Peer performed an disallowed action and the server will close
45    #[error("Peer performed an invalid action: {}", _0)]
46    PeerError(String),
47
48    /// Action tried in an invalid state
49    #[error("Tried to do an action in an invalid state")]
50    InvalidState,
51
52    /// Responder doesn't have a channel
53    #[error("No channel found for reply")]
54    NoChannel,
55
56    /// When a message hasn't been implemented yet, the parser will return this.
57    #[error("Message has not been implemented yet")]
58    UnimplementedMessage,
59
60    /// An argument is invalid.
61    #[error("Invalid argument")]
62    InvalidArgs,
63
64    #[doc(hidden)]
65    #[error("__Nonexhaustive error should never be created.")]
66    __Nonexhaustive,
67}
68
69#[derive(Debug, PartialEq, Clone)]
70pub enum AudioSampleFormat {
71    Eight { unsigned: bool },
72    Sixteen { unsigned: bool, invert_endian: bool },
73    TwentyFourPacked { unsigned: bool, invert_endian: bool },
74    TwentyIn32 { unsigned: bool, invert_endian: bool },
75    TwentyFourIn32 { unsigned: bool, invert_endian: bool },
76    ThirtyTwo { unsigned: bool, invert_endian: bool },
77    Float { invert_endian: bool },
78}
79
80impl AudioSampleFormat {
81    fn is_unsigned(&self) -> bool {
82        use AudioSampleFormat::*;
83        match self {
84            Eight { unsigned }
85            | Sixteen { unsigned, .. }
86            | TwentyFourPacked { unsigned, .. }
87            | TwentyIn32 { unsigned, .. }
88            | TwentyFourIn32 { unsigned, .. }
89            | ThirtyTwo { unsigned, .. } => *unsigned,
90            Float { .. } => false,
91        }
92    }
93}
94
95/// Constructs a AudioSampleFormat from a fidl_fuchsia_hardware_audio::SampleFormat.
96impl From<PcmFormat> for AudioSampleFormat {
97    fn from(v: PcmFormat) -> Self {
98        if let SampleFormat::PcmFloat = v.sample_format {
99            if v.bytes_per_sample == 32 && v.valid_bits_per_sample == 32 {
100                AudioSampleFormat::Float { invert_endian: false }
101            } else {
102                panic!("audio sample format not supported");
103            }
104        } else {
105            let is_unsigned = v.sample_format == SampleFormat::PcmUnsigned;
106            match v.bytes_per_sample {
107                1u8 => {
108                    assert_eq!(v.valid_bits_per_sample, 8u8);
109                    AudioSampleFormat::Eight { unsigned: is_unsigned }
110                }
111                2u8 => {
112                    assert_eq!(v.valid_bits_per_sample, 16u8);
113                    AudioSampleFormat::Sixteen { unsigned: is_unsigned, invert_endian: false }
114                }
115                3u8 => {
116                    assert_eq!(v.valid_bits_per_sample, 24u8);
117                    AudioSampleFormat::TwentyFourPacked {
118                        unsigned: is_unsigned,
119                        invert_endian: false,
120                    }
121                }
122                4u8 => match v.valid_bits_per_sample {
123                    20u8 => AudioSampleFormat::TwentyIn32 {
124                        unsigned: is_unsigned,
125                        invert_endian: false,
126                    },
127                    24u8 => AudioSampleFormat::TwentyFourIn32 {
128                        unsigned: is_unsigned,
129                        invert_endian: false,
130                    },
131                    32u8 => {
132                        AudioSampleFormat::ThirtyTwo { unsigned: is_unsigned, invert_endian: false }
133                    }
134                    _ => panic!(
135                        "audio valid bits per sample {:?} not supported",
136                        v.valid_bits_per_sample
137                    ),
138                },
139                _ => panic!("audio bytes per samples {:?} not supported", v.bytes_per_sample),
140            }
141        }
142    }
143}
144
145impl AudioSampleFormat {
146    /// Compute the size of an audio frame based on the sample format.
147    /// Returns Err(OutOfRange) in the case where it cannot be computed
148    /// (bad channel count, bad sample format)
149    pub fn compute_frame_size(&self, channels: usize) -> Result<usize> {
150        let bytes_per_channel = match self {
151            AudioSampleFormat::Eight { .. } => 1,
152            AudioSampleFormat::Sixteen { .. } => 2,
153            AudioSampleFormat::TwentyFourPacked { .. } => 3,
154            AudioSampleFormat::TwentyIn32 { .. }
155            | AudioSampleFormat::TwentyFourIn32 { .. }
156            | AudioSampleFormat::ThirtyTwo { .. }
157            | AudioSampleFormat::Float { .. } => 4,
158        };
159        Ok(channels * bytes_per_channel)
160    }
161}
162
163impl std::fmt::Display for AudioSampleFormat {
164    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
165        if self.is_unsigned() {
166            f.write_str("u")?;
167        } else {
168            f.write_str("i")?;
169        }
170        use AudioSampleFormat::*;
171        match self {
172            Eight { .. } => f.write_str("8"),
173            Sixteen { .. } => f.write_str("16"),
174            TwentyFourPacked { .. } => f.write_str("24p"),
175            TwentyIn32 { .. } => f.write_str("20(32)"),
176            TwentyFourIn32 { .. } => f.write_str("24(32)"),
177            ThirtyTwo { .. } => f.write_str("32"),
178            Float { .. } => f.write_str("float"),
179        }
180    }
181}