summaryrefslogtreecommitdiff
path: root/cros_alsa/src/control_tlv.rs
diff options
context:
space:
mode:
Diffstat (limited to 'cros_alsa/src/control_tlv.rs')
-rw-r--r--cros_alsa/src/control_tlv.rs313
1 files changed, 0 insertions, 313 deletions
diff --git a/cros_alsa/src/control_tlv.rs b/cros_alsa/src/control_tlv.rs
deleted file mode 100644
index e1f35510..00000000
--- a/cros_alsa/src/control_tlv.rs
+++ /dev/null
@@ -1,313 +0,0 @@
-// Copyright 2020 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-//! `ControlTLV` supports read and write of the alsa TLV byte controls
-//! Users can obtain a ControlTLV by Card::control_tlv_by_name().
-//! # Examples
-//! This is an example of how to use a `TLV`.
-//!
-//! ```
-//! use std::assert_eq;
-//! use std::convert::TryFrom;
-//! use std::error::Error;
-//!
-//! use cros_alsa::{TLV, ControlTLVError};
-//! use cros_alsa::elem::Elem;
-//!
-//! type Result<T> = std::result::Result<T, ControlTLVError>;
-//!
-//! let mut tlv = TLV::new(0, vec![1,2,3,4]);
-//! assert_eq!(4, tlv.len());
-//! assert_eq!(0, tlv.tlv_type());
-//! assert_eq!(2, tlv[1]);
-//! tlv[1] = 8;
-//! assert_eq!(vec![1,8,3,4], tlv.value().to_vec());
-//! assert_eq!(vec![0,16,1,8,3,4], Into::<Vec<u32>>::into(tlv));
-//!
-//! ```
-
-use std::{
- convert::TryFrom,
- fmt,
- ops::{Index, IndexMut},
- slice::SliceIndex,
-};
-use std::{error, mem::size_of};
-
-use remain::sorted;
-
-use crate::control_primitive::{self, Ctl, ElemId, ElemInfo, ElemType};
-
-/// The Result type of cros-alsa::control.
-pub type Result<T> = std::result::Result<T, Error>;
-
-#[sorted]
-#[derive(Debug, PartialEq)]
-/// Possible errors that can occur in cros-alsa::control.
-pub enum Error {
- /// Failed to call AlsaControlAPI.
- AlsaControlAPI(control_primitive::Error),
- /// Failed to convert buffer to TLV struct.
- InvalidTLV,
- /// ElemInfo::count() is not multiple of size_of::<u32>.
- InvalidTLVSize(String, usize),
- /// ElemInfo::elem_type() is not ElemType::Bytes.
- InvalidTLVType(String, ElemType),
- /// The control is not readable.
- TLVNotReadable,
- /// The control is not writeable.
- TLVNotWritable,
- /// Failed to call snd_ctl_elem_tlv_read.
- TLVReadFailed(i32),
- /// Failed to call snd_ctl_elem_tlv_write.
- TVLWriteFailed(i32),
-}
-
-impl error::Error for Error {}
-
-impl From<control_primitive::Error> for Error {
- fn from(err: control_primitive::Error) -> Error {
- Error::AlsaControlAPI(err)
- }
-}
-
-impl fmt::Display for Error {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- use Error::*;
- match self {
- AlsaControlAPI(e) => write!(f, "{}", e),
- InvalidTLV => write!(f, "failed to convert to TLV"),
- InvalidTLVSize(name, elem_size) => write!(
- f,
- "ElemInfo::size() of {} should be multiple of size_of::<u32>, get: {}",
- name, elem_size
- ),
- InvalidTLVType(name, elem_type) => write!(
- f,
- "invalid ElemInfo::elem_type() of {}: expect: {}, get: {}",
- name,
- ElemType::Bytes,
- elem_type
- ),
- TLVNotReadable => write!(f, "the control is not readable."),
- TLVNotWritable => write!(f, "the control is not writable."),
- TLVReadFailed(rc) => write!(f, "snd_ctl_elem_tlv_read failed: {}", rc),
- TVLWriteFailed(rc) => write!(f, "snd_ctl_elem_tlv_write failed: {}", rc),
- }
- }
-}
-
-/// TLV struct represents the TLV data to be read from
-/// or write to an alsa TLV byte control.
-#[derive(Debug)]
-pub struct TLV {
- /// data[Self::TYPE_OFFSET] contains the tlv type.
- /// data[Self::LEN_OFFSET] contains the length of the value in bytes.
- /// data[Self::VALUE_OFFSET..] contains the data.
- data: Vec<u32>,
-}
-
-impl TLV {
- const TYPE_OFFSET: usize = 0;
- const LEN_OFFSET: usize = 1;
- const VALUE_OFFSET: usize = 2;
- const TLV_HEADER_SIZE_BYTES: usize = Self::VALUE_OFFSET * size_of::<u32>();
-
- /// Initializes a `TLV` by giving the tlv type and tlv value.
- pub fn new(tlv_type: u32, tlv_value: Vec<u32>) -> Self {
- let mut data = vec![0; 2];
- data[Self::TYPE_OFFSET] = tlv_type;
- data[Self::LEN_OFFSET] = (tlv_value.len() * size_of::<u32>()) as u32;
- data.extend(tlv_value.iter());
- Self { data }
- }
-
- /// Returns the type of the tlv.
- pub fn tlv_type(&self) -> u32 {
- self.data[Self::TYPE_OFFSET]
- }
-
- /// Returns the length of the tlv value in dword.
- pub fn len(&self) -> usize {
- self.data[Self::LEN_OFFSET] as usize / size_of::<u32>()
- }
-
- /// Returns whether the tlv value is empty.
- pub fn is_empty(&self) -> bool {
- self.data[Self::LEN_OFFSET] == 0
- }
-
- /// Returns the tlv value in slice.
- pub fn value(&self) -> &[u32] {
- &self.data[Self::VALUE_OFFSET..]
- }
-}
-
-impl<I: SliceIndex<[u32]>> Index<I> for TLV {
- type Output = I::Output;
- #[inline]
- fn index(&self, index: I) -> &Self::Output {
- &self.data[Self::VALUE_OFFSET..][index]
- }
-}
-
-impl<I: SliceIndex<[u32]>> IndexMut<I> for TLV {
- #[inline]
- fn index_mut(&mut self, index: I) -> &mut Self::Output {
- &mut self.data[Self::VALUE_OFFSET..][index]
- }
-}
-
-impl TryFrom<Vec<u32>> for TLV {
- type Error = Error;
-
- /// Constructs a TLV from a vector with the following alsa tlv header validation:
- /// 1 . tlv_buf[Self::LEN_OFFSET] should be multiple of size_of::<u32>
- /// 2 . tlv_buf[Self::LEN_OFFSET] is the length of tlv value in byte and
- /// should be less than the buffer length * size_of::<u32>.
- fn try_from(data: Vec<u32>) -> Result<Self> {
- if data.len() < 2 {
- return Err(Error::InvalidTLV);
- }
-
- if data[Self::LEN_OFFSET] % size_of::<u32>() as u32 != 0 {
- return Err(Error::InvalidTLV);
- }
-
- if data[Self::LEN_OFFSET] / size_of::<u32>() as u32
- > data[Self::VALUE_OFFSET..].len() as u32
- {
- return Err(Error::InvalidTLV);
- }
-
- Ok(Self { data })
- }
-}
-
-impl Into<Vec<u32>> for TLV {
- /// Returns the raw tlv data buffer (including the tlv header).
- fn into(self) -> Vec<u32> {
- self.data
- }
-}
-
-/// `ControlTLV` supports read and write of the alsa TLV byte controls.
-pub struct ControlTLV<'a> {
- handle: &'a mut Ctl,
- id: ElemId,
-}
-
-impl<'a> ControlTLV<'a> {
- /// Called by `Card` to create a `ControlTLV`.
- pub fn new(handle: &'a mut Ctl, id: ElemId) -> Result<Self> {
- let info = ElemInfo::new(handle, &id)?;
- if info.count() % size_of::<u32>() != 0 {
- return Err(Error::InvalidTLVSize(id.name()?.to_owned(), info.count()));
- }
- match info.elem_type()? {
- ElemType::Bytes => Ok(Self { handle, id }),
- _ => Err(Error::InvalidTLVType(
- id.name()?.to_owned(),
- info.elem_type()?,
- )),
- }
- }
-
- /// Reads data from the byte control by `snd_ctl_elem_tlv_read`
- ///
- /// #
- /// # Errors
- ///
- /// * If it fails to read from the control.
- pub fn load(&mut self) -> Result<TLV> {
- if !ElemInfo::new(self.handle, &self.id)?.tlv_readable() {
- return Err(Error::TLVNotReadable);
- }
-
- let tlv_size = ElemInfo::new(self.handle, &self.id)?.count() + TLV::TLV_HEADER_SIZE_BYTES;
-
- let mut tlv_buf = vec![0; tlv_size / size_of::<u32>()];
- // Safe because handle.as_mut_ptr() is a valid *mut snd_ctl_t, id_as_ptr is valid and
- // tlv_buf.as_mut_ptr() is also valid.
- let rc = unsafe {
- alsa_sys::snd_ctl_elem_tlv_read(
- self.handle.as_mut_ptr(),
- self.id.as_ptr(),
- tlv_buf.as_mut_ptr(),
- tlv_size as u32,
- )
- };
- if rc < 0 {
- return Err(Error::TLVReadFailed(rc));
- }
- Ok(TLV::try_from(tlv_buf)?)
- }
-
- /// Writes to the byte control by `snd_ctl_elem_tlv_write`
- ///
- /// # Results
- ///
- /// * `changed` - false on success.
- /// - true on success when value was changed.
- /// #
- /// # Errors
- ///
- /// * If it fails to write to the control.
- pub fn save(&mut self, tlv: TLV) -> Result<bool> {
- if !ElemInfo::new(self.handle, &self.id)?.tlv_writable() {
- return Err(Error::TLVNotReadable);
- }
- // Safe because handle.as_mut_ptr() is a valid *mut snd_ctl_t, id_as_ptr is valid and
- // tlv.as_mut_ptr() is also valid.
- let rc = unsafe {
- alsa_sys::snd_ctl_elem_tlv_write(
- self.handle.as_mut_ptr(),
- self.id.as_ptr(),
- Into::<Vec<u32>>::into(tlv).as_mut_ptr(),
- )
- };
- if rc < 0 {
- return Err(Error::TVLWriteFailed(rc));
- }
- Ok(rc > 0)
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- #[test]
- fn test_tlv_try_from_raw_vec() {
- let tlv_buf = vec![0, 12, 2, 3, 4];
- assert!(TLV::try_from(tlv_buf).is_ok());
- }
-
- #[test]
- fn test_tlv_length_is_not_multiple_of_sizeof_int() {
- // Invalid tlv length in data[Self::LEN_OFFSET].
- let tlv_buf = vec![0, 1, 2, 3, 4];
- assert_eq!(TLV::try_from(tlv_buf).unwrap_err(), Error::InvalidTLV);
- }
-
- #[test]
- fn test_tlv_length_larger_than_buff_size() {
- // Invalid tlv length in data[Self::LEN_OFFSET].
- let tlv_buf = vec![0, 16, 2, 3, 4];
- assert_eq!(TLV::try_from(tlv_buf).unwrap_err(), Error::InvalidTLV);
- }
-
- #[test]
- fn test_tlv_length_less_than_two() {
- // tlv buffer length < 2
- let tlv_buf = vec![0];
- assert_eq!(TLV::try_from(tlv_buf).unwrap_err(), Error::InvalidTLV);
- }
-
- #[test]
- fn test_tlv_length_equal_two() {
- // tlv buffer size = 2.
- let tlv_buf = vec![0, 0];
- assert!(TLV::try_from(tlv_buf).is_ok());
- }
-}