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, Default, 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 #[default]
66 Invalid = -1,
67}
68
69#[test]
71fn enc_compare_capi() {
72 assert_eq!(std::mem::size_of::<Encoding>(), std::mem::size_of::<capi::pa_encoding_t>());
73 assert_eq!(std::mem::align_of::<Encoding>(), std::mem::align_of::<capi::pa_encoding_t>());
74
75 assert_eq!(Encoding::Any, Encoding::from(capi::pa_encoding_t::Any));
78 assert_eq!(Encoding::PCM, Encoding::from(capi::pa_encoding_t::PCM));
79 assert_eq!(Encoding::AC3_IEC61937, Encoding::from(capi::pa_encoding_t::AC3_IEC61937));
80 assert_eq!(Encoding::EAC3_IEC61937, Encoding::from(capi::pa_encoding_t::EAC3_IEC61937));
81 assert_eq!(Encoding::MPEG_IEC61937, Encoding::from(capi::pa_encoding_t::MPEG_IEC61937));
82 assert_eq!(Encoding::DTS_IEC61937, Encoding::from(capi::pa_encoding_t::DTS_IEC61937));
83 assert_eq!(Encoding::MPEG2_AAC_IEC61937, Encoding::from(capi::pa_encoding_t::MPEG2_AAC_IEC61937));
84 #[cfg(any(doc, feature = "pa_v13"))]
85 assert_eq!(Encoding::TRUEHD_IEC61937, Encoding::from(capi::pa_encoding_t::TRUEHD_IEC61937));
86 #[cfg(any(doc, feature = "pa_v13"))]
87 assert_eq!(Encoding::DTSHD_IEC61937, Encoding::from(capi::pa_encoding_t::DTSHD_IEC61937));
88 assert_eq!(Encoding::Invalid, Encoding::from(capi::pa_encoding_t::Invalid));
89}
90
91impl From<Encoding> for capi::pa_encoding_t {
92 #[inline]
93 fn from(e: Encoding) -> Self {
94 unsafe { std::mem::transmute(e) }
95 }
96}
97impl From<capi::pa_encoding_t> for Encoding {
98 #[inline]
99 fn from(e: capi::pa_encoding_t) -> Self {
100 unsafe { std::mem::transmute(e) }
101 }
102}
103
104pub struct Info {
106 pub(crate) ptr: *mut InfoInternal,
108 properties: Proplist,
110 weak: bool,
112}
113
114unsafe impl Send for Info {}
115unsafe impl Sync for Info {}
116
117#[repr(C)]
119pub(crate) struct InfoInternal {
120 pub encoding: Encoding,
123 pub list: *mut ProplistInternal,
125}
126
127#[test]
129fn info_compare_capi() {
130 assert_eq!(std::mem::size_of::<InfoInternal>(), std::mem::size_of::<capi::pa_format_info>());
131 assert_eq!(std::mem::align_of::<InfoInternal>(), std::mem::align_of::<capi::pa_format_info>());
132}
133
134impl std::fmt::Debug for Info {
135 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
136 write!(f, "Info {{ encoding: {:?}, properties: {:?} }}", self.get_encoding(),
137 *self.get_properties())
138 }
139}
140
141impl Encoding {
142 pub fn to_string(e: Self) -> Option<Cow<'static, str>> {
144 let ptr = unsafe { capi::pa_encoding_to_string(e.into()) };
145 match ptr.is_null() {
146 false => Some(unsafe { CStr::from_ptr(ptr).to_string_lossy() }),
147 true => None,
148 }
149 }
150
151 #[cfg(any(doc, feature = "pa_v12"))]
154 #[cfg_attr(docsrs, doc(cfg(feature = "pa_v12")))]
155 pub fn from_string(encoding: &str) -> Self {
156 let c_enc = CString::new(encoding).unwrap();
159 unsafe { capi::pa_encoding_from_string(c_enc.as_ptr()).into() }
160 }
161}
162
163impl Info {
164 pub fn new() -> Option<Self> {
168 let ptr = unsafe { capi::pa_format_info_new() };
169 match ptr.is_null() {
170 false => Some(Self::from_raw(ptr as *mut InfoInternal)),
171 true => None,
172 }
173 }
174
175 pub fn new_from_string(s: &str) -> Option<Self> {
180 let c_str = CString::new(s).unwrap();
183 let ptr = unsafe { capi::pa_format_info_from_string(c_str.as_ptr()) };
184 match ptr.is_null() {
185 false => Some(Self::from_raw(ptr as *mut InfoInternal)),
186 true => None,
187 }
188 }
189
190 pub fn new_from_sample_spec(ss: &sample::Spec, map: Option<&channelmap::Map>) -> Option<Self> {
203 let p_map = map.map_or(null::<capi::pa_channel_map>(), |m| m.as_ref());
204 let ptr = unsafe { capi::pa_format_info_from_sample_spec(ss.as_ref(), p_map) };
205 match ptr.is_null() {
206 false => Some(Self::from_raw(ptr as *mut InfoInternal)),
207 true => None,
208 }
209 }
210
211 pub(crate) fn from_raw(ptr: *mut InfoInternal) -> Self {
213 assert_eq!(false, ptr.is_null());
214 let pl = Proplist::from_raw_weak(unsafe { (*ptr).list });
217 Self { ptr: ptr, properties: pl, weak: false }
218 }
219
220 pub(crate) fn from_raw_weak(ptr: *mut InfoInternal) -> Self {
224 assert_eq!(false, ptr.is_null());
225 let pl = Proplist::from_raw_weak(unsafe { (*ptr).list });
226 Self { ptr: ptr, properties: pl, weak: true }
227 }
228
229 #[inline]
233 pub(crate) fn to_owned(&self) -> Self {
234 let ptr = unsafe { capi::pa_format_info_copy(self.ptr as *const capi::pa_format_info) };
235 Self::from_raw(ptr as *mut InfoInternal)
236 }
237
238 #[inline]
240 pub fn is_valid(&self) -> bool {
241 unsafe { capi::pa_format_info_valid(self.ptr as *const capi::pa_format_info) != 0 }
242 }
243
244 #[inline]
246 pub fn is_pcm(&self) -> bool {
247 unsafe { capi::pa_format_info_is_pcm(self.ptr as *const capi::pa_format_info) != 0 }
248 }
249
250 #[inline]
258 pub fn is_compatible_with(&self, with: &Self) -> bool {
259 unsafe { capi::pa_format_info_is_compatible(self.ptr as *const capi::pa_format_info,
260 with.ptr as *const capi::pa_format_info) != 0 }
261 }
262
263 pub fn print(&self) -> String {
265 const PRINT_MAX: usize = capi::PA_FORMAT_INFO_SNPRINT_MAX;
266 let mut tmp = Vec::with_capacity(PRINT_MAX);
267 unsafe {
268 capi::pa_format_info_snprint(tmp.as_mut_ptr(), PRINT_MAX,
269 self.ptr as *const capi::pa_format_info);
270 CStr::from_ptr(tmp.as_mut_ptr()).to_string_lossy().into_owned()
271 }
272 }
273
274 pub fn to_sample_spec(&self, ss: &mut sample::Spec, map: &mut channelmap::Map)
284 -> Result<(), PAErr>
285 {
286 match unsafe { capi::pa_format_info_to_sample_spec(
287 self.ptr as *const capi::pa_format_info, ss.as_mut(), map.as_mut()) }
288 {
289 0 => Ok(()),
290 e => Err(PAErr(e)),
291 }
292 }
293
294 #[inline]
296 pub fn get_encoding(&self) -> Encoding {
297 unsafe { (*self.ptr).encoding }
298 }
299
300 #[inline]
302 pub fn set_encoding(&mut self, encoding: Encoding) {
303 unsafe { (*self.ptr).encoding = encoding };
304 }
305
306 #[inline]
308 pub fn get_properties(&self) -> &Proplist {
309 &self.properties
310 }
311
312 #[inline]
314 pub fn get_properties_mut(&mut self) -> &mut Proplist {
315 &mut self.properties
316 }
317
318 pub fn get_prop_type(&self, key: &str) -> PropType {
320 let c_key = CString::new(key).unwrap();
323 unsafe { capi::pa_format_info_get_prop_type(self.ptr as *const capi::pa_format_info,
324 c_key.as_ptr()) }
325 }
326
327 pub fn get_prop_int(&self, key: &str) -> Result<i32, PAErr> {
329 let mut i: i32 = 0;
332 let c_key = CString::new(key).unwrap();
333 match unsafe { capi::pa_format_info_get_prop_int(self.ptr as *const capi::pa_format_info,
334 c_key.as_ptr(), &mut i) }
335 {
336 0 => Ok(i),
337 e => Err(PAErr(e)),
338 }
339 }
340
341 pub fn get_prop_int_range(&self, key: &str) -> Result<(i32, i32), PAErr> {
343 let mut min: i32 = 0;
346 let mut max: i32 = 0;
347 let c_key = CString::new(key).unwrap();
348 match unsafe { capi::pa_format_info_get_prop_int_range(
349 self.ptr as *const capi::pa_format_info, c_key.as_ptr(), &mut min, &mut max) }
350 {
351 0 => Ok((min, max)),
352 e => Err(PAErr(e)),
353 }
354 }
355
356 pub fn get_prop_int_array(&self, key: &str) -> Option<Vec<i32>> {
360 let c_key = CString::new(key).unwrap();
363 let mut count: i32 = 0;
364 let mut p_ints = null_mut::<i32>();
365 let result = unsafe { capi::pa_format_info_get_prop_int_array(
366 self.ptr as *const capi::pa_format_info, c_key.as_ptr(), &mut p_ints, &mut count) };
367 if result != 0 {
368 return None;
369 }
370 let mut values: Vec<i32> = Vec::with_capacity(count as usize);
372 for i in 0..count {
373 values.push(unsafe { *p_ints.offset(i as isize) });
374 }
375 unsafe { capi::pa_xfree(p_ints as *mut c_void) };
377 Some(values)
379 }
380
381 pub fn get_prop_string(&self, key: &str) -> Option<String> {
383 let c_key = CString::new(key).unwrap();
386 let mut p_str = null_mut::<c_char>();
387 let result = unsafe { capi::pa_format_info_get_prop_string(
388 self.ptr as *const capi::pa_format_info, c_key.as_ptr(), &mut p_str) };
389 if result != 0 || p_str.is_null() {
390 return None;
391 }
392 unsafe {
393 let ret = Some(CStr::from_ptr(p_str).to_string_lossy().into_owned());
394 capi::pa_xfree(p_str as *mut c_void);
395 ret
396 }
397 }
398
399 pub fn get_prop_string_array(&self, key: &str) -> Option<Vec<String>> {
401 let c_key = CString::new(key).unwrap();
404 let mut count: i32 = 0;
405 let mut pp_str = null_mut::<*mut c_char>();
406 let result = unsafe { capi::pa_format_info_get_prop_string_array(
407 self.ptr as *const capi::pa_format_info, c_key.as_ptr(), &mut pp_str, &mut count) };
408 if result != 0 || pp_str.is_null() {
409 return None;
410 }
411 let mut values: Vec<String> = Vec::with_capacity(count as usize);
413 for i in 0..count {
414 let p_str = unsafe { *pp_str.offset(i as isize) };
415 if !p_str.is_null() {
416 values.push(unsafe { CStr::from_ptr(p_str).to_string_lossy().into_owned() });
417 }
418 }
419 unsafe { capi::pa_format_info_free_string_array(pp_str, count) };
421 Some(values)
423 }
424
425 #[cfg(any(doc, feature = "pa_v13"))]
429 #[cfg_attr(docsrs, doc(cfg(feature = "pa_v13")))]
430 pub fn get_sample_format(&self) -> Result<crate::sample::Format, PAErr> {
431 let mut sf: capi::pa_sample_format_t = capi::PA_SAMPLE_INVALID;
432 match unsafe { capi::pa_format_info_get_sample_format(
433 self.ptr as *const capi::pa_format_info, &mut sf) }
434 {
435 0 => Ok(crate::sample::Format::from(sf)),
436 e => Err(PAErr(e)),
437 }
438 }
439
440 #[cfg(any(doc, feature = "pa_v13"))]
444 #[cfg_attr(docsrs, doc(cfg(feature = "pa_v13")))]
445 pub fn get_rate(&self) -> Result<u32, PAErr> {
446 let mut rate: u32 = 0;
447 match unsafe { capi::pa_format_info_get_rate(self.ptr as *const capi::pa_format_info,
448 &mut rate) }
449 {
450 0 => Ok(rate),
451 e => Err(PAErr(e)),
452 }
453 }
454
455 #[cfg(any(doc, feature = "pa_v13"))]
459 #[cfg_attr(docsrs, doc(cfg(feature = "pa_v13")))]
460 pub fn get_channel_count(&self) -> Result<u8, PAErr> {
461 let mut channels: u8 = 0;
462 match unsafe { capi::pa_format_info_get_channels(self.ptr as *const capi::pa_format_info,
463 &mut channels) }
464 {
465 0 => Ok(channels),
466 e => Err(PAErr(e)),
467 }
468 }
469
470 #[cfg(any(doc, feature = "pa_v13"))]
475 #[cfg_attr(docsrs, doc(cfg(feature = "pa_v13")))]
476 pub fn get_channel_map(&self) -> Result<crate::channelmap::Map, PAErr> {
477 let mut map: capi::pa_channel_map = capi::pa_channel_map::default();
482 match unsafe { capi::pa_format_info_get_channel_map(
483 self.ptr as *const capi::pa_format_info, &mut map) }
484 {
485 0 => Ok(crate::channelmap::Map::from(map)),
486 e => Err(PAErr(e)),
487 }
488 }
489
490 pub fn set_prop_int(&mut self, key: &str, value: i32) {
492 let c_key = CString::new(key).unwrap();
495 unsafe { capi::pa_format_info_set_prop_int(self.ptr as *mut capi::pa_format_info,
496 c_key.as_ptr(), value); }
497 }
498
499 pub fn set_prop_int_array(&mut self, key: &str, values: &[i32]) {
503 assert!(values.len() <= i32::MAX as usize);
504 let c_key = CString::new(key).unwrap();
507 unsafe { capi::pa_format_info_set_prop_int_array(self.ptr as *mut capi::pa_format_info,
508 c_key.as_ptr(), values.as_ptr(), values.len() as i32); }
509 }
510
511 pub fn set_prop_int_range(&mut self, key: &str, min: i32, max: i32) {
513 let c_key = CString::new(key).unwrap();
516 unsafe { capi::pa_format_info_set_prop_int_range(self.ptr as *mut capi::pa_format_info,
517 c_key.as_ptr(), min, max); }
518 }
519
520 pub fn set_prop_string(&mut self, key: &str, value: &str) {
522 let c_key = CString::new(key).unwrap();
525 let c_value = CString::new(value).unwrap();
526 unsafe { capi::pa_format_info_set_prop_string(self.ptr as *mut capi::pa_format_info,
527 c_key.as_ptr(), c_value.as_ptr()); }
528 }
529
530 pub fn set_prop_string_array(&mut self, key: &str, values: &[&str]) {
534 assert!(values.len() <= i32::MAX as usize);
535 let c_key = CString::new(key).unwrap();
538 let mut c_values: Vec<CString> = Vec::with_capacity(values.len());
539 for v in values {
540 c_values.push(CString::new(*v).unwrap());
541 }
542
543 let mut c_value_ptrs: Vec<*const c_char> = Vec::with_capacity(c_values.len());
545 for v in &c_values {
546 c_value_ptrs.push(v.as_ptr());
547 }
548 unsafe {
549 capi::pa_format_info_set_prop_string_array(self.ptr as *mut capi::pa_format_info,
550 c_key.as_ptr(), c_value_ptrs.as_ptr(), c_value_ptrs.len() as i32);
551 }
552 }
553
554 #[inline]
560 pub fn set_sample_format(&mut self, sf: sample::Format) {
561 unsafe { capi::pa_format_info_set_sample_format(self.ptr as *mut capi::pa_format_info,
562 sf.into()); }
563 }
564
565 #[inline]
571 pub fn set_rate(&mut self, rate: i32) {
572 unsafe { capi::pa_format_info_set_rate(self.ptr as *mut capi::pa_format_info, rate) }
573 }
574
575 #[inline]
583 pub fn set_channels(&mut self, channels: u32) {
584 assert!(channels <= std::i32::MAX as u32);
585 unsafe { capi::pa_format_info_set_channels(self.ptr as *mut capi::pa_format_info,
586 channels as i32) }
587 }
588
589 #[inline]
595 pub fn set_channel_map(&mut self, map: &channelmap::Map) {
596 unsafe { capi::pa_format_info_set_channel_map(self.ptr as *mut capi::pa_format_info,
597 map.as_ref()) }
598 }
599}
600
601impl Drop for Info {
602 fn drop(&mut self) {
603 if !self.weak {
604 unsafe { capi::pa_format_info_free(self.ptr as *mut capi::pa_format_info) };
605 }
606 }
607}
608
609impl Clone for Info {
610 fn clone(&self) -> Self {
614 self.to_owned()
615 }
616}