1use std::os::raw::{c_char, c_void};
22use std::ffi::{CStr, CString};
23use std::ptr::{null, null_mut};
24use std::borrow::Cow;
25use num_derive::{FromPrimitive, ToPrimitive};
26use crate::{sample, channelmap};
27use crate::error::PAErr;
28use crate::proplist::{Proplist, ProplistInternal};
29
30pub use capi::pa_prop_type_t as PropType;
31
32#[repr(C)]
34#[non_exhaustive]
35#[derive(Debug, Copy, Clone, PartialEq, Eq)]
36#[derive(FromPrimitive, ToPrimitive)]
37#[allow(non_camel_case_types)]
38pub enum Encoding {
39 Any,
43 PCM,
45 AC3_IEC61937,
47 EAC3_IEC61937,
49 MPEG_IEC61937,
51 DTS_IEC61937,
53 MPEG2_AAC_IEC61937,
55 #[cfg(any(doc, feature = "pa_v13"))]
57 #[cfg_attr(docsrs, doc(cfg(feature = "pa_v13")))]
58 TRUEHD_IEC61937,
59 #[cfg(any(doc, feature = "pa_v13"))]
61 #[cfg_attr(docsrs, doc(cfg(feature = "pa_v13")))]
62 DTSHD_IEC61937,
63
64 Invalid = -1,
66}
67
68#[test]
70fn enc_compare_capi() {
71 assert_eq!(std::mem::size_of::<Encoding>(), std::mem::size_of::<capi::pa_encoding_t>());
72 assert_eq!(std::mem::align_of::<Encoding>(), std::mem::align_of::<capi::pa_encoding_t>());
73
74 assert_eq!(Encoding::Any, Encoding::from(capi::pa_encoding_t::Any));
77 assert_eq!(Encoding::PCM, Encoding::from(capi::pa_encoding_t::PCM));
78 assert_eq!(Encoding::AC3_IEC61937, Encoding::from(capi::pa_encoding_t::AC3_IEC61937));
79 assert_eq!(Encoding::EAC3_IEC61937, Encoding::from(capi::pa_encoding_t::EAC3_IEC61937));
80 assert_eq!(Encoding::MPEG_IEC61937, Encoding::from(capi::pa_encoding_t::MPEG_IEC61937));
81 assert_eq!(Encoding::DTS_IEC61937, Encoding::from(capi::pa_encoding_t::DTS_IEC61937));
82 assert_eq!(Encoding::MPEG2_AAC_IEC61937, Encoding::from(capi::pa_encoding_t::MPEG2_AAC_IEC61937));
83 #[cfg(any(doc, feature = "pa_v13"))]
84 assert_eq!(Encoding::TRUEHD_IEC61937, Encoding::from(capi::pa_encoding_t::TRUEHD_IEC61937));
85 #[cfg(any(doc, feature = "pa_v13"))]
86 assert_eq!(Encoding::DTSHD_IEC61937, Encoding::from(capi::pa_encoding_t::DTSHD_IEC61937));
87 assert_eq!(Encoding::Invalid, Encoding::from(capi::pa_encoding_t::Invalid));
88}
89
90impl From<Encoding> for capi::pa_encoding_t {
91 #[inline]
92 fn from(e: Encoding) -> Self {
93 unsafe { std::mem::transmute(e) }
94 }
95}
96impl From<capi::pa_encoding_t> for Encoding {
97 #[inline]
98 fn from(e: capi::pa_encoding_t) -> Self {
99 unsafe { std::mem::transmute(e) }
100 }
101}
102
103impl Default for Encoding {
104 #[inline(always)]
105 fn default() -> Self {
106 Encoding::Invalid
107 }
108}
109
110pub struct Info {
112 pub(crate) ptr: *mut InfoInternal,
114 properties: Proplist,
116 weak: bool,
118}
119
120unsafe impl Send for Info {}
121unsafe impl Sync for Info {}
122
123#[repr(C)]
125pub(crate) struct InfoInternal {
126 pub encoding: Encoding,
129 pub list: *mut ProplistInternal,
131}
132
133#[test]
135fn info_compare_capi() {
136 assert_eq!(std::mem::size_of::<InfoInternal>(), std::mem::size_of::<capi::pa_format_info>());
137 assert_eq!(std::mem::align_of::<InfoInternal>(), std::mem::align_of::<capi::pa_format_info>());
138}
139
140impl std::fmt::Debug for Info {
141 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
142 write!(f, "Info {{ encoding: {:?}, properties: {:?} }}", self.get_encoding(),
143 *self.get_properties())
144 }
145}
146
147impl Encoding {
148 pub fn to_string(e: Self) -> Option<Cow<'static, str>> {
150 let ptr = unsafe { capi::pa_encoding_to_string(e.into()) };
151 match ptr.is_null() {
152 false => Some(unsafe { CStr::from_ptr(ptr).to_string_lossy() }),
153 true => None,
154 }
155 }
156
157 #[cfg(any(doc, feature = "pa_v12"))]
160 #[cfg_attr(docsrs, doc(cfg(feature = "pa_v12")))]
161 pub fn from_string(encoding: &str) -> Self {
162 let c_enc = CString::new(encoding).unwrap();
165 unsafe { capi::pa_encoding_from_string(c_enc.as_ptr()).into() }
166 }
167}
168
169impl Info {
170 pub fn new() -> Option<Self> {
174 let ptr = unsafe { capi::pa_format_info_new() };
175 match ptr.is_null() {
176 false => Some(Self::from_raw(ptr as *mut InfoInternal)),
177 true => None,
178 }
179 }
180
181 pub fn new_from_string(s: &str) -> Option<Self> {
186 let c_str = CString::new(s).unwrap();
189 let ptr = unsafe { capi::pa_format_info_from_string(c_str.as_ptr()) };
190 match ptr.is_null() {
191 false => Some(Self::from_raw(ptr as *mut InfoInternal)),
192 true => None,
193 }
194 }
195
196 pub fn new_from_sample_spec(ss: &sample::Spec, map: Option<&channelmap::Map>) -> Option<Self> {
209 let p_map = map.map_or(null::<capi::pa_channel_map>(), |m| m.as_ref());
210 let ptr = unsafe { capi::pa_format_info_from_sample_spec(ss.as_ref(), p_map) };
211 match ptr.is_null() {
212 false => Some(Self::from_raw(ptr as *mut InfoInternal)),
213 true => None,
214 }
215 }
216
217 pub(crate) fn from_raw(ptr: *mut InfoInternal) -> Self {
219 assert_eq!(false, ptr.is_null());
220 unsafe { Self { ptr: ptr, properties: Proplist::from_raw_weak((*ptr).list), weak: false } }
223 }
224
225 pub(crate) fn from_raw_weak(ptr: *mut InfoInternal) -> Self {
229 assert_eq!(false, ptr.is_null());
230 unsafe { Self { ptr: ptr, properties: Proplist::from_raw_weak((*ptr).list), weak: true } }
231 }
232
233 #[inline]
235 pub fn is_valid(&self) -> bool {
236 unsafe { capi::pa_format_info_valid(self.ptr as *const capi::pa_format_info) != 0 }
237 }
238
239 #[inline]
241 pub fn is_pcm(&self) -> bool {
242 unsafe { capi::pa_format_info_is_pcm(self.ptr as *const capi::pa_format_info) != 0 }
243 }
244
245 #[inline]
253 pub fn is_compatible_with(&self, with: &Self) -> bool {
254 unsafe { capi::pa_format_info_is_compatible(self.ptr as *const capi::pa_format_info,
255 with.ptr as *const capi::pa_format_info) != 0 }
256 }
257
258 pub fn print(&self) -> String {
260 const PRINT_MAX: usize = capi::PA_FORMAT_INFO_SNPRINT_MAX;
261 let mut tmp = Vec::with_capacity(PRINT_MAX);
262 unsafe {
263 capi::pa_format_info_snprint(tmp.as_mut_ptr(), PRINT_MAX,
264 self.ptr as *const capi::pa_format_info);
265 CStr::from_ptr(tmp.as_mut_ptr()).to_string_lossy().into_owned()
266 }
267 }
268
269 pub fn to_sample_spec(&self, ss: &mut sample::Spec, map: &mut channelmap::Map)
279 -> Result<(), PAErr>
280 {
281 match unsafe { capi::pa_format_info_to_sample_spec(
282 self.ptr as *const capi::pa_format_info, ss.as_mut(), map.as_mut()) }
283 {
284 0 => Ok(()),
285 e => Err(PAErr(e)),
286 }
287 }
288
289 #[inline]
291 pub fn get_encoding(&self) -> Encoding {
292 unsafe { (*self.ptr).encoding }
293 }
294
295 #[inline]
297 pub fn set_encoding(&mut self, encoding: Encoding) {
298 unsafe { (*self.ptr).encoding = encoding };
299 }
300
301 #[inline]
303 pub fn get_properties(&self) -> &Proplist {
304 &self.properties
305 }
306
307 #[inline]
309 pub fn get_properties_mut(&mut self) -> &mut Proplist {
310 &mut self.properties
311 }
312
313 pub fn get_prop_type(&self, key: &str) -> PropType {
315 let c_key = CString::new(key).unwrap();
318 unsafe { capi::pa_format_info_get_prop_type(self.ptr as *const capi::pa_format_info,
319 c_key.as_ptr()) }
320 }
321
322 pub fn get_prop_int(&self, key: &str) -> Result<i32, PAErr> {
324 let mut i: i32 = 0;
327 let c_key = CString::new(key).unwrap();
328 match unsafe { capi::pa_format_info_get_prop_int(self.ptr as *const capi::pa_format_info,
329 c_key.as_ptr(), &mut i) }
330 {
331 0 => Ok(i),
332 e => Err(PAErr(e)),
333 }
334 }
335
336 pub fn get_prop_int_range(&self, key: &str) -> Result<(i32, i32), PAErr> {
338 let mut min: i32 = 0;
341 let mut max: i32 = 0;
342 let c_key = CString::new(key).unwrap();
343 match unsafe { capi::pa_format_info_get_prop_int_range(
344 self.ptr as *const capi::pa_format_info, c_key.as_ptr(), &mut min, &mut max) }
345 {
346 0 => Ok((min, max)),
347 e => Err(PAErr(e)),
348 }
349 }
350
351 pub fn get_prop_int_array(&self, key: &str) -> Option<Vec<i32>> {
355 let c_key = CString::new(key).unwrap();
358 let mut count: i32 = 0;
359 let mut p_ints = null_mut::<i32>();
360 let result = unsafe { capi::pa_format_info_get_prop_int_array(
361 self.ptr as *const capi::pa_format_info, c_key.as_ptr(), &mut p_ints, &mut count) };
362 if result != 0 {
363 return None;
364 }
365 let mut values: Vec<i32> = Vec::with_capacity(count as usize);
367 for i in 0..count {
368 values.push(unsafe { *p_ints.offset(i as isize) });
369 }
370 unsafe { capi::pa_xfree(p_ints as *mut c_void) };
372 Some(values)
374 }
375
376 pub fn get_prop_string(&self, key: &str) -> Option<String> {
378 let c_key = CString::new(key).unwrap();
381 let mut p_str = null_mut::<c_char>();
382 let result = unsafe { capi::pa_format_info_get_prop_string(
383 self.ptr as *const capi::pa_format_info, c_key.as_ptr(), &mut p_str) };
384 if result != 0 || p_str.is_null() {
385 return None;
386 }
387 unsafe {
388 let ret = Some(CStr::from_ptr(p_str).to_string_lossy().into_owned());
389 capi::pa_xfree(p_str as *mut c_void);
390 ret
391 }
392 }
393
394 pub fn get_prop_string_array(&self, key: &str) -> Option<Vec<String>> {
396 let c_key = CString::new(key).unwrap();
399 let mut count: i32 = 0;
400 let mut pp_str = null_mut::<*mut c_char>();
401 let result = unsafe { capi::pa_format_info_get_prop_string_array(
402 self.ptr as *const capi::pa_format_info, c_key.as_ptr(), &mut pp_str, &mut count) };
403 if result != 0 || pp_str.is_null() {
404 return None;
405 }
406 let mut values: Vec<String> = Vec::with_capacity(count as usize);
408 for i in 0..count {
409 let p_str = unsafe { *pp_str.offset(i as isize) };
410 if !p_str.is_null() {
411 values.push(unsafe { CStr::from_ptr(p_str).to_string_lossy().into_owned() });
412 }
413 }
414 unsafe { capi::pa_format_info_free_string_array(pp_str, count) };
416 Some(values)
418 }
419
420 #[cfg(any(doc, feature = "pa_v13"))]
424 #[cfg_attr(docsrs, doc(cfg(feature = "pa_v13")))]
425 pub fn get_sample_format(&self) -> Result<crate::sample::Format, PAErr> {
426 let mut sf: capi::pa_sample_format_t = capi::PA_SAMPLE_INVALID;
427 match unsafe { capi::pa_format_info_get_sample_format(
428 self.ptr as *const capi::pa_format_info, &mut sf) }
429 {
430 0 => Ok(crate::sample::Format::from(sf)),
431 e => Err(PAErr(e)),
432 }
433 }
434
435 #[cfg(any(doc, feature = "pa_v13"))]
439 #[cfg_attr(docsrs, doc(cfg(feature = "pa_v13")))]
440 pub fn get_rate(&self) -> Result<u32, PAErr> {
441 let mut rate: u32 = 0;
442 match unsafe { capi::pa_format_info_get_rate(self.ptr as *const capi::pa_format_info,
443 &mut rate) }
444 {
445 0 => Ok(rate),
446 e => Err(PAErr(e)),
447 }
448 }
449
450 #[cfg(any(doc, feature = "pa_v13"))]
454 #[cfg_attr(docsrs, doc(cfg(feature = "pa_v13")))]
455 pub fn get_channel_count(&self) -> Result<u8, PAErr> {
456 let mut channels: u8 = 0;
457 match unsafe { capi::pa_format_info_get_channels(self.ptr as *const capi::pa_format_info,
458 &mut channels) }
459 {
460 0 => Ok(channels),
461 e => Err(PAErr(e)),
462 }
463 }
464
465 #[cfg(any(doc, feature = "pa_v13"))]
470 #[cfg_attr(docsrs, doc(cfg(feature = "pa_v13")))]
471 pub fn get_channel_map(&self) -> Result<crate::channelmap::Map, PAErr> {
472 let mut map: capi::pa_channel_map = capi::pa_channel_map::default();
477 match unsafe { capi::pa_format_info_get_channel_map(
478 self.ptr as *const capi::pa_format_info, &mut map) }
479 {
480 0 => Ok(crate::channelmap::Map::from(map)),
481 e => Err(PAErr(e)),
482 }
483 }
484
485 pub fn set_prop_int(&mut self, key: &str, value: i32) {
487 let c_key = CString::new(key).unwrap();
490 unsafe { capi::pa_format_info_set_prop_int(self.ptr as *mut capi::pa_format_info,
491 c_key.as_ptr(), value); }
492 }
493
494 pub fn set_prop_int_array(&mut self, key: &str, values: &[i32]) {
496 let c_key = CString::new(key).unwrap();
499 unsafe { capi::pa_format_info_set_prop_int_array(self.ptr as *mut capi::pa_format_info,
500 c_key.as_ptr(), values.as_ptr(), values.len() as i32); }
501 }
502
503 pub fn set_prop_int_range(&mut self, key: &str, min: i32, max: i32) {
505 let c_key = CString::new(key).unwrap();
508 unsafe { capi::pa_format_info_set_prop_int_range(self.ptr as *mut capi::pa_format_info,
509 c_key.as_ptr(), min, max); }
510 }
511
512 pub fn set_prop_string(&mut self, key: &str, value: &str) {
514 let c_key = CString::new(key).unwrap();
517 let c_value = CString::new(value).unwrap();
518 unsafe { capi::pa_format_info_set_prop_string(self.ptr as *mut capi::pa_format_info,
519 c_key.as_ptr(), c_value.as_ptr()); }
520 }
521
522 pub fn set_prop_string_array(&mut self, key: &str, values: &[&str]) {
524 let c_key = CString::new(key).unwrap();
527 let mut c_values: Vec<CString> = Vec::with_capacity(values.len());
528 for v in values {
529 c_values.push(CString::new(*v).unwrap());
530 }
531
532 let mut c_value_ptrs: Vec<*const c_char> = Vec::with_capacity(c_values.len());
534 for v in &c_values {
535 c_value_ptrs.push(v.as_ptr());
536 }
537 unsafe {
538 capi::pa_format_info_set_prop_string_array(self.ptr as *mut capi::pa_format_info,
539 c_key.as_ptr(), c_value_ptrs.as_ptr(), c_value_ptrs.len() as i32);
540 }
541 }
542
543 #[inline]
549 pub fn set_sample_format(&mut self, sf: sample::Format) {
550 unsafe { capi::pa_format_info_set_sample_format(self.ptr as *mut capi::pa_format_info,
551 sf.into()); }
552 }
553
554 #[inline]
560 pub fn set_rate(&mut self, rate: i32) {
561 unsafe { capi::pa_format_info_set_rate(self.ptr as *mut capi::pa_format_info, rate) }
562 }
563
564 #[inline]
570 pub fn set_channels(&mut self, channels: u32) {
571 debug_assert!(channels <= std::i32::MAX as u32);
572 unsafe { capi::pa_format_info_set_channels(self.ptr as *mut capi::pa_format_info,
573 channels as i32) }
574 }
575
576 #[inline]
582 pub fn set_channel_map(&mut self, map: &channelmap::Map) {
583 unsafe { capi::pa_format_info_set_channel_map(self.ptr as *mut capi::pa_format_info,
584 map.as_ref()) }
585 }
586}
587
588impl Drop for Info {
589 fn drop(&mut self) {
590 if !self.weak {
591 unsafe { capi::pa_format_info_free(self.ptr as *mut capi::pa_format_info) };
592 }
593 }
594}
595
596impl Clone for Info {
597 fn clone(&self) -> Self {
600 let ptr = unsafe { capi::pa_format_info_copy(self.ptr as *const capi::pa_format_info) };
601 assert_eq!(false, ptr.is_null());
602 Self::from_raw(ptr as *mut InfoInternal)
603 }
604}