Skip to main content

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