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