| 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 | |