blob: 36f11a397fe2e8b000bbed4d7685b67e9f7f2e20 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use {
fidl_fuchsia_hardware_audio::{PcmFormat, SampleFormat},
fuchsia_zircon as zx,
std::result,
thiserror::Error,
};
/// Result type alias for brevity.
pub type Result<T> = result::Result<T, Error>;
/// The Error type of the fuchsia-audio-device
#[derive(Error, Debug)]
pub enum Error {
/// The value that was received was out of range
#[error("Value was out of range")]
OutOfRange,
/// The header was invalid when parsing a message.
#[error("Invalid Header for a message")]
InvalidHeader,
/// Can't encode into a buffer
#[error("Encoding error")]
Encoding,
/// Encountered an IO error reading
#[error("Encountered an IO error reading from the channel: {}", _0)]
PeerRead(zx::Status),
/// Encountered an IO error writing
#[error("Encountered an IO error writing to the channel: {}", _0)]
PeerWrite(zx::Status),
/// Other IO Error
#[error("Encountered an IO error: {}", _0)]
IOError(zx::Status),
/// Encountered a FIDL error reading a request
#[error("Encountered an error on a RequestStream: {}", _0)]
RequestStreamError(#[from] fidl::Error),
/// Peer performed an disallowed action and the server will close
#[error("Peer performed an invalid action: {}", _0)]
PeerError(String),
/// Action tried in an invalid state
#[error("Tried to do an action in an invalid state")]
InvalidState,
/// Responder doesn't have a channel
#[error("No channel found for reply")]
NoChannel,
/// When a message hasn't been implemented yet, the parser will return this.
#[error("Message has not been implemented yet")]
UnimplementedMessage,
/// An argument is invalid.
#[error("Invalid argument")]
InvalidArgs,
#[doc(hidden)]
#[error("__Nonexhaustive error should never be created.")]
__Nonexhaustive,
}
#[derive(Debug, PartialEq, Clone)]
pub enum AudioSampleFormat {
Eight { unsigned: bool },
Sixteen { unsigned: bool, invert_endian: bool },
TwentyFourPacked { unsigned: bool, invert_endian: bool },
TwentyIn32 { unsigned: bool, invert_endian: bool },
TwentyFourIn32 { unsigned: bool, invert_endian: bool },
ThirtyTwo { unsigned: bool, invert_endian: bool },
Float { invert_endian: bool },
}
impl AudioSampleFormat {
fn is_unsigned(&self) -> bool {
use AudioSampleFormat::*;
match self {
Eight { unsigned }
| Sixteen { unsigned, .. }
| TwentyFourPacked { unsigned, .. }
| TwentyIn32 { unsigned, .. }
| TwentyFourIn32 { unsigned, .. }
| ThirtyTwo { unsigned, .. } => *unsigned,
Float { .. } => false,
}
}
}
/// Constructs a AudioSampleFormat from a fidl_fuchsia_hardware_audio::SampleFormat.
impl From<PcmFormat> for AudioSampleFormat {
fn from(v: PcmFormat) -> Self {
if let SampleFormat::PcmFloat = v.sample_format {
if v.bytes_per_sample == 32 && v.valid_bits_per_sample == 32 {
AudioSampleFormat::Float { invert_endian: false }
} else {
panic!("audio sample format not supported");
}
} else {
let is_unsigned = v.sample_format == SampleFormat::PcmUnsigned;
match v.bytes_per_sample {
1u8 => {
assert_eq!(v.valid_bits_per_sample, 8u8);
AudioSampleFormat::Eight { unsigned: is_unsigned }
}
2u8 => {
assert_eq!(v.valid_bits_per_sample, 16u8);
AudioSampleFormat::Sixteen { unsigned: is_unsigned, invert_endian: false }
}
3u8 => {
assert_eq!(v.valid_bits_per_sample, 24u8);
AudioSampleFormat::TwentyFourPacked {
unsigned: is_unsigned,
invert_endian: false,
}
}
4u8 => match v.valid_bits_per_sample {
20u8 => AudioSampleFormat::TwentyIn32 {
unsigned: is_unsigned,
invert_endian: false,
},
24u8 => AudioSampleFormat::TwentyFourIn32 {
unsigned: is_unsigned,
invert_endian: false,
},
32u8 => {
AudioSampleFormat::ThirtyTwo { unsigned: is_unsigned, invert_endian: false }
}
_ => panic!(
"audio valid bits per sample {:?} not supported",
v.valid_bits_per_sample
),
},
_ => panic!("audio bytes per samples {:?} not supported", v.bytes_per_sample),
}
}
}
}
impl AudioSampleFormat {
/// Compute the size of an audio frame based on the sample format.
/// Returns Err(OutOfRange) in the case where it cannot be computed
/// (bad channel count, bad sample format)
pub fn compute_frame_size(&self, channels: usize) -> Result<usize> {
let bytes_per_channel = match self {
AudioSampleFormat::Eight { .. } => 1,
AudioSampleFormat::Sixteen { .. } => 2,
AudioSampleFormat::TwentyFourPacked { .. } => 3,
AudioSampleFormat::TwentyIn32 { .. }
| AudioSampleFormat::TwentyFourIn32 { .. }
| AudioSampleFormat::ThirtyTwo { .. }
| AudioSampleFormat::Float { .. } => 4,
};
Ok(channels * bytes_per_channel)
}
}
impl std::fmt::Display for AudioSampleFormat {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.is_unsigned() {
f.write_str("u")?;
} else {
f.write_str("i")?;
}
use AudioSampleFormat::*;
match self {
Eight { .. } => f.write_str("8"),
Sixteen { .. } => f.write_str("16"),
TwentyFourPacked { .. } => f.write_str("24p"),
TwentyIn32 { .. } => f.write_str("20(32)"),
TwentyFourIn32 { .. } => f.write_str("24(32)"),
ThirtyTwo { .. } => f.write_str("32"),
Float { .. } => f.write_str("float"),
}
}
}