1 // Copyright 2020 The Chromium OS 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 5 //! `control` module is meant to provide easier to use and more type safe abstractions 6 //! for various alsa mixer controls. 7 //! 8 //! Each mixer control should implement the `Control` trait to allow itself to be created by `Card`. 9 //! Each mixer control could hold `Ctl` as handle and `ElemID` as id and use `#[derive(ControlOps)]` macro 10 //! to generate default load / save implementations of the `ControlOps` trait which allows itself to read and 11 //! write the underlying hardware. 12 //! 13 //! # Examples 14 //! This is an example of how to define a `SwitchControl`. 15 //! 16 //! ``` 17 //! use std::error::Error; 18 //! 19 //! use cros_alsa::{Ctl, ElemId, Control, ControlError, ControlOps}; 20 //! use cros_alsa::elem::Elem; 21 //! 22 //! type Result<T> = std::result::Result<T, ControlError>; 23 //! 24 //! #[derive(ControlOps)] 25 //! pub struct SwitchControl<'a> { 26 //! // Must hold `Ctl` as handle and `ElemID` as id to use `#[derive(ControlOps)]`. 27 //! handle: &'a mut Ctl, 28 //! id: ElemId, 29 //! } 30 //! 31 //! impl<'a> Control<'a> for SwitchControl <'a> { 32 //! type Item = [bool; 1]; 33 //! 34 //! fn new(handle: &'a mut Ctl, id: ElemId) -> Self { 35 //! Self { 36 //! handle, 37 //! id, 38 //! } 39 //! } 40 //! } 41 //! 42 //! impl<'a> SwitchControl<'a> { 43 //! /// Reads the state of a switch type mix control. 44 //! pub fn state(&mut self) -> Result<bool> { 45 //! // Uses ControlOps::load() to read the mixer control. 46 //! let v = self.load()?; 47 //! Ok(v[0]) 48 //! } 49 //! 50 //! /// Updates the control state to true. 51 //! pub fn on(&mut self) -> Result<()> { 52 //! // Uses ControlOps::save() to write the mixer control. 53 //! self.save([true])?; 54 //! Ok(()) 55 //! } 56 //! } 57 //! 58 //! ``` 59 60 use std::error; 61 use std::fmt; 62 63 use cros_alsa_derive::ControlOps; 64 use remain::sorted; 65 66 use crate::control_primitive::{self, Ctl, ElemId, ElemInfo, ElemType}; 67 use crate::elem::{self, Elem}; 68 69 /// The Result type of cros-alsa::control. 70 pub type Result<T> = std::result::Result<T, Error>; 71 72 #[sorted] 73 #[derive(Debug)] 74 /// Possible errors that can occur in cros-alsa::control. 75 pub enum Error { 76 /// Failed to call AlsaControlAPI. 77 AlsaControlAPI(control_primitive::Error), 78 /// Error occurs in Elem. 79 Elem(elem::Error), 80 /// Elem::size() does not match the element count of the mixer control. 81 MismatchElemCount(String, usize, usize), 82 /// Elem::elem_type() does not match the data type of the mixer control. 83 MismatchElemType(String, ElemType, ElemType), 84 } 85 86 impl error::Error for Error {} 87 88 impl From<control_primitive::Error> for Error { from(err: control_primitive::Error) -> Error89 fn from(err: control_primitive::Error) -> Error { 90 Error::AlsaControlAPI(err) 91 } 92 } 93 94 impl From<elem::Error> for Error { from(err: elem::Error) -> Error95 fn from(err: elem::Error) -> Error { 96 Error::Elem(err) 97 } 98 } 99 100 impl fmt::Display for Error { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result101 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 102 use Error::*; 103 match self { 104 AlsaControlAPI(e) => write!(f, "{}", e), 105 Elem(e) => write!(f, "{}", e), 106 MismatchElemCount(name, count, elem_count) => write!( 107 f, 108 "invalid `Control::size()` of {}: expect: {}, get: {}", 109 name, count, elem_count 110 ), 111 MismatchElemType(name, t, elem_type) => write!( 112 f, 113 "invalid `Control::elem_type()` of {}: expect: {}, get: {}", 114 name, t, elem_type 115 ), 116 } 117 } 118 } 119 120 /// Each mixer control should implement the `Control` trait to allow itself to be created by `Card`. 121 pub trait Control<'a>: Sized + 'a { 122 /// The data type of the mixer control. 123 /// Use `ElemType::load()` and `ElemType::save()` to read or write the mixer control. 124 type Item: Elem; 125 126 /// Called by `Self::from(handle: &'a mut Ctl, id: ElemId)` to create a `Control`. new(handle: &'a mut Ctl, id: ElemId) -> Self127 fn new(handle: &'a mut Ctl, id: ElemId) -> Self; 128 /// Called by `Card` to create a `Control`. from(handle: &'a mut Ctl, id: ElemId) -> Result<Self>129 fn from(handle: &'a mut Ctl, id: ElemId) -> Result<Self> { 130 let info = ElemInfo::new(handle, &id)?; 131 if info.elem_type()? != Self::elem_type() { 132 return Err(Error::MismatchElemType( 133 id.name()?.to_owned(), 134 info.elem_type()?, 135 Self::elem_type(), 136 )); 137 } 138 139 if info.count() != Self::size() { 140 return Err(Error::MismatchElemCount( 141 id.name()?.to_owned(), 142 info.count(), 143 Self::size(), 144 )); 145 } 146 147 Ok(Self::new(handle, id)) 148 } 149 /// Called by `Self::from(handle: &'a mut Ctl, id: ElemId)` to validate the data type of a 150 /// `Control`. elem_type() -> ElemType151 fn elem_type() -> ElemType { 152 Self::Item::elem_type() 153 } 154 /// Called by `Self::from(handle: &'a mut Ctl, id: ElemId)` to validate the number of value 155 /// entries of a `Control`. size() -> usize156 fn size() -> usize { 157 Self::Item::size() 158 } 159 } 160 161 /// Each mixer control could implement the `ControlOps` trait to allow itself to read and 162 /// write the underlying hardware`. Users could hold `Ctl` and `ElemID` as `handle` and `id` 163 /// in their control structure and use `#[derive(ControlOps)]` macro to generate default 164 /// load / save implementations. 165 pub trait ControlOps<'a>: Control<'a> { 166 /// Reads the values of the mixer control. load(&mut self) -> Result<<Self as Control<'a>>::Item>167 fn load(&mut self) -> Result<<Self as Control<'a>>::Item>; 168 /// Saves the values to the mixer control. save(&mut self, val: <Self as Control<'a>>::Item) -> Result<bool>169 fn save(&mut self, val: <Self as Control<'a>>::Item) -> Result<bool>; 170 } 171 172 /// `Control` that reads and writes a single integer value entry. 173 /// Since this crate is the `cros_alsa` crate, we replace the `cros_alsa` 174 /// path to `crate` in derive macros by `cros_alsa` attribute. 175 #[derive(ControlOps)] 176 #[cros_alsa(path = "crate")] 177 pub struct IntControl<'a> { 178 handle: &'a mut Ctl, 179 id: ElemId, 180 } 181 182 impl<'a> IntControl<'a> { 183 /// Gets an i32 value from the mixer control. 184 /// 185 /// # Errors 186 /// 187 /// * If it fails to read from the control. get(&mut self) -> Result<i32>188 pub fn get(&mut self) -> Result<i32> { 189 let val = self.load()?; 190 Ok(val[0]) 191 } 192 193 /// Updates an i32 value to the mixer control. 194 /// 195 /// # Errors 196 /// 197 /// * If it fails to write to the control. set(&mut self, val: i32) -> Result<()>198 pub fn set(&mut self, val: i32) -> Result<()> { 199 self.save([val])?; 200 Ok(()) 201 } 202 } 203 204 impl<'a> Control<'a> for IntControl<'a> { 205 type Item = [i32; 1]; new(handle: &'a mut Ctl, id: ElemId) -> Self206 fn new(handle: &'a mut Ctl, id: ElemId) -> Self { 207 Self { handle, id } 208 } 209 } 210 211 /// Stereo Volume Mixer Control 212 /// Since this crate is the `cros_alsa` crate, we replace the `cros_alsa` 213 /// path to `crate` in derive macros by `cros_alsa` attribute. 214 #[derive(ControlOps)] 215 #[cros_alsa(path = "crate")] 216 pub struct StereoVolumeControl<'a> { 217 handle: &'a mut Ctl, 218 id: ElemId, 219 } 220 221 impl<'a> StereoVolumeControl<'a> { 222 /// Reads the left and right volume. 223 /// 224 /// # Errors 225 /// 226 /// * If it fails to read from the control. volume(&mut self) -> Result<(i32, i32)>227 pub fn volume(&mut self) -> Result<(i32, i32)> { 228 let val = self.load()?; 229 Ok((val[0], val[1])) 230 } 231 232 /// Updates the left and right volume. 233 /// 234 /// # Errors 235 /// 236 /// * If it fails to write to the control. set_volume(&mut self, left: i32, right: i32) -> Result<()>237 pub fn set_volume(&mut self, left: i32, right: i32) -> Result<()> { 238 self.save([left, right])?; 239 Ok(()) 240 } 241 } 242 243 impl<'a> Control<'a> for StereoVolumeControl<'a> { 244 type Item = [i32; 2]; new(handle: &'a mut Ctl, id: ElemId) -> Self245 fn new(handle: &'a mut Ctl, id: ElemId) -> Self { 246 Self { handle, id } 247 } 248 } 249 250 /// `Control` that reads and writes a single boolean value entry. 251 /// Since this crate is the `cros_alsa` crate, we replace the `cros_alsa` 252 /// path to `crate` in derive macros by `cros_alsa` attribute. 253 #[derive(ControlOps)] 254 #[cros_alsa(path = "crate")] 255 pub struct SwitchControl<'a> { 256 handle: &'a mut Ctl, 257 id: ElemId, 258 } 259 260 impl<'a> SwitchControl<'a> { 261 /// Reads the state of a switch type mix control. 262 /// 263 /// # Errors 264 /// 265 /// * If it fails to read from the control. state(&mut self) -> Result<bool>266 pub fn state(&mut self) -> Result<bool> { 267 let v = self.load()?; 268 Ok(v[0]) 269 } 270 271 /// Updates the control state to true. 272 /// 273 /// # Errors 274 /// 275 /// * If it fails to write to the control. on(&mut self) -> Result<()>276 pub fn on(&mut self) -> Result<()> { 277 self.save([true])?; 278 Ok(()) 279 } 280 281 /// Updates the control state to false. 282 /// 283 /// # Errors 284 /// 285 /// * If it fails to write to the control. off(&mut self) -> Result<()>286 pub fn off(&mut self) -> Result<()> { 287 self.save([false])?; 288 Ok(()) 289 } 290 } 291 292 impl<'a> Control<'a> for SwitchControl<'a> { 293 type Item = [bool; 1]; new(handle: &'a mut Ctl, id: ElemId) -> Self294 fn new(handle: &'a mut Ctl, id: ElemId) -> Self { 295 Self { handle, id } 296 } 297 } 298