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