use std;
use libc;
use capi;
use std::os::raw::{c_char, c_void};
use std::ffi::{CStr, CString};
use std::ptr::{null, null_mut};
pub use capi::pa_prop_type_t as PropType;
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[allow(non_camel_case_types)]
pub enum Encoding {
Any,
PCM,
AC3_IEC61937,
EAC3_IEC61937,
MPEG_IEC61937,
DTS_IEC61937,
MPEG2_AAC_IEC61937,
Invalid = -1,
}
impl From<Encoding> for capi::pa_encoding_t {
fn from(e: Encoding) -> Self {
unsafe { std::mem::transmute(e) }
}
}
impl From<capi::pa_encoding_t> for Encoding {
fn from(e: capi::pa_encoding_t) -> Self {
unsafe { std::mem::transmute(e) }
}
}
impl Default for Encoding {
fn default() -> Self {
Encoding::Invalid
}
}
pub struct Info<'a> {
pub ptr: &'a mut InfoInternal,
weak: bool,
}
#[repr(C)]
pub struct InfoInternal {
pub encoding: Encoding,
pub list: *mut ::proplist::ProplistInternal,
}
pub const PRINT_MAX: usize = capi::PA_FORMAT_INFO_SNPRINT_MAX;
impl Encoding {
pub fn to_string(e: Self) -> Option<&'static CStr> {
let ptr = unsafe { capi::pa_encoding_to_string(e.into()) };
if ptr.is_null() {
return None;
}
Some(unsafe { CStr::from_ptr(ptr) })
}
#[cfg(feature = "pa_encoding_from_string")]
pub fn from_string(encoding: &str) -> Self {
let c_enc = CString::new(encoding.clone()).unwrap();
unsafe { capi::pa_encoding_from_string(c_enc.as_ptr()) }
}
}
impl<'a> Info<'a> {
pub fn new() -> Option<Self> {
let ptr = unsafe { capi::pa_format_info_new() };
if ptr.is_null() {
return None;
}
Some(Self::from_raw(unsafe { std::mem::transmute(ptr) }))
}
pub fn new_from_string(s: &str) -> Option<Self> {
let c_str = CString::new(s.clone()).unwrap();
let ptr = unsafe { capi::pa_format_info_from_string(c_str.as_ptr()) };
if ptr.is_null() {
return None;
}
Some(Self::from_raw(unsafe { std::mem::transmute(ptr) }))
}
pub fn new_from_sample_spec(ss: &::sample::Spec, map: Option<&::channelmap::Map>
) -> Option<Self>
{
let p_map: *const capi::pa_channel_map = match map {
Some(map) => unsafe { std::mem::transmute(map) },
None => null::<capi::pa_channel_map>(),
};
let ptr = unsafe { capi::pa_format_info_from_sample_spec(std::mem::transmute(ss), p_map) };
if ptr.is_null() {
return None;
}
Some(Self::from_raw(unsafe { std::mem::transmute(ptr) }))
}
pub fn from_raw(ptr: *mut InfoInternal) -> Self {
assert_eq!(false, ptr.is_null());
unsafe { Self { ptr: &mut *ptr, weak: false } }
}
pub fn from_raw_weak(ptr: *mut InfoInternal) -> Self {
assert_eq!(false, ptr.is_null());
unsafe { Self { ptr: &mut *ptr, weak: true } }
}
pub fn is_valid(&self) -> bool {
unsafe { capi::pa_format_info_valid(std::mem::transmute(&self.ptr)) != 0 }
}
pub fn is_pcm(&self) -> bool {
unsafe { capi::pa_format_info_is_pcm(std::mem::transmute(&self.ptr)) != 0 }
}
pub fn is_compatible_with(&self, with: &Self) -> bool {
unsafe { capi::pa_format_info_is_compatible(std::mem::transmute(&self.ptr),
std::mem::transmute(&with.ptr)) != 0 }
}
pub fn print(&self) -> Option<String> {
let tmp = unsafe { libc::malloc(PRINT_MAX) as *mut c_char };
if tmp.is_null() {
return None;
}
unsafe {
capi::pa_format_info_snprint(tmp, PRINT_MAX, std::mem::transmute(&self.ptr));
let ret = Some(CStr::from_ptr(tmp).to_string_lossy().into_owned());
libc::free(tmp as *mut libc::c_void);
ret
}
}
pub fn to_sample_spec(&self, ss: &mut ::sample::Spec, map: &mut ::channelmap::Map
) -> Result<(), i32>
{
match unsafe { capi::pa_format_info_to_sample_spec(std::mem::transmute(&self.ptr),
std::mem::transmute(ss), std::mem::transmute(map)) }
{
0 => Ok(()),
e => Err(e),
}
}
pub fn set_encoding(&mut self, encoding: Encoding) {
(*self.ptr).encoding = encoding;
}
pub fn get_prop_type(&self, key: &str) -> PropType {
let c_key = CString::new(key.clone()).unwrap();
unsafe { capi::pa_format_info_get_prop_type(std::mem::transmute(&self.ptr), c_key.as_ptr()) }
}
pub fn get_prop_int(&self, key: &str) -> Result<i32, i32> {
let mut i: i32 = 0;
let c_key = CString::new(key.clone()).unwrap();
match unsafe { capi::pa_format_info_get_prop_int(std::mem::transmute(&self.ptr),
c_key.as_ptr(), &mut i) }
{
0 => Ok(i),
e => Err(e),
}
}
pub fn get_prop_int_range(&self, key: &str) -> Result<(i32, i32), i32> {
let mut min: i32 = 0;
let mut max: i32 = 0;
let c_key = CString::new(key.clone()).unwrap();
match unsafe { capi::pa_format_info_get_prop_int_range(std::mem::transmute(&self.ptr),
c_key.as_ptr(), &mut min, &mut max) }
{
0 => Ok((min, max)),
e => Err(e),
}
}
pub fn get_prop_int_array(&self, key: &str) -> Option<Vec<i32>> {
let c_key = CString::new(key.clone()).unwrap();
let mut count: i32 = 0;
let mut p_ints = null_mut::<i32>();
let result = unsafe { capi::pa_format_info_get_prop_int_array(
std::mem::transmute(&self.ptr), c_key.as_ptr(), &mut p_ints, &mut count) };
if result != 0 {
return None;
}
let mut values: Vec<i32> = Vec::with_capacity(count as usize);
for i in 0..count {
values.push(unsafe { *p_ints.offset(i as isize) });
}
unsafe { capi::pa_xfree(p_ints as *mut c_void) };
Some(values)
}
pub fn get_prop_string(&self, key: &str) -> Option<String> {
let c_key = CString::new(key.clone()).unwrap();
let mut p_str = null_mut::<c_char>();
let result = unsafe { capi::pa_format_info_get_prop_string(std::mem::transmute(&self.ptr),
c_key.as_ptr(), &mut p_str) };
if result != 0 || p_str.is_null() {
return None;
}
unsafe {
let ret = Some(CStr::from_ptr(p_str).to_string_lossy().into_owned());
capi::pa_xfree(p_str as *mut c_void);
ret
}
}
pub fn get_prop_string_array(&self, key: &str) -> Option<Vec<String>> {
let c_key = CString::new(key.clone()).unwrap();
let mut count: i32 = 0;
let mut pp_str = null_mut::<*mut c_char>();
let result = unsafe { capi::pa_format_info_get_prop_string_array(
std::mem::transmute(&self.ptr), c_key.as_ptr(), &mut pp_str, &mut count) };
if result != 0 || pp_str.is_null() {
return None;
}
let mut values: Vec<String> = Vec::with_capacity(count as usize);
for i in 0..count {
let p_str = unsafe { *pp_str.offset(i as isize) };
if !p_str.is_null() {
values.push(unsafe { CStr::from_ptr(p_str).to_string_lossy().into_owned() });
}
}
unsafe { capi::pa_format_info_free_string_array(pp_str, count) };
Some(values)
}
pub fn set_prop_int(&mut self, key: &str, value: i32) {
let c_key = CString::new(key.clone()).unwrap();
unsafe { capi::pa_format_info_set_prop_int(std::mem::transmute(&self.ptr), c_key.as_ptr(),
value); }
}
pub fn set_prop_int_array(&mut self, key: &str, values: &[i32]) {
let c_key = CString::new(key.clone()).unwrap();
unsafe { capi::pa_format_info_set_prop_int_array(std::mem::transmute(&self.ptr),
c_key.as_ptr(), values.as_ptr(), values.len() as i32); }
}
pub fn set_prop_int_range(&mut self, key: &str, min: i32, max: i32) {
let c_key = CString::new(key.clone()).unwrap();
unsafe { capi::pa_format_info_set_prop_int_range(std::mem::transmute(&self.ptr),
c_key.as_ptr(), min, max); }
}
pub fn set_prop_string(&mut self, key: &str, value: &str) {
let c_key = CString::new(key.clone()).unwrap();
let c_value = CString::new(value.clone()).unwrap();
unsafe { capi::pa_format_info_set_prop_string(std::mem::transmute(&self.ptr),
c_key.as_ptr(), c_value.as_ptr()); }
}
pub fn set_prop_string_array(&mut self, key: &str, values: &[&str]) {
let c_key = CString::new(key.clone()).unwrap();
let mut c_values: Vec<CString> = Vec::with_capacity(values.len());
for v in values {
c_values.push(CString::new(v.clone()).unwrap());
}
let mut c_value_ptrs: Vec<*const c_char> = Vec::with_capacity(c_values.len());
for v in c_values {
c_value_ptrs.push(v.as_ptr());
}
unsafe {
capi::pa_format_info_set_prop_string_array(std::mem::transmute(&self.ptr),
c_key.as_ptr(), c_value_ptrs.as_ptr(), c_value_ptrs.len() as i32);
}
}
pub fn set_sample_format(&mut self, sf: ::sample::Format) {
unsafe { capi::pa_format_info_set_sample_format(std::mem::transmute(&self.ptr),
sf.into()); }
}
pub fn set_rate(&mut self, rate: i32) {
unsafe { capi::pa_format_info_set_rate(std::mem::transmute(&self.ptr), rate) }
}
pub fn set_channels(&mut self, channels: u32) {
debug_assert!(channels <= std::i32::MAX as u32);
unsafe { capi::pa_format_info_set_channels(std::mem::transmute(&self.ptr), channels as i32) }
}
pub fn set_channel_map(&mut self, map: &::channelmap::Map) {
unsafe { capi::pa_format_info_set_channel_map(std::mem::transmute(&self.ptr),
std::mem::transmute(map)) }
}
}
impl<'a> Drop for Info<'a> {
fn drop(&mut self) {
if !self.weak {
unsafe { capi::pa_format_info_free(std::mem::transmute(&self.ptr)) };
}
}
}
impl<'a> Clone for Info<'a> {
fn clone(&self) -> Self {
let ptr = unsafe { capi::pa_format_info_copy(std::mem::transmute(&self.ptr)) };
assert_eq!(false, ptr.is_null());
Self::from_raw(unsafe { std::mem::transmute(ptr) })
}
}