| 1 | |
| 2 | use crate::alsa; |
| 3 | use super::pcm::Info; |
| 4 | use std::ffi::{CStr, CString}; |
| 5 | use super::Direction; |
| 6 | use super::error::*; |
| 7 | use super::mixer::MilliBel; |
| 8 | use super::Round; |
| 9 | use std::{ptr, mem, fmt, cmp}; |
| 10 | use crate::{Card, poll}; |
| 11 | use std::cell::UnsafeCell; |
| 12 | use libc::{c_uint, c_void, size_t, c_long, c_int, pollfd, c_short}; |
| 13 | |
| 14 | /// We prefer not to allocate for every ElemId, ElemInfo or ElemValue. |
| 15 | /// But we don't know if these will increase in the future or on other platforms. |
| 16 | /// Unfortunately, Rust does not support alloca, so hard-code the sizes for now. |
| 17 | |
| 18 | const ELEM_ID_SIZE: usize = 64; |
| 19 | // const ELEM_VALUE_SIZE: usize = 1224; |
| 20 | // const ELEM_INFO_SIZE: usize = 272; |
| 21 | |
| 22 | /// [snd_ctl_pcm_next_device](https://www.alsa-project.org/alsa-doc/alsa-lib/control_8c.html#accbb0be6e5ca7361ffec0ea304ed1b05) wrapper. |
| 23 | /// Iterate over devices of a card. |
| 24 | pub struct DeviceIter<'a>(&'a Ctl, c_int); |
| 25 | |
| 26 | impl<'a> DeviceIter<'a>{ |
| 27 | pub fn new(ctl: &'a Ctl) -> DeviceIter { |
| 28 | DeviceIter(ctl, -1) |
| 29 | } |
| 30 | } |
| 31 | |
| 32 | impl<'a> Iterator for DeviceIter<'a> { |
| 33 | type Item = c_int; |
| 34 | |
| 35 | fn next(&mut self) -> Option<c_int> { |
| 36 | match acheck!(snd_ctl_pcm_next_device(self.0.0, &mut self.1)) { |
| 37 | Ok(_) if self.1 == -1 => None, |
| 38 | Ok(_) => Some(self.1), |
| 39 | Err(_) => None, |
| 40 | } |
| 41 | } |
| 42 | } |
| 43 | |
| 44 | /// [snd_ctl_t](http://www.alsa-project.org/alsa-doc/alsa-lib/group___control.html) wrapper |
| 45 | pub struct Ctl(*mut alsa::snd_ctl_t); |
| 46 | |
| 47 | unsafe impl Send for Ctl {} |
| 48 | |
| 49 | impl Ctl { |
| 50 | /// Wrapper around open that takes a &str instead of a &CStr |
| 51 | pub fn new(c: &str, nonblock: bool) -> Result<Self> { |
| 52 | Self::open(&CString::new(c).unwrap(), nonblock) |
| 53 | } |
| 54 | |
| 55 | /// Open does not support async mode (it's not very Rustic anyway) |
| 56 | pub fn open(c: &CStr, nonblock: bool) -> Result<Ctl> { |
| 57 | let mut r = ptr::null_mut(); |
| 58 | let flags = if nonblock { 1 } else { 0 }; // FIXME: alsa::SND_CTL_NONBLOCK does not exist in alsa-sys |
| 59 | acheck!(snd_ctl_open(&mut r, c.as_ptr(), flags)).map(|_| Ctl(r)) |
| 60 | } |
| 61 | |
| 62 | pub fn from_card(c: &Card, nonblock: bool) -> Result<Ctl> { |
| 63 | let s = format!("hw: {}" , c.get_index()); |
| 64 | Ctl::open(&CString::new(s).unwrap(), nonblock) |
| 65 | } |
| 66 | |
| 67 | pub fn card_info(&self) -> Result<CardInfo> { CardInfo::new().and_then(|c| |
| 68 | acheck!(snd_ctl_card_info(self.0, c.0)).map(|_| c)) } |
| 69 | |
| 70 | pub fn wait(&self, timeout_ms: Option<u32>) -> Result<bool> { |
| 71 | acheck!(snd_ctl_wait(self.0, timeout_ms.map(|x| x as c_int).unwrap_or(-1))).map(|i| i == 1) } |
| 72 | |
| 73 | pub fn get_db_range(&self, id: &ElemId) -> Result<(MilliBel, MilliBel)> { |
| 74 | let mut min: c_long = 0; |
| 75 | let mut max: c_long = 0; |
| 76 | acheck!(snd_ctl_get_dB_range(self.0, elem_id_ptr(id), &mut min, &mut max)) |
| 77 | .map(|_| (MilliBel(min as i64), MilliBel(max as i64))) |
| 78 | } |
| 79 | |
| 80 | pub fn convert_to_db(&self, id: &ElemId, volume: i64) -> Result<MilliBel> { |
| 81 | let mut m: c_long = 0; |
| 82 | acheck!(snd_ctl_convert_to_dB(self.0, elem_id_ptr(id), volume as c_long, &mut m)) |
| 83 | .map(|_| (MilliBel(m as i64))) |
| 84 | } |
| 85 | |
| 86 | pub fn convert_from_db(&self, id: &ElemId, mb: MilliBel, dir: Round) -> Result<i64> { |
| 87 | let mut m: c_long = 0; |
| 88 | acheck!(snd_ctl_convert_from_dB(self.0, elem_id_ptr(id), mb.0 as c_long, &mut m, dir as c_int)) |
| 89 | .map(|_| m as i64) |
| 90 | } |
| 91 | |
| 92 | pub fn elem_read(&self, val: &mut ElemValue) -> Result<()> { |
| 93 | acheck!(snd_ctl_elem_read(self.0, elem_value_ptr(val))).map(|_| ()) |
| 94 | } |
| 95 | |
| 96 | pub fn elem_write(&self, val: &ElemValue) -> Result<()> { |
| 97 | acheck!(snd_ctl_elem_write(self.0, elem_value_ptr(val))).map(|_| ()) |
| 98 | } |
| 99 | |
| 100 | pub fn elem_lock(&self, id: &ElemId) -> Result<i32> { |
| 101 | acheck!(snd_ctl_elem_lock(self.0, elem_id_ptr(id))) |
| 102 | } |
| 103 | |
| 104 | pub fn elem_unlock(&self, id: &ElemId) -> Result<i32> { |
| 105 | acheck!(snd_ctl_elem_unlock(self.0, elem_id_ptr(id))) |
| 106 | } |
| 107 | |
| 108 | /// Note: According to alsa-lib documentation, you're also supposed to have functionality for |
| 109 | /// returning whether or not you are subscribed. This does not work in practice, so I'm not |
| 110 | /// including that here. |
| 111 | pub fn subscribe_events(&self, subscribe: bool) -> Result<()> { |
| 112 | acheck!(snd_ctl_subscribe_events(self.0, if subscribe { 1 } else { 0 })).map(|_| ()) |
| 113 | } |
| 114 | |
| 115 | pub fn read(&self) -> Result<Option<Event>> { |
| 116 | let e = event_new()?; |
| 117 | acheck!(snd_ctl_read(self.0, e.0)).map(|r| if r == 1 { Some(e) } else { None }) |
| 118 | } |
| 119 | |
| 120 | pub fn pcm_info(&self, device: u32, subdevice: u32, direction: Direction) -> Result<Info> { |
| 121 | Info::new().and_then(|mut info| { |
| 122 | info.set_device(device); |
| 123 | info.set_subdevice(subdevice); |
| 124 | info.set_stream(direction); |
| 125 | acheck!(snd_ctl_pcm_info(self.0, info.0)).map(|_| info ) |
| 126 | }) |
| 127 | } |
| 128 | } |
| 129 | |
| 130 | impl Drop for Ctl { |
| 131 | fn drop(&mut self) { unsafe { alsa::snd_ctl_close(self.0) }; } |
| 132 | } |
| 133 | |
| 134 | impl poll::Descriptors for Ctl { |
| 135 | fn count(&self) -> usize { |
| 136 | unsafe { alsa::snd_ctl_poll_descriptors_count(self.0) as usize } |
| 137 | } |
| 138 | fn fill(&self, p: &mut [pollfd]) -> Result<usize> { |
| 139 | let z: i32 = unsafe { alsa::snd_ctl_poll_descriptors(self.0, pfds:p.as_mut_ptr(), space:p.len() as c_uint) }; |
| 140 | from_code("snd_ctl_poll_descriptors" , z).map(|_| z as usize) |
| 141 | } |
| 142 | fn revents(&self, p: &[pollfd]) -> Result<poll::Flags> { |
| 143 | let mut r: u16 = 0; |
| 144 | let z: i32 = unsafe { alsa::snd_ctl_poll_descriptors_revents(self.0, pfds:p.as_ptr() as *mut pollfd, nfds:p.len() as c_uint, &mut r) }; |
| 145 | from_code("snd_ctl_poll_descriptors_revents" , z).map(|_| poll::Flags::from_bits_truncate(bits:r as c_short)) |
| 146 | } |
| 147 | } |
| 148 | |
| 149 | |
| 150 | pub fn ctl_ptr(a: &Ctl) -> *mut alsa::snd_ctl_t { a.0 } |
| 151 | |
| 152 | /// [snd_ctl_card_info_t](http://www.alsa-project.org/alsa-doc/alsa-lib/group___control.html) wrapper |
| 153 | pub struct CardInfo(*mut alsa::snd_ctl_card_info_t); |
| 154 | |
| 155 | impl Drop for CardInfo { |
| 156 | fn drop(&mut self) { unsafe { alsa::snd_ctl_card_info_free(self.0) }} |
| 157 | } |
| 158 | |
| 159 | impl CardInfo { |
| 160 | fn new() -> Result<CardInfo> { |
| 161 | let mut p: *mut _snd_ctl_card_info = ptr::null_mut(); |
| 162 | acheck!(snd_ctl_card_info_malloc(&mut p)).map(|_| CardInfo(p)) |
| 163 | } |
| 164 | |
| 165 | pub fn get_id(&self) -> Result<&str> { |
| 166 | from_const(func:"snd_ctl_card_info_get_id" , s:unsafe { alsa::snd_ctl_card_info_get_id(self.0) })} |
| 167 | pub fn get_driver(&self) -> Result<&str> { |
| 168 | from_const(func:"snd_ctl_card_info_get_driver" , s:unsafe { alsa::snd_ctl_card_info_get_driver(self.0) })} |
| 169 | pub fn get_components(&self) -> Result<&str> { |
| 170 | from_const(func:"snd_ctl_card_info_get_components" , s:unsafe { alsa::snd_ctl_card_info_get_components(self.0) })} |
| 171 | pub fn get_longname(&self) -> Result<&str> { |
| 172 | from_const(func:"snd_ctl_card_info_get_longname" , s:unsafe { alsa::snd_ctl_card_info_get_longname(self.0) })} |
| 173 | pub fn get_name(&self) -> Result<&str> { |
| 174 | from_const(func:"snd_ctl_card_info_get_name" , s:unsafe { alsa::snd_ctl_card_info_get_name(self.0) })} |
| 175 | pub fn get_mixername(&self) -> Result<&str> { |
| 176 | from_const(func:"snd_ctl_card_info_get_mixername" , s:unsafe { alsa::snd_ctl_card_info_get_mixername(self.0) })} |
| 177 | pub fn get_card(&self) -> Card { Card::new(index:unsafe { alsa::snd_ctl_card_info_get_card(self.0) })} |
| 178 | } |
| 179 | |
| 180 | alsa_enum!( |
| 181 | /// [SND_CTL_ELEM_IFACE_xxx](http://www.alsa-project.org/alsa-doc/alsa-lib/group___control.html) constants |
| 182 | ElemIface, ALL_ELEMIFACE[7], |
| 183 | |
| 184 | Card = SND_CTL_ELEM_IFACE_CARD, |
| 185 | Hwdep = SND_CTL_ELEM_IFACE_HWDEP, |
| 186 | Mixer = SND_CTL_ELEM_IFACE_MIXER, |
| 187 | PCM = SND_CTL_ELEM_IFACE_PCM, |
| 188 | Rawmidi = SND_CTL_ELEM_IFACE_RAWMIDI, |
| 189 | Timer = SND_CTL_ELEM_IFACE_TIMER, |
| 190 | Sequencer = SND_CTL_ELEM_IFACE_SEQUENCER, |
| 191 | ); |
| 192 | |
| 193 | alsa_enum!( |
| 194 | /// [SND_CTL_ELEM_TYPE_xxx](http://www.alsa-project.org/alsa-doc/alsa-lib/group___control.html) constants |
| 195 | ElemType, ALL_ELEMTYPE[7], |
| 196 | |
| 197 | None = SND_CTL_ELEM_TYPE_NONE, |
| 198 | Boolean = SND_CTL_ELEM_TYPE_BOOLEAN, |
| 199 | Integer = SND_CTL_ELEM_TYPE_INTEGER, |
| 200 | Enumerated = SND_CTL_ELEM_TYPE_ENUMERATED, |
| 201 | Bytes = SND_CTL_ELEM_TYPE_BYTES, |
| 202 | IEC958 = SND_CTL_ELEM_TYPE_IEC958, |
| 203 | Integer64 = SND_CTL_ELEM_TYPE_INTEGER64, |
| 204 | ); |
| 205 | |
| 206 | /// [snd_ctl_elem_value_t](http://www.alsa-project.org/alsa-doc/alsa-lib/group___control.html) wrapper |
| 207 | pub struct ElemValue { |
| 208 | ptr: *mut alsa::snd_ctl_elem_value_t, |
| 209 | etype: ElemType, |
| 210 | count: u32, |
| 211 | } |
| 212 | |
| 213 | impl Drop for ElemValue { |
| 214 | fn drop(&mut self) { unsafe { alsa::snd_ctl_elem_value_free(self.ptr) }; } |
| 215 | } |
| 216 | |
| 217 | pub fn elem_value_ptr(a: &ElemValue) -> *mut alsa::snd_ctl_elem_value_t { a.ptr } |
| 218 | |
| 219 | pub fn elem_value_new(t: ElemType, count: u32) -> Result<ElemValue> { |
| 220 | let mut p: *mut _snd_ctl_elem_value = ptr::null_mut(); |
| 221 | acheck!(snd_ctl_elem_value_malloc(&mut p)) |
| 222 | .map(|_| ElemValue { ptr: p, etype: t, count }) |
| 223 | } |
| 224 | |
| 225 | impl ElemValue { |
| 226 | |
| 227 | pub fn set_id(&mut self, id: &ElemId) { |
| 228 | unsafe { alsa::snd_ctl_elem_value_set_id(self.ptr, elem_id_ptr(id)) } |
| 229 | } |
| 230 | |
| 231 | // Note: The get_bytes hands out a reference to inside the object. Therefore, we can't treat |
| 232 | // the content as "cell"ed, but must take a "&mut self" (to make sure the reference |
| 233 | // from get_bytes has been dropped when calling a set_* function). |
| 234 | |
| 235 | pub fn get_boolean(&self, idx: u32) -> Option<bool> { |
| 236 | if self.etype != ElemType::Boolean || idx >= self.count { None } |
| 237 | else { Some( unsafe { alsa::snd_ctl_elem_value_get_boolean(self.ptr, idx as c_uint) } != 0) } |
| 238 | } |
| 239 | |
| 240 | pub fn set_boolean(&mut self, idx: u32, val: bool) -> Option<()> { |
| 241 | if self.etype != ElemType::Boolean || idx >= self.count { None } |
| 242 | else { unsafe { alsa::snd_ctl_elem_value_set_boolean(self.ptr, idx as c_uint, if val {1} else {0}) }; Some(()) } |
| 243 | } |
| 244 | |
| 245 | pub fn get_integer(&self, idx: u32) -> Option<i32> { |
| 246 | if self.etype != ElemType::Integer || idx >= self.count { None } |
| 247 | else { Some( unsafe { alsa::snd_ctl_elem_value_get_integer(self.ptr, idx as c_uint) } as i32) } |
| 248 | } |
| 249 | |
| 250 | pub fn set_integer(&mut self, idx: u32, val: i32) -> Option<()> { |
| 251 | if self.etype != ElemType::Integer || idx >= self.count { None } |
| 252 | else { unsafe { alsa::snd_ctl_elem_value_set_integer(self.ptr, idx as c_uint, val as c_long) }; Some(()) } |
| 253 | } |
| 254 | |
| 255 | pub fn get_integer64(&self, idx: u32) -> Option<i64> { |
| 256 | if self.etype != ElemType::Integer64 || idx >= self.count { None } |
| 257 | else { Some( unsafe { alsa::snd_ctl_elem_value_get_integer64(self.ptr, idx as c_uint) } as i64) } |
| 258 | } |
| 259 | |
| 260 | pub fn set_integer64(&mut self, idx: u32, val: i64) -> Option<()> { |
| 261 | if self.etype != ElemType::Integer || idx >= self.count { None } |
| 262 | else { unsafe { alsa::snd_ctl_elem_value_set_integer64(self.ptr, idx as c_uint, val) }; Some(()) } |
| 263 | } |
| 264 | |
| 265 | pub fn get_enumerated(&self, idx: u32) -> Option<u32> { |
| 266 | if self.etype != ElemType::Enumerated || idx >= self.count { None } |
| 267 | else { Some( unsafe { alsa::snd_ctl_elem_value_get_enumerated(self.ptr, idx as c_uint) } as u32) } |
| 268 | } |
| 269 | |
| 270 | pub fn set_enumerated(&mut self, idx: u32, val: u32) -> Option<()> { |
| 271 | if self.etype != ElemType::Enumerated || idx >= self.count { None } |
| 272 | else { unsafe { alsa::snd_ctl_elem_value_set_enumerated(self.ptr, idx as c_uint, val as c_uint) }; Some(()) } |
| 273 | } |
| 274 | |
| 275 | pub fn get_byte(&self, idx: u32) -> Option<u8> { |
| 276 | if self.etype != ElemType::Bytes || idx >= self.count { None } |
| 277 | else { Some( unsafe { alsa::snd_ctl_elem_value_get_byte(self.ptr, idx as c_uint) } as u8) } |
| 278 | } |
| 279 | |
| 280 | pub fn set_byte(&mut self, idx: u32, val: u8) -> Option<()> { |
| 281 | if self.etype != ElemType::Bytes || idx >= self.count { None } |
| 282 | else { unsafe { alsa::snd_ctl_elem_value_set_byte(self.ptr, idx as c_uint, val) }; Some(()) } |
| 283 | } |
| 284 | |
| 285 | pub fn get_bytes(&self) -> Option<&[u8]> { |
| 286 | if self.etype != ElemType::Bytes { None } |
| 287 | else { Some( unsafe { ::std::slice::from_raw_parts( |
| 288 | alsa::snd_ctl_elem_value_get_bytes(self.ptr) as *const u8, self.count as usize) } ) } |
| 289 | } |
| 290 | |
| 291 | pub fn set_bytes(&mut self, val: &[u8]) -> Option<()> { |
| 292 | if self.etype != ElemType::Bytes || val.len() != self.count as usize { None } |
| 293 | |
| 294 | // Note: the alsa-lib function definition is broken. First, the pointer is declared as mut even |
| 295 | // though it's const, and second, there is a "value" missing between "elem" and "set_bytes". |
| 296 | else { unsafe { alsa::snd_ctl_elem_set_bytes(self.ptr, val.as_ptr() as *mut c_void, val.len() as size_t) }; Some(()) } |
| 297 | } |
| 298 | |
| 299 | /// Creates a new ElemValue. |
| 300 | pub fn new(t: ElemType) -> Result<ElemValue> { |
| 301 | // See max length in include/uapi/sound/asound.h in linux kernel for these values |
| 302 | let count = match t { |
| 303 | ElemType::None => 1, |
| 304 | ElemType::Boolean => 128, |
| 305 | ElemType::Integer => 128, |
| 306 | ElemType::Enumerated => 128, |
| 307 | ElemType::Bytes => 512, |
| 308 | ElemType::IEC958 => 1, |
| 309 | ElemType::Integer64 => 64, |
| 310 | }; |
| 311 | // if count > maxcount { return Err(Error::new(Some("ElemValue::new - count too large".into()), 1)) } |
| 312 | let ev = elem_value_new(t, count)?; |
| 313 | unsafe { alsa::snd_ctl_elem_value_clear(elem_value_ptr(&ev)) }; |
| 314 | Ok(ev) |
| 315 | } |
| 316 | |
| 317 | } |
| 318 | |
| 319 | impl fmt::Debug for ElemValue { |
| 320 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| 321 | use self::ElemType::*; |
| 322 | write!(f, "ElemValue( {:?}" , self.etype)?; |
| 323 | for a: u32 in 0..self.count { match self.etype { |
| 324 | Boolean => write!(f, ", {:?}" , self.get_boolean(a).unwrap()), |
| 325 | Integer => write!(f, ", {:?}" , self.get_integer(a).unwrap()), |
| 326 | Integer64 => write!(f, ", {:?}" , self.get_integer64(a).unwrap()), |
| 327 | Enumerated => write!(f, ", {:?}" , self.get_enumerated(a).unwrap()), |
| 328 | Bytes => write!(f, ", {:?}" , self.get_byte(a).unwrap()), |
| 329 | _ => Ok(()), |
| 330 | }?}; |
| 331 | write!(f, ")" ) |
| 332 | } |
| 333 | } |
| 334 | |
| 335 | /// [snd_ctl_elem_info_t](http://www.alsa-project.org/alsa-doc/alsa-lib/group___control.html) wrapper |
| 336 | pub struct ElemInfo(*mut alsa::snd_ctl_elem_info_t); |
| 337 | |
| 338 | pub fn elem_info_ptr(a: &ElemInfo) -> *mut alsa::snd_ctl_elem_info_t { a.0 } |
| 339 | |
| 340 | impl Drop for ElemInfo { |
| 341 | fn drop(&mut self) { unsafe { alsa::snd_ctl_elem_info_free(self.0) }; } |
| 342 | } |
| 343 | |
| 344 | pub fn elem_info_new() -> Result<ElemInfo> { |
| 345 | let mut p: *mut _snd_ctl_elem_info = ptr::null_mut(); |
| 346 | acheck!(snd_ctl_elem_info_malloc(&mut p)).map(|_| ElemInfo(p)) |
| 347 | } |
| 348 | |
| 349 | impl ElemInfo { |
| 350 | pub fn get_type(&self) -> ElemType { ElemType::from_c_int( |
| 351 | c:unsafe { alsa::snd_ctl_elem_info_get_type(self.0) } as c_int, s:"snd_ctl_elem_info_get_type" ).unwrap() } |
| 352 | pub fn get_count(&self) -> u32 { unsafe { alsa::snd_ctl_elem_info_get_count(self.0) as u32 } } |
| 353 | } |
| 354 | |
| 355 | // |
| 356 | // Non-allocating version of ElemId |
| 357 | // |
| 358 | |
| 359 | /// [snd_ctl_elem_id_t](http://www.alsa-project.org/alsa-doc/alsa-lib/group___control.html) wrapper |
| 360 | pub struct ElemId(UnsafeCell<[u8; ELEM_ID_SIZE]>); |
| 361 | |
| 362 | pub fn elem_id_new() -> Result<ElemId> { |
| 363 | assert!(unsafe { alsa::snd_ctl_elem_id_sizeof() } as usize <= ELEM_ID_SIZE); |
| 364 | Ok(ElemId(UnsafeCell::new(unsafe { mem::zeroed() }))) |
| 365 | } |
| 366 | |
| 367 | #[inline ] |
| 368 | pub fn elem_id_ptr(a: &ElemId) -> *mut alsa::snd_ctl_elem_id_t { a.0.get() as *mut _ as *mut alsa::snd_ctl_elem_id_t } |
| 369 | |
| 370 | unsafe impl Send for ElemId {} |
| 371 | |
| 372 | impl Clone for ElemId { |
| 373 | fn clone(&self) -> Self { |
| 374 | ElemId(UnsafeCell::new(unsafe { *self.0.get() })) |
| 375 | } |
| 376 | } |
| 377 | |
| 378 | // |
| 379 | // Allocating version of ElemId |
| 380 | // |
| 381 | |
| 382 | /* |
| 383 | |
| 384 | /// [snd_ctl_elem_id_t](http://www.alsa-project.org/alsa-doc/alsa-lib/group___control.html) wrapper |
| 385 | pub struct ElemId(*mut alsa::snd_ctl_elem_id_t); |
| 386 | |
| 387 | impl Drop for ElemId { |
| 388 | fn drop(&mut self) { unsafe { alsa::snd_ctl_elem_id_free(self.0) }; } |
| 389 | } |
| 390 | |
| 391 | pub fn elem_id_new() -> Result<ElemId> { |
| 392 | let mut p = ptr::null_mut(); |
| 393 | acheck!(snd_ctl_elem_id_malloc(&mut p)).map(|_| ElemId(p)) |
| 394 | } |
| 395 | |
| 396 | pub fn elem_id_ptr(a: &ElemId) -> *mut alsa::snd_ctl_elem_id_t { a.0 } |
| 397 | |
| 398 | */ |
| 399 | |
| 400 | impl ElemId { |
| 401 | pub fn get_name(&self) -> Result<&str> { |
| 402 | from_const("snd_hctl_elem_id_get_name" , unsafe { alsa::snd_ctl_elem_id_get_name(elem_id_ptr(self)) })} |
| 403 | pub fn get_device(&self) -> u32 { unsafe { alsa::snd_ctl_elem_id_get_device(elem_id_ptr(self)) as u32 }} |
| 404 | pub fn get_subdevice(&self) -> u32 { unsafe { alsa::snd_ctl_elem_id_get_subdevice(elem_id_ptr(self)) as u32 }} |
| 405 | pub fn get_numid(&self) -> u32 { unsafe { alsa::snd_ctl_elem_id_get_numid(elem_id_ptr(self)) as u32 }} |
| 406 | pub fn get_index(&self) -> u32 { unsafe { alsa::snd_ctl_elem_id_get_index(elem_id_ptr(self)) as u32 }} |
| 407 | pub fn get_interface(&self) -> ElemIface { ElemIface::from_c_int( |
| 408 | unsafe { alsa::snd_ctl_elem_id_get_interface(elem_id_ptr(self)) } as c_int, "snd_ctl_elem_id_get_interface" ).unwrap() } |
| 409 | |
| 410 | pub fn set_device(&mut self, v: u32) { unsafe { alsa::snd_ctl_elem_id_set_device(elem_id_ptr(self), v) }} |
| 411 | pub fn set_subdevice(&mut self, v: u32) { unsafe { alsa::snd_ctl_elem_id_set_subdevice(elem_id_ptr(self), v) }} |
| 412 | pub fn set_numid(&mut self, v: u32) { unsafe { alsa::snd_ctl_elem_id_set_numid(elem_id_ptr(self), v) }} |
| 413 | pub fn set_index(&mut self, v: u32) { unsafe { alsa::snd_ctl_elem_id_set_index(elem_id_ptr(self), v) }} |
| 414 | pub fn set_interface(&mut self, v: ElemIface) { unsafe { alsa::snd_ctl_elem_id_set_interface(elem_id_ptr(self), v as u32) }} |
| 415 | pub fn set_name(&mut self, v: &CStr) { unsafe { alsa::snd_ctl_elem_id_set_name(elem_id_ptr(self), v.as_ptr()) }} |
| 416 | |
| 417 | /// Creates a new ElemId. |
| 418 | /// |
| 419 | /// To ensure safety (i e make sure we never have an invalid interface enum), we need to supply it to the "new" function. |
| 420 | pub fn new(iface: ElemIface) -> Self { |
| 421 | let mut r = elem_id_new().unwrap(); |
| 422 | r.set_interface(iface); |
| 423 | r |
| 424 | } |
| 425 | } |
| 426 | |
| 427 | impl cmp::Eq for ElemId {} |
| 428 | |
| 429 | impl cmp::PartialEq for ElemId { |
| 430 | fn eq(&self, a: &ElemId) -> bool { |
| 431 | self.get_numid() == a.get_numid() && self.get_interface() == a.get_interface() && |
| 432 | self.get_index() == a.get_index() && self.get_device() == a.get_device() && |
| 433 | self.get_subdevice() == a.get_subdevice() && self.get_name().ok() == a.get_name().ok() |
| 434 | } |
| 435 | } |
| 436 | |
| 437 | impl fmt::Debug for ElemId { |
| 438 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| 439 | let index: u32 = self.get_index(); |
| 440 | let device: u32 = self.get_device(); |
| 441 | let subdevice: u32 = self.get_subdevice(); |
| 442 | |
| 443 | write!(f, "ElemId(# {}, {:?}, {:?}" , self.get_numid(), self.get_interface(), self.get_name())?; |
| 444 | if index > 0 { write!(f, ", index= {}" , index)? }; |
| 445 | if device > 0 || subdevice > 0 { write!(f, ", device= {}" , device)? }; |
| 446 | if subdevice > 0 { write!(f, ", subdevice= {}" , device)? }; |
| 447 | write!(f, ")" ) |
| 448 | } |
| 449 | } |
| 450 | |
| 451 | /// [snd_ctl_event_t](http://www.alsa-project.org/alsa-doc/alsa-lib/group___control.html) wrapper |
| 452 | pub struct Event(*mut alsa::snd_ctl_event_t); |
| 453 | |
| 454 | impl Drop for Event { |
| 455 | fn drop(&mut self) { unsafe { alsa::snd_ctl_event_free(self.0) }; } |
| 456 | } |
| 457 | |
| 458 | pub fn event_new() -> Result<Event> { |
| 459 | let mut p: *mut _snd_ctl_event = ptr::null_mut(); |
| 460 | acheck!(snd_ctl_event_malloc(&mut p)).map(|_| Event(p)) |
| 461 | } |
| 462 | |
| 463 | impl Event { |
| 464 | pub fn get_mask(&self) -> EventMask { EventMask(unsafe { alsa::snd_ctl_event_elem_get_mask(self.0) as u32 })} |
| 465 | pub fn get_id(&self) -> ElemId { |
| 466 | let r: ElemId = elem_id_new().unwrap(); |
| 467 | unsafe { alsa::snd_ctl_event_elem_get_id(self.0, elem_id_ptr(&r)) }; |
| 468 | r |
| 469 | } |
| 470 | } |
| 471 | |
| 472 | |
| 473 | /// [SND_CTL_EVENT_MASK_XXX](http://www.alsa-project.org/alsa-doc/alsa-lib/group___control.html) bitmask |
| 474 | #[derive (Default, Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] |
| 475 | pub struct EventMask(pub u32); |
| 476 | |
| 477 | impl EventMask { |
| 478 | pub fn remove(&self) -> bool { return self.0 & 0xffffffff == 0xffffffff } |
| 479 | pub fn value(&self) -> bool { return (!self.remove()) && (self.0 & (1 << 0) != 0); } |
| 480 | pub fn info(&self) -> bool { return (!self.remove()) && (self.0 & (1 << 1) != 0); } |
| 481 | pub fn add(&self) -> bool { return (!self.remove()) && (self.0 & (1 << 2) != 0); } |
| 482 | pub fn tlv(&self) -> bool { return (!self.remove()) && (self.0 & (1 << 3) != 0); } |
| 483 | } |
| 484 | |
| 485 | #[test ] |
| 486 | fn print_sizeof() { |
| 487 | let elemid = unsafe { alsa::snd_ctl_elem_id_sizeof() } as usize; |
| 488 | let elemvalue = unsafe { alsa::snd_ctl_elem_value_sizeof() } as usize; |
| 489 | let eleminfo = unsafe { alsa::snd_ctl_elem_info_sizeof() } as usize; |
| 490 | |
| 491 | assert!(elemid <= ELEM_ID_SIZE); |
| 492 | // assert!(elemvalue <= ELEM_VALUE_SIZE); |
| 493 | // assert!(eleminfo <= ELEM_INFO_SIZE); |
| 494 | |
| 495 | println!("Elem id: {}, Elem value: {}, Elem info: {}" , elemid, elemvalue, eleminfo); |
| 496 | } |
| 497 | |