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, 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)] |
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: 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 | |