use std::borrow::{Borrow, BorrowMut};
use std::ffi::{CStr, CString};
use std::borrow::Cow;
use crate::sample;
pub use capi::pa_channel_map_def_t as MapDef;
pub type PositionMask = capi::channelmap::pa_channel_position_mask_t;
pub const POSITION_MASK_ALL: PositionMask = 0xffffffffffffffffu64;
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Position {
Invalid = -1,
Mono = 0,
FrontLeft,
FrontRight,
FrontCenter,
RearCenter,
RearLeft,
RearRight,
Lfe,
FrontLeftOfCenter,
FrontRightOfCenter,
SideLeft,
SideRight,
Aux0,
Aux1,
Aux2,
Aux3,
Aux4,
Aux5,
Aux6,
Aux7,
Aux8,
Aux9,
Aux10,
Aux11,
Aux12,
Aux13,
Aux14,
Aux15,
Aux16,
Aux17,
Aux18,
Aux19,
Aux20,
Aux21,
Aux22,
Aux23,
Aux24,
Aux25,
Aux26,
Aux27,
Aux28,
Aux29,
Aux30,
Aux31,
TopCenter,
TopFrontLeft,
TopFrontRight,
TopFrontCenter,
TopRearLeft,
TopRearRight,
TopRearCenter,
}
impl Default for Position {
#[inline(always)]
fn default() -> Self {
Position::Invalid
}
}
#[test]
fn pos_compare_capi(){
assert_eq!(std::mem::size_of::<Position>(), std::mem::size_of::<capi::pa_channel_position_t>());
assert_eq!(std::mem::align_of::<Position>(), std::mem::align_of::<capi::pa_channel_position_t>());
}
impl From<Position> for capi::pa_channel_position_t {
#[inline]
fn from(p: Position) -> Self {
unsafe { std::mem::transmute(p) }
}
}
impl From<capi::pa_channel_position_t> for Position {
#[inline]
fn from(p: capi::pa_channel_position_t) -> Self {
unsafe { std::mem::transmute(p) }
}
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct Map {
channels: u8,
map: [Position; sample::CHANNELS_MAX],
}
impl Borrow<[Position]> for Map {
fn borrow(&self) -> &[Position] {
&self.map[..self.channels as usize]
}
}
impl BorrowMut<[Position]> for Map {
fn borrow_mut(&mut self) -> &mut [Position] {
&mut self.map[..self.channels as usize]
}
}
#[test]
fn map_compare_capi(){
assert_eq!(std::mem::size_of::<Map>(), std::mem::size_of::<capi::pa_channel_map>());
assert_eq!(std::mem::align_of::<Map>(), std::mem::align_of::<capi::pa_channel_map>());
}
impl AsRef<capi::pa_channel_map> for Map {
#[inline]
fn as_ref(&self) -> &capi::pa_channel_map {
unsafe { &*(self as *const Self as *const capi::pa_channel_map) }
}
}
impl AsMut<capi::pa_channel_map> for Map {
#[inline]
fn as_mut(&mut self) -> &mut capi::pa_channel_map {
unsafe { &mut *(self as *mut Self as *mut capi::pa_channel_map) }
}
}
impl AsRef<Map> for capi::pa_channel_map {
#[inline]
fn as_ref(&self) -> &Map {
unsafe { &*(self as *const Self as *const Map) }
}
}
impl From<capi::pa_channel_map> for Map {
#[inline]
fn from(m: capi::pa_channel_map) -> Self {
unsafe { std::mem::transmute(m) }
}
}
impl Default for Map {
fn default() -> Self {
Self {
channels: 0,
map: [Position::Invalid; sample::CHANNELS_MAX],
}
}
}
impl PartialEq for Map {
#[inline]
fn eq(&self, other: &Self) -> bool {
unsafe { capi::pa_channel_map_equal(self.as_ref(), other.as_ref()) == 1 }
}
}
impl Position {
pub fn to_mask(self) -> PositionMask {
if self == Position::Invalid {
return 0;
}
(1 as PositionMask) << (self as PositionMask)
}
pub fn to_string(pos: Self) -> Option<Cow<'static, str>> {
let ptr = unsafe { capi::pa_channel_position_to_string(pos.into()) };
match ptr.is_null() {
false => Some(unsafe { CStr::from_ptr(ptr).to_string_lossy() }),
true => None,
}
}
pub fn to_pretty_string(pos: Self) -> Option<String> {
let ptr = unsafe { capi::pa_channel_position_to_pretty_string(pos.into()) };
match ptr.is_null() {
false => Some(unsafe { CStr::from_ptr(ptr).to_string_lossy().into_owned() }),
true => None,
}
}
pub fn from_string(s: &str) -> Self {
let c_str = CString::new(s.clone()).unwrap();
unsafe { capi::pa_channel_position_from_string(c_str.as_ptr()).into() }
}
}
impl Map {
pub fn new_from_string(s: &str) -> Result<Self, ()> {
let c_str = CString::new(s.clone()).unwrap();
let mut map: Self = Self::default();
unsafe {
if capi::pa_channel_map_parse((&mut map).as_mut(), c_str.as_ptr()).is_null() {
return Err(());
}
}
Ok(map)
}
#[inline]
pub fn init(&mut self) -> &mut Self {
unsafe { capi::pa_channel_map_init(self.as_mut()) };
self
}
#[inline]
pub fn init_mono(&mut self) -> &mut Self {
unsafe { capi::pa_channel_map_init_mono(self.as_mut()) };
self
}
#[inline]
pub fn init_stereo(&mut self) -> &mut Self {
unsafe { capi::pa_channel_map_init_stereo(self.as_mut()) };
self
}
pub fn init_auto(&mut self, channels: u32, def: MapDef) -> Option<&mut Self> {
debug_assert!(channels as usize <= sample::CHANNELS_MAX);
unsafe {
if capi::pa_channel_map_init_auto(self.as_mut(), channels, def).is_null() {
return None;
}
}
Some(self)
}
pub fn init_extend(&mut self, channels: u32, def: MapDef) -> &mut Self {
debug_assert!(channels as usize <= sample::CHANNELS_MAX);
unsafe { capi::pa_channel_map_init_extend(self.as_mut(), channels, def) };
self
}
#[inline]
pub fn is_valid(&self) -> bool {
unsafe { capi::pa_channel_map_valid(self.as_ref()) != 0 }
}
#[inline]
pub fn len(&self) -> u8 {
self.channels
}
#[inline]
pub fn set_len(&mut self, channels: u8) {
assert!(channels as usize <= sample::CHANNELS_MAX);
self.channels = channels;
}
#[inline]
pub fn get(&self) -> &[Position] {
self.borrow()
}
#[inline]
pub fn get_mut(&mut self) -> &mut [Position] {
self.borrow_mut()
}
pub fn print(&self) -> String {
const PRINT_MAX: usize = capi::PA_CHANNEL_MAP_SNPRINT_MAX;
let mut tmp = Vec::with_capacity(PRINT_MAX);
unsafe {
capi::pa_channel_map_snprint(tmp.as_mut_ptr(), PRINT_MAX, self.as_ref());
CStr::from_ptr(tmp.as_mut_ptr()).to_string_lossy().into_owned()
}
}
#[inline]
pub fn is_compatible_with_sample_spec(&self, ss: &sample::Spec) -> bool {
unsafe { capi::pa_channel_map_compatible(self.as_ref(), ss.as_ref()) != 0 }
}
#[inline]
pub fn is_superset_of(&self, of: &Self) -> bool {
unsafe { capi::pa_channel_map_superset(self.as_ref(), of.as_ref()) != 0 }
}
#[inline]
pub fn can_balance(&self) -> bool {
unsafe { capi::pa_channel_map_can_balance(self.as_ref()) != 0 }
}
#[inline]
pub fn can_fade(&self) -> bool {
unsafe { capi::pa_channel_map_can_fade(self.as_ref()) != 0 }
}
#[inline]
#[cfg(any(feature = "pa_v8", feature = "dox"))]
pub fn can_lfe_balance(&self) -> bool {
unsafe { capi::pa_channel_map_can_lfe_balance(self.as_ref()) != 0 }
}
pub fn to_name(&self) -> Option<Cow<'static, str>> {
let ptr = unsafe { capi::pa_channel_map_to_name(self.as_ref()) };
match ptr.is_null() {
false => Some(unsafe { CStr::from_ptr(ptr).to_string_lossy() }),
true => None,
}
}
pub fn to_pretty_name(&self) -> Option<String> {
let ptr = unsafe { capi::pa_channel_map_to_pretty_name(self.as_ref()) };
match ptr.is_null() {
false => Some(unsafe { CStr::from_ptr(ptr).to_string_lossy().into_owned() }),
true => None,
}
}
#[inline]
pub fn has_position(&self, p: Position) -> bool {
unsafe { capi::pa_channel_map_has_position(self.as_ref(), p.into()) != 0 }
}
#[inline]
pub fn get_mask(&self) -> PositionMask {
unsafe { capi::pa_channel_map_mask(self.as_ref()) }
}
}