1 | use crate::alsa; |
2 | use std::{fmt, mem, slice}; |
3 | use super::error::*; |
4 | |
5 | alsa_enum!( |
6 | /// [SND_CHMAP_TYPE_xxx](http://www.alsa-project.org/alsa-doc/alsa-lib/group___p_c_m.html) constants |
7 | ChmapType, ALL_CHMAP_TYPES[4], |
8 | |
9 | None = SND_CHMAP_TYPE_NONE, |
10 | Fixed = SND_CHMAP_TYPE_FIXED, |
11 | Var = SND_CHMAP_TYPE_VAR, |
12 | Paired = SND_CHMAP_TYPE_PAIRED, |
13 | ); |
14 | |
15 | alsa_enum!( |
16 | /// [SND_CHMAP_xxx](http://www.alsa-project.org/alsa-doc/alsa-lib/group___p_c_m.html) constants |
17 | ChmapPosition, ALL_CHMAP_POSITIONS[33], |
18 | |
19 | Unknown = SND_CHMAP_UNKNOWN, |
20 | NA = SND_CHMAP_NA, |
21 | Mono = SND_CHMAP_MONO, |
22 | FL = SND_CHMAP_FL, |
23 | FR = SND_CHMAP_FR, |
24 | RL = SND_CHMAP_RL, |
25 | SR = SND_CHMAP_SR, |
26 | RC = SND_CHMAP_RC, |
27 | FLC = SND_CHMAP_FLC, |
28 | FRC = SND_CHMAP_FRC, |
29 | RLC = SND_CHMAP_RLC, |
30 | RRC = SND_CHMAP_RRC, |
31 | FLW = SND_CHMAP_FLW, |
32 | FRW = SND_CHMAP_FRW, |
33 | FLH = SND_CHMAP_FLH, |
34 | FCH = SND_CHMAP_FCH, |
35 | FRH = SND_CHMAP_FRH, |
36 | TC = SND_CHMAP_TC, |
37 | TFL = SND_CHMAP_TFL, |
38 | TFR = SND_CHMAP_TFR, |
39 | TFC = SND_CHMAP_TFC, |
40 | TRL = SND_CHMAP_TRL, |
41 | TRR = SND_CHMAP_TRR, |
42 | TRC = SND_CHMAP_TRC, |
43 | TFLC = SND_CHMAP_TFLC, |
44 | TFRC = SND_CHMAP_TFRC, |
45 | TSL = SND_CHMAP_TSL, |
46 | TSR = SND_CHMAP_TSR, |
47 | LLFE = SND_CHMAP_LLFE, |
48 | RLFE = SND_CHMAP_RLFE, |
49 | BC = SND_CHMAP_BC, |
50 | BLC = SND_CHMAP_BLC, |
51 | BRC = SND_CHMAP_BRC, |
52 | ); |
53 | |
54 | impl fmt::Display for ChmapPosition { |
55 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
56 | let s: *const {unknown} = unsafe { alsa::snd_pcm_chmap_long_name(*self as libc::c_uint) }; |
57 | let s: &str = from_const(func:"snd_pcm_chmap_long_name" , s)?; |
58 | write!(f, " {}" , s) |
59 | } |
60 | } |
61 | |
62 | |
63 | /// [snd_pcm_chmap_t](http://www.alsa-project.org/alsa-doc/alsa-lib/group___p_c_m.html) wrapper |
64 | pub struct Chmap(*mut alsa::snd_pcm_chmap_t, bool); |
65 | |
66 | impl Drop for Chmap { |
67 | fn drop(&mut self) { if self.1 { unsafe { libc::free(self.0 as *mut libc::c_void) }}} |
68 | } |
69 | |
70 | impl Chmap { |
71 | fn set_channels(&mut self, c: libc::c_uint) { unsafe { (*self.0) .channels = c }} |
72 | fn as_slice_mut(&mut self) -> &mut [libc::c_uint] { |
73 | unsafe { slice::from_raw_parts_mut((*self.0).pos.as_mut_ptr(), (*self.0).channels as usize) } |
74 | } |
75 | fn as_slice(&self) -> &[libc::c_uint] { |
76 | unsafe { slice::from_raw_parts((*self.0).pos.as_ptr(), (*self.0).channels as usize) } |
77 | } |
78 | } |
79 | |
80 | impl fmt::Display for Chmap { |
81 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
82 | let mut buf: Vec<libc::c_char> = vec![0; 512]; |
83 | acheck!(snd_pcm_chmap_print(self.0, buf.len() as libc::size_t, buf.as_mut_ptr()))?; |
84 | let s: &str = from_const(func:"snd_pcm_chmap_print" , s:buf.as_mut_ptr())?; |
85 | write!(f, " {}" , s) |
86 | } |
87 | } |
88 | |
89 | impl<'a> From<&'a [ChmapPosition]> for Chmap { |
90 | fn from(a: &'a [ChmapPosition]) -> Chmap { |
91 | let p: *mut c_void = unsafe { libc::malloc((mem::size_of::<alsa::snd_pcm_chmap_t>() + mem::size_of::<libc::c_uint>() * a.len()) as libc::size_t) }; |
92 | if p.is_null() { panic!("Out of memory" ) } |
93 | let mut r: Chmap = Chmap(p as *mut alsa::snd_pcm_chmap_t, true); |
94 | r.set_channels(a.len() as libc::c_uint); |
95 | for (i: usize,v: &mut u32) in r.as_slice_mut().iter_mut().enumerate() { *v = a[i] as libc::c_uint } |
96 | r |
97 | } |
98 | } |
99 | |
100 | impl<'a> From<&'a Chmap> for Vec<ChmapPosition> { |
101 | fn from(a: &'a Chmap) -> Vec<ChmapPosition> { |
102 | a.as_slice().iter().map(|&v: u32| ChmapPosition::from_c_int(c:v as libc::c_int, s:"" ).unwrap()).collect() |
103 | } |
104 | } |
105 | |
106 | pub fn chmap_new(a: *mut alsa::snd_pcm_chmap_t) -> Chmap { Chmap(a, true) } |
107 | pub fn chmap_handle(a: &Chmap) -> *mut alsa::snd_pcm_chmap_t { a.0 } |
108 | |
109 | |
110 | /// Iterator over available channel maps - see [snd_pcm_chmap_query_t](http://www.alsa-project.org/alsa-doc/alsa-lib/group___p_c_m.html) |
111 | pub struct ChmapsQuery(*mut *mut alsa::snd_pcm_chmap_query_t, isize); |
112 | |
113 | impl Drop for ChmapsQuery { |
114 | fn drop(&mut self) { unsafe { alsa::snd_pcm_free_chmaps(self.0) }} |
115 | } |
116 | |
117 | pub fn chmaps_query_new(a: *mut *mut alsa::snd_pcm_chmap_query_t) -> ChmapsQuery { ChmapsQuery(a, 0) } |
118 | |
119 | impl Iterator for ChmapsQuery { |
120 | type Item = (ChmapType, Chmap); |
121 | fn next(&mut self) -> Option<Self::Item> { |
122 | if self.0.is_null() { return None; } |
123 | let p: *mut snd_pcm_chmap_query = unsafe { *self.0.offset(self.1) }; |
124 | if p.is_null() { return None; } |
125 | self.1 += 1; |
126 | let t: ChmapType = ChmapType::from_c_int(c:unsafe { (*p).type_ } as libc::c_int, s:"snd_pcm_query_chmaps" ).unwrap(); |
127 | let m: Chmap = Chmap(unsafe { &mut (*p).map }, false); |
128 | Some((t, m)) |
129 | } |
130 | } |
131 | |
132 | |
133 | #[test ] |
134 | fn chmap_for_first_pcm() { |
135 | use super::*; |
136 | use std::ffi::CString; |
137 | use crate::device_name::HintIter; |
138 | let i = HintIter::new(None, &*CString::new("pcm" ).unwrap()).unwrap(); |
139 | for p in i.map(|n| n.name.unwrap()) { |
140 | println!("Chmaps for {:?}:" , p); |
141 | match PCM::open(&CString::new(p).unwrap(), Direction::Playback, false) { |
142 | Ok(a) => for c in a.query_chmaps() { |
143 | println!(" {:?}, {}" , c.0, c.1); |
144 | }, |
145 | Err(a) => println!(" {}" , a) // It's okay to have entries in the name hint array that can't be opened |
146 | } |
147 | } |
148 | } |
149 | |