1use std::borrow::{Borrow, BorrowMut};
37use std::ffi::{CStr, CString};
38use std::borrow::Cow;
39use num_derive::{FromPrimitive, ToPrimitive};
40use crate::sample;
41
42pub use capi::pa_channel_map_def_t as MapDef;
43
44pub type PositionMask = capi::channelmap::pa_channel_position_mask_t;
46
47pub const POSITION_MASK_ALL: PositionMask = 0xffffffffffffffffu64;
49
50#[repr(C)]
55#[derive(Debug, Copy, Clone, PartialEq, Eq)]
56#[derive(FromPrimitive, ToPrimitive)]
57pub enum Position {
58 Invalid = -1,
63
64 Mono = 0,
66
67 FrontLeft,
69 FrontRight,
71 FrontCenter,
73
74 RearCenter,
77 RearLeft,
80 RearRight,
83
84 Lfe,
87
88 FrontLeftOfCenter,
90 FrontRightOfCenter,
92
93 SideLeft,
96 SideRight,
99
100 Aux0,
102 Aux1,
104 Aux2,
106 Aux3,
108 Aux4,
110 Aux5,
112 Aux6,
114 Aux7,
116 Aux8,
118 Aux9,
120 Aux10,
122 Aux11,
124 Aux12,
126 Aux13,
128 Aux14,
130 Aux15,
132 Aux16,
134 Aux17,
136 Aux18,
138 Aux19,
140 Aux20,
142 Aux21,
144 Aux22,
146 Aux23,
148 Aux24,
150 Aux25,
152 Aux26,
154 Aux27,
156 Aux28,
158 Aux29,
160 Aux30,
162 Aux31,
164
165 TopCenter,
167
168 TopFrontLeft,
170 TopFrontRight,
172 TopFrontCenter,
174
175 TopRearLeft,
177 TopRearRight,
179 TopRearCenter,
181}
182
183impl Default for Position {
184 #[inline(always)]
185 fn default() -> Self {
186 Position::Invalid
187 }
188}
189
190#[test]
192fn pos_compare_capi() {
193 assert_eq!(std::mem::size_of::<Position>(), std::mem::size_of::<capi::pa_channel_position_t>());
194 assert_eq!(std::mem::align_of::<Position>(), std::mem::align_of::<capi::pa_channel_position_t>());
195
196 assert_eq!(Position::Invalid, Position::from(capi::pa_channel_position_t::Invalid));
199 assert_eq!(Position::Mono, Position::from(capi::pa_channel_position_t::Mono));
200 assert_eq!(Position::FrontLeft, Position::from(capi::pa_channel_position_t::FrontLeft));
201 assert_eq!(Position::FrontRight, Position::from(capi::pa_channel_position_t::FrontRight));
202 assert_eq!(Position::FrontCenter, Position::from(capi::pa_channel_position_t::FrontCenter));
203 assert_eq!(Position::RearCenter, Position::from(capi::pa_channel_position_t::RearCenter));
204 assert_eq!(Position::RearLeft, Position::from(capi::pa_channel_position_t::RearLeft));
205 assert_eq!(Position::RearRight, Position::from(capi::pa_channel_position_t::RearRight));
206 assert_eq!(Position::Lfe, Position::from(capi::pa_channel_position_t::Lfe));
207 assert_eq!(Position::FrontLeftOfCenter, Position::from(capi::pa_channel_position_t::FrontLeftOfCenter));
208 assert_eq!(Position::FrontRightOfCenter, Position::from(capi::pa_channel_position_t::FrontRightOfCenter));
209 assert_eq!(Position::SideLeft, Position::from(capi::pa_channel_position_t::SideLeft));
210 assert_eq!(Position::SideRight, Position::from(capi::pa_channel_position_t::SideRight));
211 assert_eq!(Position::Aux0, Position::from(capi::pa_channel_position_t::Aux0));
212 assert_eq!(Position::Aux1, Position::from(capi::pa_channel_position_t::Aux1));
213 assert_eq!(Position::Aux2, Position::from(capi::pa_channel_position_t::Aux2));
214 assert_eq!(Position::Aux3, Position::from(capi::pa_channel_position_t::Aux3));
215 assert_eq!(Position::Aux4, Position::from(capi::pa_channel_position_t::Aux4));
216 assert_eq!(Position::Aux5, Position::from(capi::pa_channel_position_t::Aux5));
217 assert_eq!(Position::Aux6, Position::from(capi::pa_channel_position_t::Aux6));
218 assert_eq!(Position::Aux7, Position::from(capi::pa_channel_position_t::Aux7));
219 assert_eq!(Position::Aux8, Position::from(capi::pa_channel_position_t::Aux8));
220 assert_eq!(Position::Aux9, Position::from(capi::pa_channel_position_t::Aux9));
221 assert_eq!(Position::Aux10, Position::from(capi::pa_channel_position_t::Aux10));
222 assert_eq!(Position::Aux11, Position::from(capi::pa_channel_position_t::Aux11));
223 assert_eq!(Position::Aux12, Position::from(capi::pa_channel_position_t::Aux12));
224 assert_eq!(Position::Aux13, Position::from(capi::pa_channel_position_t::Aux13));
225 assert_eq!(Position::Aux14, Position::from(capi::pa_channel_position_t::Aux14));
226 assert_eq!(Position::Aux15, Position::from(capi::pa_channel_position_t::Aux15));
227 assert_eq!(Position::Aux16, Position::from(capi::pa_channel_position_t::Aux16));
228 assert_eq!(Position::Aux17, Position::from(capi::pa_channel_position_t::Aux17));
229 assert_eq!(Position::Aux18, Position::from(capi::pa_channel_position_t::Aux18));
230 assert_eq!(Position::Aux19, Position::from(capi::pa_channel_position_t::Aux19));
231 assert_eq!(Position::Aux20, Position::from(capi::pa_channel_position_t::Aux20));
232 assert_eq!(Position::Aux21, Position::from(capi::pa_channel_position_t::Aux21));
233 assert_eq!(Position::Aux22, Position::from(capi::pa_channel_position_t::Aux22));
234 assert_eq!(Position::Aux23, Position::from(capi::pa_channel_position_t::Aux23));
235 assert_eq!(Position::Aux24, Position::from(capi::pa_channel_position_t::Aux24));
236 assert_eq!(Position::Aux25, Position::from(capi::pa_channel_position_t::Aux25));
237 assert_eq!(Position::Aux26, Position::from(capi::pa_channel_position_t::Aux26));
238 assert_eq!(Position::Aux27, Position::from(capi::pa_channel_position_t::Aux27));
239 assert_eq!(Position::Aux28, Position::from(capi::pa_channel_position_t::Aux28));
240 assert_eq!(Position::Aux29, Position::from(capi::pa_channel_position_t::Aux29));
241 assert_eq!(Position::Aux30, Position::from(capi::pa_channel_position_t::Aux30));
242 assert_eq!(Position::Aux31, Position::from(capi::pa_channel_position_t::Aux31));
243 assert_eq!(Position::TopCenter, Position::from(capi::pa_channel_position_t::TopCenter));
244 assert_eq!(Position::TopFrontLeft, Position::from(capi::pa_channel_position_t::TopFrontLeft));
245 assert_eq!(Position::TopFrontRight, Position::from(capi::pa_channel_position_t::TopFrontRight));
246 assert_eq!(Position::TopFrontCenter, Position::from(capi::pa_channel_position_t::TopFrontCenter));
247 assert_eq!(Position::TopRearLeft, Position::from(capi::pa_channel_position_t::TopRearLeft));
248 assert_eq!(Position::TopRearRight, Position::from(capi::pa_channel_position_t::TopRearRight));
249 assert_eq!(Position::TopRearCenter, Position::from(capi::pa_channel_position_t::TopRearCenter));
250}
251
252impl From<Position> for capi::pa_channel_position_t {
253 #[inline]
254 fn from(p: Position) -> Self {
255 unsafe { std::mem::transmute(p) }
256 }
257}
258impl From<capi::pa_channel_position_t> for Position {
259 #[inline]
260 fn from(p: capi::pa_channel_position_t) -> Self {
261 unsafe { std::mem::transmute(p) }
262 }
263}
264
265#[repr(C)]
269#[derive(Debug, Copy, Clone)]
270pub struct Map {
271 channels: u8,
274 map: [Position; Self::CHANNELS_MAX as usize],
276}
277
278impl Borrow<[Position]> for Map {
279 fn borrow(&self) -> &[Position] {
280 &self.map[..self.channels as usize]
281 }
282}
283
284impl BorrowMut<[Position]> for Map {
285 fn borrow_mut(&mut self) -> &mut [Position] {
286 &mut self.map[..self.channels as usize]
287 }
288}
289
290#[test]
292fn map_compare_capi() {
293 assert_eq!(std::mem::size_of::<Map>(), std::mem::size_of::<capi::pa_channel_map>());
294 assert_eq!(std::mem::align_of::<Map>(), std::mem::align_of::<capi::pa_channel_map>());
295}
296
297impl AsRef<capi::pa_channel_map> for Map {
298 #[inline]
299 fn as_ref(&self) -> &capi::pa_channel_map {
300 unsafe { &*(self as *const Self as *const capi::pa_channel_map) }
301 }
302}
303impl AsMut<capi::pa_channel_map> for Map {
304 #[inline]
305 fn as_mut(&mut self) -> &mut capi::pa_channel_map {
306 unsafe { &mut *(self as *mut Self as *mut capi::pa_channel_map) }
307 }
308}
309impl AsRef<Map> for capi::pa_channel_map {
310 #[inline]
311 fn as_ref(&self) -> &Map {
312 unsafe { &*(self as *const Self as *const Map) }
313 }
314}
315
316impl From<capi::pa_channel_map> for Map {
317 #[inline]
318 fn from(m: capi::pa_channel_map) -> Self {
319 unsafe { std::mem::transmute(m) }
320 }
321}
322
323impl Default for Map {
324 fn default() -> Self {
325 Self { channels: 0, map: [Position::Invalid; Self::CHANNELS_MAX as usize] }
326 }
327}
328
329impl PartialEq for Map {
330 #[inline]
331 fn eq(&self, other: &Self) -> bool {
332 unsafe { capi::pa_channel_map_equal(self.as_ref(), other.as_ref()) == 1 }
333 }
334}
335
336impl Position {
337 pub const fn to_mask(self) -> PositionMask {
339 match self {
340 Position::Invalid => 0,
341 _ => (1 as PositionMask) << (self as PositionMask),
342 }
343 }
344
345 pub fn to_string(pos: Self) -> Option<Cow<'static, str>> {
347 let ptr = unsafe { capi::pa_channel_position_to_string(pos.into()) };
348 match ptr.is_null() {
349 false => Some(unsafe { CStr::from_ptr(ptr).to_string_lossy() }),
350 true => None,
351 }
352 }
353
354 pub fn to_pretty_string(pos: Self) -> Option<String> {
356 let ptr = unsafe { capi::pa_channel_position_to_pretty_string(pos.into()) };
357 match ptr.is_null() {
358 false => Some(unsafe { CStr::from_ptr(ptr).to_string_lossy().into_owned() }),
359 true => None,
360 }
361 }
362
363 pub fn from_string(s: &str) -> Self {
366 let c_str = CString::new(s).unwrap();
369 unsafe { capi::pa_channel_position_from_string(c_str.as_ptr()).into() }
370 }
371}
372
373impl Map {
374 pub const CHANNELS_MAX: u8 = capi::PA_CHANNELS_MAX;
376
377 pub fn new_from_string(s: &str) -> Result<Self, ()> {
382 let c_str = CString::new(s).unwrap();
385 let mut map: Self = Self::default();
386 unsafe {
387 if capi::pa_channel_map_parse((&mut map).as_mut(), c_str.as_ptr()).is_null() {
388 return Err(());
389 }
390 }
391 Ok(map)
392 }
393
394 #[inline]
398 pub fn init(&mut self) -> &mut Self {
399 unsafe { capi::pa_channel_map_init(self.as_mut()) };
400 self
401 }
402
403 #[inline]
405 pub fn init_mono(&mut self) -> &mut Self {
406 unsafe { capi::pa_channel_map_init_mono(self.as_mut()) };
407 self
408 }
409
410 #[inline]
412 pub fn init_stereo(&mut self) -> &mut Self {
413 unsafe { capi::pa_channel_map_init_stereo(self.as_mut()) };
414 self
415 }
416
417 pub fn init_auto(&mut self, channels: u8, def: MapDef) -> Option<&mut Self> {
423 debug_assert!(channels <= Self::CHANNELS_MAX);
424 unsafe {
425 if capi::pa_channel_map_init_auto(self.as_mut(), channels as u32, def).is_null() {
426 return None;
427 }
428 }
429 Some(self)
430 }
431
432 pub fn init_extend(&mut self, channels: u8, def: MapDef) -> &mut Self {
436 debug_assert!(channels <= Self::CHANNELS_MAX);
437 unsafe { capi::pa_channel_map_init_extend(self.as_mut(), channels as u32, def) };
438 self
439 }
440
441 #[inline]
443 pub fn is_valid(&self) -> bool {
444 unsafe { capi::pa_channel_map_valid(self.as_ref()) != 0 }
445 }
446
447 #[inline]
449 pub const fn len(&self) -> u8 {
450 self.channels
451 }
452
453 #[inline]
461 pub fn set_len(&mut self, channels: u8) {
462 assert!(channels <= Self::CHANNELS_MAX);
463 self.channels = channels;
464 }
465
466 #[inline]
468 pub fn get(&self) -> &[Position] {
469 self.borrow()
470 }
471
472 #[inline]
474 pub fn get_mut(&mut self) -> &mut [Position] {
475 self.borrow_mut()
476 }
477
478 pub fn print(&self) -> String {
480 const PRINT_MAX: usize = capi::PA_CHANNEL_MAP_SNPRINT_MAX;
481 let mut tmp = Vec::with_capacity(PRINT_MAX);
482 unsafe {
483 capi::pa_channel_map_snprint(tmp.as_mut_ptr(), PRINT_MAX, self.as_ref());
484 CStr::from_ptr(tmp.as_mut_ptr()).to_string_lossy().into_owned()
485 }
486 }
487
488 #[inline]
490 pub fn is_compatible_with_sample_spec(&self, ss: &sample::Spec) -> bool {
491 unsafe { capi::pa_channel_map_compatible(self.as_ref(), ss.as_ref()) != 0 }
492 }
493
494 #[inline]
496 pub fn is_superset_of(&self, of: &Self) -> bool {
497 unsafe { capi::pa_channel_map_superset(self.as_ref(), of.as_ref()) != 0 }
498 }
499
500 #[inline]
503 pub fn can_balance(&self) -> bool {
504 unsafe { capi::pa_channel_map_can_balance(self.as_ref()) != 0 }
505 }
506
507 #[inline]
510 pub fn can_fade(&self) -> bool {
511 unsafe { capi::pa_channel_map_can_fade(self.as_ref()) != 0 }
512 }
513
514 #[inline]
518 #[cfg(any(doc, feature = "pa_v8"))]
519 #[cfg_attr(docsrs, doc(cfg(feature = "pa_v8")))]
520 pub fn can_lfe_balance(&self) -> bool {
521 unsafe { capi::pa_channel_map_can_lfe_balance(self.as_ref()) != 0 }
522 }
523
524 pub fn to_name(&self) -> Option<Cow<'static, str>> {
528 let ptr = unsafe { capi::pa_channel_map_to_name(self.as_ref()) };
529 match ptr.is_null() {
530 false => Some(unsafe { CStr::from_ptr(ptr).to_string_lossy() }),
531 true => None,
532 }
533 }
534
535 pub fn to_pretty_name(&self) -> Option<String> {
538 let ptr = unsafe { capi::pa_channel_map_to_pretty_name(self.as_ref()) };
539 match ptr.is_null() {
540 false => Some(unsafe { CStr::from_ptr(ptr).to_string_lossy().into_owned() }),
541 true => None,
542 }
543 }
544
545 #[inline]
547 pub fn has_position(&self, p: Position) -> bool {
548 unsafe { capi::pa_channel_map_has_position(self.as_ref(), p.into()) != 0 }
549 }
550
551 #[inline]
553 pub fn get_mask(&self) -> PositionMask {
554 unsafe { capi::pa_channel_map_mask(self.as_ref()) }
555 }
556}