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
17use std::ptr;
18use libc::{c_void, c_int};
19use crate::alsa;
20use super::{Card, Direction};
21use super::error::*;
22use std::ffi::{CStr, CString};
23
24/// [snd_device_name_hint](http://www.alsa-project.org/alsa-doc/alsa-lib/group___control.html) wrapper
25pub struct HintIter(*mut *mut c_void, isize);
26
27impl Drop for HintIter {
28 fn drop(&mut self) { unsafe { alsa::snd_device_name_free_hint(self.0); }}
29}
30
31impl 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
46impl 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)]
60pub struct Hint {
61 pub name: Option<String>,
62 pub desc: Option<String>,
63 pub direction: Option<Direction>,
64}
65
66impl 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]
84fn 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