1 //! Enumerate devices in the alsa library configuration
2 //!
3 //! # Example
4 //! Print all devices found in various categories.
5 //!
6 //! ```
7 //! use std::ffi::CString;
8 //! use alsa::device_name::HintIter;
9 //!
10 //! for t in &["pcm", "ctl", "rawmidi", "timer", "seq", "hwdep"] {
11 //!     println!("{} devices:", t);
12 //!     let i = HintIter::new(None, &*CString::new(*t).unwrap()).unwrap();
13 //!     for a in i { println!("  {:?}", a) }
14 //! }
15 //! ```
16 
17 use std::ptr;
18 use libc::{c_void, c_int};
19 use alsa;
20 use super::{Card, Direction};
21 use super::error::*;
22 use std::ffi::{CStr, CString};
23 
24 /// [snd_device_name_hint](http://www.alsa-project.org/alsa-doc/alsa-lib/group___control.html) wrapper
25 pub struct HintIter(*mut *mut c_void, isize);
26 
27 impl Drop for HintIter {
drop(&mut self)28     fn drop(&mut self) { unsafe { alsa::snd_device_name_free_hint(self.0); }}
29 }
30 
31 impl HintIter {
32     /// typical interfaces are: "pcm", "ctl", "rawmidi", "timer", "seq" and "hwdep".
new(card: Option<&Card>, iface: &CStr) -> Result<HintIter>33     pub fn new(card: Option<&Card>, iface: &CStr) -> Result<HintIter> {
34         let mut p = ptr::null_mut();
35         let cnr = card.map(|c| c.get_index()).unwrap_or(-1) as c_int;
36         acheck!(snd_device_name_hint(cnr, iface.as_ptr(), &mut p))
37             .map(|_| HintIter(p, 0))
38     }
39 
40     /// A constructor variant that takes the interface as a Rust string slice.
new_str(card: Option<&Card>, iface: &str) -> Result<HintIter>41     pub fn new_str(card: Option<&Card>, iface: &str) -> Result<HintIter> {
42         HintIter::new(card, &CString::new(iface).unwrap())
43     }
44 }
45 
46 impl Iterator for HintIter {
47     type Item = Hint;
next<'a> (&'a mut self) -> Option<Hint>48     fn next<'a> (&'a mut self) -> Option<Hint> {
49         if self.0.is_null() { return None; }
50         let p = unsafe { *self.0.offset(self.1) };
51         if p.is_null() { return None; }
52         self.1 += 1;
53         Some(Hint::new(p))
54     }
55 }
56 
57 
58 /// [snd_device_name_get_hint](http://www.alsa-project.org/alsa-doc/alsa-lib/group___control.html) wrapper
59 #[derive(Debug, Clone)]
60 pub struct Hint {
61     pub name: Option<String>,
62     pub desc: Option<String>,
63     pub direction: Option<Direction>,
64 }
65 
66 impl Hint {
get_str(p: *const c_void, name: &str) -> Option<String>67     fn get_str(p: *const c_void, name: &str) -> Option<String> {
68         let c = unsafe { alsa::snd_device_name_get_hint(p, CString::new(name).unwrap().as_ptr()) };
69         from_alloc("snd_device_name_get_hint", c).ok()
70     }
71 
new(p: *const c_void) -> Hint72     fn new(p: *const c_void) -> Hint {
73        let d = Hint::get_str(p, "IOID").and_then(|x| match &*x {
74             "Input" => Some(Direction::Capture),
75             "Output" => Some(Direction::Playback),
76             _ => None,
77        });
78        Hint { name: Hint::get_str(p, "NAME"), desc: Hint::get_str(p, "DESC"), direction: d }
79     }
80 }
81 
82 #[test]
print_hints()83 fn print_hints() {
84     for t in &["pcm", "ctl", "rawmidi", "timer", "seq", "hwdep"] {
85         println!("{} devices:", t);
86         let i = HintIter::new(None, &*CString::new(*t).unwrap()).unwrap();
87         for a in i { println!("  {:?}", a) }
88     }
89 }
90