1use crate::alsa;
2use std::{fmt, mem, slice};
3use super::error::*;
4
5alsa_enum!(
6 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
15alsa_enum!(
16 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
54impl fmt::Display for ChmapPosition {
55 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
56 let s = unsafe { alsa::snd_pcm_chmap_long_name(*self as libc::c_uint) };
57 let s = from_const("snd_pcm_chmap_long_name", s)?;
58 write!(f, "{}", s)
59 }
60}
61
62
63pub struct Chmap(*mut alsa::snd_pcm_chmap_t, bool);
65
66impl Drop for Chmap {
67 fn drop(&mut self) { if self.1 { unsafe { libc::free(self.0 as *mut libc::c_void) }}}
68}
69
70impl 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
80impl 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 = from_const("snd_pcm_chmap_print", buf.as_mut_ptr())?;
85 write!(f, "{}", s)
86 }
87}
88
89impl<'a> From<&'a [ChmapPosition]> for Chmap {
90 fn from(a: &'a [ChmapPosition]) -> Chmap {
91 let p = 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(p as *mut alsa::snd_pcm_chmap_t, true);
94 r.set_channels(a.len() as libc::c_uint);
95 for (i,v) in r.as_slice_mut().iter_mut().enumerate() { *v = a[i] as libc::c_uint }
96 r
97 }
98}
99
100impl<'a> From<&'a Chmap> for Vec<ChmapPosition> {
101 fn from(a: &'a Chmap) -> Vec<ChmapPosition> {
102 a.as_slice().iter().map(|&v| ChmapPosition::from_c_int(v as libc::c_int, "").unwrap()).collect()
103 }
104}
105
106pub fn chmap_new(a: *mut alsa::snd_pcm_chmap_t) -> Chmap { Chmap(a, true) }
107pub fn chmap_handle(a: &Chmap) -> *mut alsa::snd_pcm_chmap_t { a.0 }
108
109
110pub struct ChmapsQuery(*mut *mut alsa::snd_pcm_chmap_query_t, isize);
112
113impl Drop for ChmapsQuery {
114 fn drop(&mut self) { unsafe { alsa::snd_pcm_free_chmaps(self.0) }}
115}
116
117pub fn chmaps_query_new(a: *mut *mut alsa::snd_pcm_chmap_query_t) -> ChmapsQuery { ChmapsQuery(a, 0) }
118
119impl 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 = unsafe { *self.0.offset(self.1) };
124 if p.is_null() { return None; }
125 self.1 += 1;
126 let t = ChmapType::from_c_int(unsafe { (*p).type_ } as libc::c_int, "snd_pcm_query_chmaps").unwrap();
127 let m = Chmap(unsafe { &mut (*p).map }, false);
128 Some((t, m))
129 }
130}
131
132
133#[test]
134fn 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) }
147 }
148}