| 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 {unknown} = 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 in &["pcm" , "ctl" , "rawmidi" , "timer" , "seq" , "hwdep" ] { |
| 86 | println!("{} devices:" , t); |
| 87 | let i = HintIter::new(None, &*CString::new(*t).unwrap()).unwrap(); |
| 88 | for a in i { println!(" {:?}" , a) } |
| 89 | } |
| 90 | } |
| 91 | |