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 crate::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 { |
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". |
33 | pub fn new(card: Option<&Card>, iface: &CStr) -> Result<HintIter> { |
34 | let mut p: *mut *mut c_void = ptr::null_mut(); |
35 | let cnr: i32 = card.map(|c| c.get_index()).unwrap_or(default:-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. |
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; |
48 | fn next(&mut self) -> Option<Hint> { |
49 | if self.0.is_null() { return None; } |
50 | let p: *mut c_void = 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 { |
67 | fn get_str(p: *const c_void, name: &str) -> Option<String> { |
68 | let name: CString = CString::new(name).unwrap(); |
69 | let c: *mut i8 = unsafe { alsa::snd_device_name_get_hint(hint:p, id:name.as_ptr()) }; |
70 | from_alloc(func:"snd_device_name_get_hint" , s:c).ok() |
71 | } |
72 | |
73 | fn new(p: *const c_void) -> Hint { |
74 | let d: Option = Hint::get_str(p, name:"IOID" ).and_then(|x: String| match &*x { |
75 | "Input" => Some(Direction::Capture), |
76 | "Output" => Some(Direction::Playback), |
77 | _ => None, |
78 | }); |
79 | Hint { name: Hint::get_str(p, name:"NAME" ), desc: Hint::get_str(p, name:"DESC" ), direction: d } |
80 | } |
81 | } |
82 | |
83 | #[test ] |
84 | fn print_hints() { |
85 | for t: &&str in &["pcm" , "ctl" , "rawmidi" , "timer" , "seq" , "hwdep" ] { |
86 | println!(" {} devices:" , t); |
87 | let i: HintIter = HintIter::new(card:None, &*CString::new(*t).unwrap()).unwrap(); |
88 | for a: Hint in i { println!(" {:?}" , a) } |
89 | } |
90 | } |
91 | |