1
2use crate::alsa;
3use super::pcm::Info;
4use std::ffi::{CStr, CString};
5use super::Direction;
6use super::error::*;
7use super::mixer::MilliBel;
8use super::Round;
9use std::{ptr, mem, fmt, cmp};
10use crate::{Card, poll};
11use std::cell::UnsafeCell;
12use 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
18const 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.
24pub struct DeviceIter<'a>(&'a Ctl, c_int);
25
26impl<'a> DeviceIter<'a>{
27 pub fn new(ctl: &'a Ctl) -> DeviceIter {
28 DeviceIter(ctl, -1)
29 }
30}
31
32impl<'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
45pub struct Ctl(*mut alsa::snd_ctl_t);
46
47unsafe impl Send for Ctl {}
48
49impl 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
130impl Drop for Ctl {
131 fn drop(&mut self) { unsafe { alsa::snd_ctl_close(self.0) }; }
132}
133
134impl 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
150pub 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
153pub struct CardInfo(*mut alsa::snd_ctl_card_info_t);
154
155impl Drop for CardInfo {
156 fn drop(&mut self) { unsafe { alsa::snd_ctl_card_info_free(self.0) }}
157}
158
159impl 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
180alsa_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
193alsa_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
207pub struct ElemValue {
208 ptr: *mut alsa::snd_ctl_elem_value_t,
209 etype: ElemType,
210 count: u32,
211}
212
213impl Drop for ElemValue {
214 fn drop(&mut self) { unsafe { alsa::snd_ctl_elem_value_free(self.ptr) }; }
215}
216
217pub fn elem_value_ptr(a: &ElemValue) -> *mut alsa::snd_ctl_elem_value_t { a.ptr }
218
219pub 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
225impl 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
319impl 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
336pub struct ElemInfo(*mut alsa::snd_ctl_elem_info_t);
337
338pub fn elem_info_ptr(a: &ElemInfo) -> *mut alsa::snd_ctl_elem_info_t { a.0 }
339
340impl Drop for ElemInfo {
341 fn drop(&mut self) { unsafe { alsa::snd_ctl_elem_info_free(self.0) }; }
342}
343
344pub 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
349impl 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
360pub struct ElemId(UnsafeCell<[u8; ELEM_ID_SIZE]>);
361
362pub 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]
368pub 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
370unsafe impl Send for ElemId {}
371
372impl 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
385pub struct ElemId(*mut alsa::snd_ctl_elem_id_t);
386
387impl Drop for ElemId {
388 fn drop(&mut self) { unsafe { alsa::snd_ctl_elem_id_free(self.0) }; }
389}
390
391pub 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
396pub fn elem_id_ptr(a: &ElemId) -> *mut alsa::snd_ctl_elem_id_t { a.0 }
397
398*/
399
400impl 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
427impl cmp::Eq for ElemId {}
428
429impl 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
437impl 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
452pub struct Event(*mut alsa::snd_ctl_event_t);
453
454impl Drop for Event {
455 fn drop(&mut self) { unsafe { alsa::snd_ctl_event_free(self.0) }; }
456}
457
458pub 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
463impl 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, ptr: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)]
475pub struct EventMask(pub u32);
476
477impl 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]
486fn print_sizeof() {
487 let elemid: usize = unsafe { alsa::snd_ctl_elem_id_sizeof() } as usize;
488 let elemvalue: usize = unsafe { alsa::snd_ctl_elem_value_sizeof() } as usize;
489 let eleminfo: usize = 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