use std::os::raw::{c_char, c_void};
use std::ffi::{CStr, CString};
use std::ptr::{null, null_mut};
use std::borrow::Cow;
use bitflags::bitflags;
use num_derive::{FromPrimitive, ToPrimitive};
use capi::pa_stream as StreamInternal;
use crate::{channelmap, format, def, proplist, sample};
use crate::callbacks::{self, box_closure_get_capi_ptr, get_su_capi_params, get_su_callback};
use crate::error::{self, PAErr};
use crate::format::InfoInternal;
use crate::proplist::{Proplist, ProplistInternal};
use crate::{context::Context, volume::ChannelVolumes, operation::Operation, time::MicroSeconds};
pub use capi::pa_seek_mode_t as SeekMode;
pub use capi::pa_stream_direction_t as Direction;
pub struct Stream {
ptr: *mut StreamInternal,
cb_ptrs: CallbackPointers,
}
unsafe impl Send for Stream {}
unsafe impl Sync for Stream {}
#[derive(Default)]
struct CallbackPointers {
read: RequestCb,
write: RequestCb,
set_state: NotifyCb,
overflow: NotifyCb,
underflow: NotifyCb,
started: NotifyCb,
latency_update: NotifyCb,
moved: NotifyCb,
suspended: NotifyCb,
buffer_attr: NotifyCb,
event: EventCb,
}
type RequestCb = callbacks::MultiUseCallback<dyn FnMut(usize),
extern "C" fn(*mut StreamInternal, usize, *mut c_void)>;
type NotifyCb = callbacks::MultiUseCallback<dyn FnMut(),
extern "C" fn(*mut StreamInternal, *mut c_void)>;
type EventCb = callbacks::MultiUseCallback<dyn FnMut(String, Proplist),
extern "C" fn(*mut StreamInternal, name: *const c_char, pl: *mut ProplistInternal, *mut c_void)>;
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[derive(FromPrimitive, ToPrimitive)]
pub enum State {
Unconnected,
Creating,
Ready,
Failed,
Terminated,
}
#[test]
fn state_compare_capi() {
assert_eq!(std::mem::size_of::<State>(), std::mem::size_of::<capi::pa_stream_state_t>());
assert_eq!(std::mem::align_of::<State>(), std::mem::align_of::<capi::pa_stream_state_t>());
assert_eq!(State::Unconnected, State::from(capi::pa_stream_state_t::Unconnected));
assert_eq!(State::Creating, State::from(capi::pa_stream_state_t::Creating));
assert_eq!(State::Ready, State::from(capi::pa_stream_state_t::Ready));
assert_eq!(State::Failed, State::from(capi::pa_stream_state_t::Failed));
assert_eq!(State::Terminated, State::from(capi::pa_stream_state_t::Terminated));
}
impl From<State> for capi::pa_stream_state_t {
#[inline]
fn from(s: State) -> Self {
unsafe { std::mem::transmute(s) }
}
}
impl From<capi::pa_stream_state_t> for State {
#[inline]
fn from(s: capi::pa_stream_state_t) -> Self {
unsafe { std::mem::transmute(s) }
}
}
impl State {
#[inline]
pub fn is_good(self) -> bool {
self == State::Creating || self == State::Ready
}
}
bitflags! {
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(transparent)]
pub struct FlagSet: u32 {
const NOFLAGS = capi::PA_STREAM_NOFLAGS;
const START_CORKED = capi::PA_STREAM_START_CORKED;
const INTERPOLATE_TIMING = capi::PA_STREAM_INTERPOLATE_TIMING;
const NOT_MONOTONIC = capi::PA_STREAM_NOT_MONOTONIC;
const AUTO_TIMING_UPDATE = capi::PA_STREAM_AUTO_TIMING_UPDATE;
const NO_REMAP_CHANNELS = capi::PA_STREAM_NO_REMAP_CHANNELS;
const NO_REMIX_CHANNELS = capi::PA_STREAM_NO_REMIX_CHANNELS;
const FIX_FORMAT = capi::PA_STREAM_FIX_FORMAT;
const FIX_RATE = capi::PA_STREAM_FIX_RATE;
const FIX_CHANNELS = capi::PA_STREAM_FIX_CHANNELS;
const DONT_MOVE = capi::PA_STREAM_DONT_MOVE;
const VARIABLE_RATE = capi::PA_STREAM_VARIABLE_RATE;
const PEAK_DETECT = capi::PA_STREAM_PEAK_DETECT;
const START_MUTED = capi::PA_STREAM_START_MUTED;
const ADJUST_LATENCY = capi::PA_STREAM_ADJUST_LATENCY;
const EARLY_REQUESTS = capi::PA_STREAM_EARLY_REQUESTS;
const DONT_INHIBIT_AUTO_SUSPEND = capi::PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND;
const START_UNMUTED = capi::PA_STREAM_START_UNMUTED;
const FAIL_ON_SUSPEND = capi::PA_STREAM_FAIL_ON_SUSPEND;
const RELATIVE_VOLUME = capi::PA_STREAM_RELATIVE_VOLUME;
const PASSTHROUGH = capi::PA_STREAM_PASSTHROUGH;
}
}
impl Default for FlagSet {
fn default() -> Self {
Self::NOFLAGS
}
}
pub mod event_names {
use capi;
pub const EVENT_REQUEST_CORK: &str = capi::PA_STREAM_EVENT_REQUEST_CORK;
pub const EVENT_REQUEST_UNCORK: &str = capi::PA_STREAM_EVENT_REQUEST_UNCORK;
pub const EVENT_FORMAT_LOST: &str = capi::PA_STREAM_EVENT_FORMAT_LOST;
}
#[derive(Debug)]
pub enum PeekResult<'a> {
Empty,
Hole(usize),
Data(&'a [u8]),
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Latency {
None,
Positive(MicroSeconds),
Negative(MicroSeconds),
}
impl Stream {
pub fn new(ctx: &mut Context, name: &str, ss: &sample::Spec, map: Option<&channelmap::Map>)
-> Option<Self>
{
let c_name = CString::new(name).unwrap();
let p_map = map.map_or(null::<capi::pa_channel_map>(), |m| m.as_ref());
let ptr = unsafe { capi::pa_stream_new(ctx.ptr, c_name.as_ptr(), ss.as_ref(), p_map) };
match ptr.is_null() {
false => Some(Self::from_raw(ptr)),
true => None,
}
}
pub fn new_with_proplist(ctx: &mut Context, name: &str, ss: &sample::Spec,
map: Option<&channelmap::Map>, proplist: &mut Proplist) -> Option<Self>
{
let c_name = CString::new(name).unwrap();
let p_map = map.map_or(null::<capi::pa_channel_map>(), |m| m.as_ref());
let ptr = unsafe {
capi::pa_stream_new_with_proplist(ctx.ptr, c_name.as_ptr(), ss.as_ref(),
p_map, proplist.0.ptr)
};
match ptr.is_null() {
false => Some(Self::from_raw(ptr)),
true => None,
}
}
pub fn new_extended(ctx: &mut Context, name: &str, formats: &[&format::Info],
proplist: &mut Proplist) -> Option<Self>
{
assert!(formats.len() <= u32::MAX as usize);
let c_name = CString::new(name).unwrap();
let mut info_ptrs: Vec<*const capi::pa_format_info> = Vec::with_capacity(formats.len());
for format in formats {
info_ptrs.push(format.ptr as *const capi::pa_format_info);
}
let ptr = unsafe {
capi::pa_stream_new_extended(ctx.ptr, c_name.as_ptr(), info_ptrs.as_ptr(),
info_ptrs.len() as u32, proplist.0.ptr)
};
match ptr.is_null() {
false => Some(Self::from_raw(ptr)),
true => None,
}
}
#[inline]
fn from_raw(ptr: *mut StreamInternal) -> Self {
assert_eq!(false, ptr.is_null());
Self { ptr: ptr, cb_ptrs: Default::default() }
}
#[inline]
pub fn get_state(&self) -> State {
unsafe { capi::pa_stream_get_state(self.ptr).into() }
}
pub fn get_index(&self) -> Option<u32> {
match unsafe { capi::pa_stream_get_index(self.ptr) } {
def::INVALID_INDEX => None,
r => Some(r),
}
}
pub fn get_device_index(&self) -> Option<u32> {
match unsafe { capi::pa_stream_get_device_index(self.ptr) } {
def::INVALID_INDEX => None,
r => Some(r),
}
}
pub fn get_device_name(&self) -> Option<Cow<'static, str>> {
let ptr: *const c_char = unsafe { capi::pa_stream_get_device_name(self.ptr) };
match ptr.is_null() {
false => Some(unsafe { CStr::from_ptr(ptr).to_string_lossy() }),
true => None,
}
}
pub fn is_suspended(&self) -> Result<bool, PAErr> {
match unsafe { capi::pa_stream_is_suspended(self.ptr) } {
0 => Ok(false),
1 => Ok(true),
e => Err(PAErr(e)),
}
}
pub fn is_corked(&self) -> Result<bool, PAErr> {
match unsafe { capi::pa_stream_is_corked(self.ptr) } {
0 => Ok(false),
1 => Ok(true),
e => Err(PAErr(e)),
}
}
pub fn connect_playback(&mut self, dev: Option<&str>, attr: Option<&def::BufferAttr>,
flags: FlagSet, volume: Option<&ChannelVolumes>, sync_stream: Option<&mut Self>)
-> Result<(), PAErr>
{
let c_dev = match dev {
Some(dev) => CString::new(dev).unwrap(),
None => CString::new("").unwrap(),
};
let p_attr = attr.map_or(null::<capi::pa_buffer_attr>(), |a| a.as_ref());
let p_vol = volume.map_or(null::<capi::pa_cvolume>(), |v| v.as_ref());
let p_sync = sync_stream.map_or(null_mut::<StreamInternal>(), |s| s.ptr);
let p_dev = dev.map_or(null::<c_char>(), |_| c_dev.as_ptr() as *const c_char);
let r = unsafe {
capi::pa_stream_connect_playback(self.ptr, p_dev, p_attr, flags.bits(), p_vol, p_sync)
};
match r {
0 => Ok(()),
e => Err(PAErr(e)),
}
}
pub fn connect_record(&mut self, dev: Option<&str>, attr: Option<&def::BufferAttr>,
flags: FlagSet) -> Result<(), PAErr>
{
let c_dev = match dev {
Some(dev) => CString::new(dev).unwrap(),
None => CString::new("").unwrap(),
};
let p_attr = attr.map_or(null::<capi::pa_buffer_attr>(), |a| a.as_ref());
let p_dev = dev.map_or(null::<c_char>(), |_| c_dev.as_ptr() as *const c_char);
match unsafe { capi::pa_stream_connect_record(self.ptr, p_dev, p_attr, flags.bits()) } {
0 => Ok(()),
e => Err(PAErr(e)),
}
}
pub fn connect_upload(&mut self, length: usize) -> Result<(), PAErr> {
match unsafe { capi::pa_stream_connect_upload(self.ptr, length) } {
0 => Ok(()),
e => Err(PAErr(e)),
}
}
pub fn finish_upload(&mut self) -> Result<(), PAErr> {
match unsafe { capi::pa_stream_finish_upload(self.ptr) } {
0 => Ok(()),
e => Err(PAErr(e)),
}
}
pub fn disconnect(&mut self) -> Result<(), PAErr> {
match unsafe { capi::pa_stream_disconnect(self.ptr) } {
0 => Ok(()),
e => Err(PAErr(e)),
}
}
pub fn begin_write<'a>(&mut self, nbytes: Option<usize>)
-> Result<Option<&'a mut [u8]>, PAErr>
{
let mut data_ptr = null_mut::<c_void>();
let mut nbytes_tmp = nbytes.unwrap_or(std::usize::MAX);
match unsafe { capi::pa_stream_begin_write(self.ptr, &mut data_ptr, &mut nbytes_tmp) } {
0 => match data_ptr.is_null() {
true => Ok(None),
false => {
let slice =
unsafe { std::slice::from_raw_parts_mut(data_ptr as *mut u8, nbytes_tmp) };
Ok(Some(slice))
},
},
e => Err(PAErr(e)),
}
}
pub fn cancel_write(&mut self) -> Result<(), PAErr> {
match unsafe { capi::pa_stream_cancel_write(self.ptr) } {
0 => Ok(()),
e => Err(PAErr(e)),
}
}
pub fn write(&mut self, data: &[u8], free_cb: Option<def::FreeCb>, offset: i64,
seek: SeekMode) -> Result<(), PAErr>
{
debug_assert_eq!(0, data.len().checked_rem(self.get_sample_spec().unwrap().frame_size())
.unwrap());
let r = unsafe {
capi::pa_stream_write(self.ptr, data.as_ptr() as *const c_void, data.len(), free_cb,
offset, seek)
};
match r {
0 => Ok(()),
e => Err(PAErr(e)),
}
}
#[inline(always)]
pub fn write_copy(&mut self, data: &[u8], offset: i64, seek: SeekMode) -> Result<(), PAErr> {
self.write(data, None, offset, seek)
}
#[cfg(any(doc, feature = "pa_v6"))]
#[cfg_attr(docsrs, doc(cfg(feature = "pa_v6")))]
pub fn write_ext_free(&mut self, data: &[u8], free_cb: Option<(def::FreeCb, *mut c_void)>,
offset: i64, seek: SeekMode) -> Result<(), PAErr>
{
let (cb_f, cb_d) = match free_cb {
Some((f, d)) => (Some(f), d),
None => (None, null_mut::<c_void>()),
};
debug_assert_eq!(0, data.len().checked_rem(self.get_sample_spec().unwrap().frame_size())
.unwrap());
let r = unsafe {
capi::pa_stream_write_ext_free(self.ptr, data.as_ptr() as *const c_void, data.len(),
cb_f, cb_d, offset, seek.into())
};
match r {
0 => Ok(()),
e => Err(PAErr(e)),
}
}
pub fn peek<'a>(&mut self) -> Result<PeekResult<'a>, PAErr> {
let mut data_ptr = null::<c_void>();
let mut nbytes: usize = 0;
match unsafe { capi::pa_stream_peek(self.ptr, &mut data_ptr, &mut nbytes) } {
0 => {
if data_ptr.is_null() {
match nbytes {
0 => Ok(PeekResult::Empty),
_ => Ok(PeekResult::Hole(nbytes)),
}
}
else {
let slice =
unsafe { std::slice::from_raw_parts(data_ptr as *const u8, nbytes) };
Ok(PeekResult::Data(slice))
}
},
e => Err(PAErr(e)),
}
}
pub fn discard(&mut self) -> Result<(), PAErr> {
match unsafe { capi::pa_stream_drop(self.ptr) } {
0 => Ok(()),
e => Err(PAErr(e)),
}
}
pub fn writable_size(&self) -> Option<usize> {
match unsafe { capi::pa_stream_writable_size(self.ptr) } {
std::usize::MAX => None,
r => Some(r),
}
}
pub fn readable_size(&self) -> Option<usize> {
match unsafe { capi::pa_stream_readable_size(self.ptr) } {
std::usize::MAX => None,
r => Some(r),
}
}
pub fn drain(&mut self, callback: Option<Box<dyn FnMut(bool) + 'static>>)
-> Operation<dyn FnMut(bool)>
{
let (cb_fn, cb_data): (Option<extern "C" fn(_, _, _)>, _) =
get_su_capi_params::<_, _>(callback, success_cb_proxy);
let ptr = unsafe { capi::pa_stream_drain(self.ptr, cb_fn, cb_data) };
Operation::from_raw(ptr, cb_data as *mut Box<dyn FnMut(bool)>)
}
pub fn update_timing_info(&mut self, callback: Option<Box<dyn FnMut(bool) + 'static>>)
-> Operation<dyn FnMut(bool)>
{
let (cb_fn, cb_data): (Option<extern "C" fn(_, _, _)>, _) =
get_su_capi_params::<_, _>(callback, success_cb_proxy);
let ptr = unsafe { capi::pa_stream_update_timing_info(self.ptr, cb_fn, cb_data) };
Operation::from_raw(ptr, cb_data as *mut Box<dyn FnMut(bool)>)
}
pub fn set_state_callback(&mut self, callback: Option<Box<dyn FnMut() + 'static>>) {
let saved = &mut self.cb_ptrs.set_state;
*saved = NotifyCb::new(callback);
let (cb_fn, cb_data) = saved.get_capi_params(notify_cb_proxy);
unsafe { capi::pa_stream_set_state_callback(self.ptr, cb_fn, cb_data); }
}
pub fn set_write_callback(&mut self, callback: Option<Box<dyn FnMut(usize) + 'static>>) {
let saved = &mut self.cb_ptrs.write;
*saved = RequestCb::new(callback);
let (cb_fn, cb_data) = saved.get_capi_params(request_cb_proxy);
unsafe { capi::pa_stream_set_write_callback(self.ptr, cb_fn, cb_data); }
}
pub fn set_read_callback(&mut self, callback: Option<Box<dyn FnMut(usize) + 'static>>) {
let saved = &mut self.cb_ptrs.read;
*saved = RequestCb::new(callback);
let (cb_fn, cb_data) = saved.get_capi_params(request_cb_proxy);
unsafe { capi::pa_stream_set_read_callback(self.ptr, cb_fn, cb_data); }
}
pub fn set_overflow_callback(&mut self, callback: Option<Box<dyn FnMut() + 'static>>) {
let saved = &mut self.cb_ptrs.overflow;
*saved = NotifyCb::new(callback);
let (cb_fn, cb_data) = saved.get_capi_params(notify_cb_proxy);
unsafe { capi::pa_stream_set_overflow_callback(self.ptr, cb_fn, cb_data); }
}
pub fn get_underflow_index(&self) -> Option<u64> {
match unsafe { capi::pa_stream_get_underflow_index(self.ptr) } {
r if r < 0 => None,
r => Some(r as u64),
}
}
pub fn set_underflow_callback(&mut self, callback: Option<Box<dyn FnMut() + 'static>>) {
let saved = &mut self.cb_ptrs.underflow;
*saved = NotifyCb::new(callback);
let (cb_fn, cb_data) = saved.get_capi_params(notify_cb_proxy);
unsafe { capi::pa_stream_set_underflow_callback(self.ptr, cb_fn, cb_data); }
}
pub fn set_started_callback(&mut self, callback: Option<Box<dyn FnMut() + 'static>>) {
let saved = &mut self.cb_ptrs.started;
*saved = NotifyCb::new(callback);
let (cb_fn, cb_data) = saved.get_capi_params(notify_cb_proxy);
unsafe { capi::pa_stream_set_started_callback(self.ptr, cb_fn, cb_data); }
}
pub fn set_latency_update_callback(&mut self, callback: Option<Box<dyn FnMut() + 'static>>) {
let saved = &mut self.cb_ptrs.latency_update;
*saved = NotifyCb::new(callback);
let (cb_fn, cb_data) = saved.get_capi_params(notify_cb_proxy);
unsafe { capi::pa_stream_set_latency_update_callback(self.ptr, cb_fn, cb_data); }
}
pub fn set_moved_callback(&mut self, callback: Option<Box<dyn FnMut() + 'static>>) {
let saved = &mut self.cb_ptrs.moved;
*saved = NotifyCb::new(callback);
let (cb_fn, cb_data) = saved.get_capi_params(notify_cb_proxy);
unsafe { capi::pa_stream_set_moved_callback(self.ptr, cb_fn, cb_data); }
}
pub fn set_suspended_callback(&mut self, callback: Option<Box<dyn FnMut() + 'static>>) {
let saved = &mut self.cb_ptrs.suspended;
*saved = NotifyCb::new(callback);
let (cb_fn, cb_data) = saved.get_capi_params(notify_cb_proxy);
unsafe { capi::pa_stream_set_suspended_callback(self.ptr, cb_fn, cb_data); }
}
pub fn set_event_callback(&mut self,
callback: Option<Box<dyn FnMut(String, Proplist) + 'static>>)
{
let saved = &mut self.cb_ptrs.event;
*saved = EventCb::new(callback);
let (cb_fn, cb_data) = saved.get_capi_params(event_cb_proxy);
unsafe { capi::pa_stream_set_event_callback(self.ptr, cb_fn, cb_data); }
}
pub fn set_buffer_attr_callback(&mut self, callback: Option<Box<dyn FnMut() + 'static>>) {
let saved = &mut self.cb_ptrs.buffer_attr;
*saved = NotifyCb::new(callback);
let (cb_fn, cb_data) = saved.get_capi_params(notify_cb_proxy);
unsafe { capi::pa_stream_set_buffer_attr_callback(self.ptr, cb_fn, cb_data); }
}
#[inline(always)]
pub fn cork(&mut self, callback: Option<Box<dyn FnMut(bool) + 'static>>)
-> Operation<dyn FnMut(bool)>
{
self.set_corked_state(true, callback)
}
#[inline(always)]
pub fn uncork(&mut self, callback: Option<Box<dyn FnMut(bool) + 'static>>)
-> Operation<dyn FnMut(bool)>
{
self.set_corked_state(false, callback)
}
pub fn set_corked_state(&mut self, state: bool, callback: Option<Box<dyn FnMut(bool) + 'static>>)
-> Operation<dyn FnMut(bool)>
{
let (cb_fn, cb_data): (Option<extern "C" fn(_, _, _)>, _) =
get_su_capi_params::<_, _>(callback, success_cb_proxy);
let ptr = unsafe { capi::pa_stream_cork(self.ptr, state as i32, cb_fn, cb_data) };
Operation::from_raw(ptr, cb_data as *mut Box<dyn FnMut(bool)>)
}
pub fn flush(&mut self, callback: Option<Box<dyn FnMut(bool) + 'static>>)
-> Operation<dyn FnMut(bool)>
{
let (cb_fn, cb_data): (Option<extern "C" fn(_, _, _)>, _) =
get_su_capi_params::<_, _>(callback, success_cb_proxy);
let ptr = unsafe { capi::pa_stream_flush(self.ptr, cb_fn, cb_data) };
Operation::from_raw(ptr, cb_data as *mut Box<dyn FnMut(bool)>)
}
pub fn prebuf(&mut self, callback: Option<Box<dyn FnMut(bool) + 'static>>)
-> Operation<dyn FnMut(bool)>
{
let (cb_fn, cb_data): (Option<extern "C" fn(_, _, _)>, _) =
get_su_capi_params::<_, _>(callback, success_cb_proxy);
let ptr = unsafe { capi::pa_stream_prebuf(self.ptr, cb_fn, cb_data) };
Operation::from_raw(ptr, cb_data as *mut Box<dyn FnMut(bool)>)
}
pub fn trigger(&mut self, callback: Option<Box<dyn FnMut(bool) + 'static>>)
-> Operation<dyn FnMut(bool)>
{
let (cb_fn, cb_data): (Option<extern "C" fn(_, _, _)>, _) =
get_su_capi_params::<_, _>(callback, success_cb_proxy);
let ptr = unsafe { capi::pa_stream_trigger(self.ptr, cb_fn, cb_data) };
Operation::from_raw(ptr, cb_data as *mut Box<dyn FnMut(bool)>)
}
pub fn set_name(&mut self, name: &str, callback: Option<Box<dyn FnMut(bool) + 'static>>)
-> Operation<dyn FnMut(bool)>
{
let c_name = CString::new(name).unwrap();
let (cb_fn, cb_data): (Option<extern "C" fn(_, _, _)>, _) =
get_su_capi_params::<_, _>(callback, success_cb_proxy);
let ptr = unsafe { capi::pa_stream_set_name(self.ptr, c_name.as_ptr(), cb_fn, cb_data) };
Operation::from_raw(ptr, cb_data as *mut Box<dyn FnMut(bool)>)
}
pub fn get_time(&self) -> Result<Option<MicroSeconds>, PAErr> {
let mut r_usecs = MicroSeconds(0);
match unsafe { capi::pa_stream_get_time(self.ptr, &mut r_usecs.0) } {
0 => Ok(Some(r_usecs)),
e if e == PAErr::from(error::Code::NoData).0 => Ok(None),
e => Err(PAErr(e)),
}
}
pub fn get_latency(&self) -> Result<Latency, PAErr> {
let mut r_usecs = MicroSeconds(0);
let mut negative: i32 = 0;
match unsafe { capi::pa_stream_get_latency(self.ptr, &mut r_usecs.0, &mut negative) } {
0 => match negative {
1 => Ok(Latency::Negative(r_usecs)),
_ => Ok(Latency::Positive(r_usecs)),
},
e if e == PAErr::from(error::Code::NoData).0 => Ok(Latency::None),
e => Err(PAErr(e)),
}
}
pub fn get_timing_info<'a>(&mut self) -> Option<&'a def::TimingInfo> {
unsafe {
let ptr = capi::pa_stream_get_timing_info(self.ptr);
ptr.as_ref().map(|r| r.as_ref())
}
}
pub fn get_sample_spec<'a>(&mut self) -> Option<&'a sample::Spec> {
unsafe {
let ptr = capi::pa_stream_get_sample_spec(self.ptr);
ptr.as_ref().map(|r| r.as_ref())
}
}
pub fn get_channel_map<'a>(&mut self) -> Option<&'a channelmap::Map> {
unsafe {
let ptr = capi::pa_stream_get_channel_map(self.ptr);
ptr.as_ref().map(|r| r.as_ref())
}
}
pub fn get_format_info(&self) -> Option<format::Info> {
let ptr = unsafe { capi::pa_stream_get_format_info(self.ptr) };
match ptr.is_null() {
false => Some(format::Info::from_raw_weak(ptr as *mut InfoInternal)),
true => None,
}
}
pub fn get_buffer_attr<'a>(&mut self) -> Option<&'a def::BufferAttr> {
unsafe {
let ptr = capi::pa_stream_get_buffer_attr(self.ptr);
ptr.as_ref().map(|r| r.as_ref())
}
}
pub fn set_buffer_attr<F>(&mut self, attr: &def::BufferAttr, callback: F)
-> Operation<dyn FnMut(bool)>
where F: FnMut(bool) + 'static
{
let cb_data = box_closure_get_capi_ptr::<dyn FnMut(bool)>(Box::new(callback));
let ptr = unsafe { capi::pa_stream_set_buffer_attr(self.ptr, attr.as_ref(),
Some(success_cb_proxy), cb_data) };
Operation::from_raw(ptr, cb_data as *mut Box<dyn FnMut(bool)>)
}
pub fn update_sample_rate<F>(&mut self, rate: u32, callback: F) -> Operation<dyn FnMut(bool)>
where F: FnMut(bool) + 'static
{
let cb_data = box_closure_get_capi_ptr::<dyn FnMut(bool)>(Box::new(callback));
let ptr = unsafe { capi::pa_stream_update_sample_rate(self.ptr, rate,
Some(success_cb_proxy), cb_data) };
Operation::from_raw(ptr, cb_data as *mut Box<dyn FnMut(bool)>)
}
pub fn update_proplist<F>(&mut self, mode: proplist::UpdateMode, proplist: &mut Proplist,
callback: F) -> Operation<dyn FnMut(bool)>
where F: FnMut(bool) + 'static
{
let cb_data = box_closure_get_capi_ptr::<dyn FnMut(bool)>(Box::new(callback));
let ptr = unsafe { capi::pa_stream_proplist_update(self.ptr, mode, proplist.0.ptr,
Some(success_cb_proxy), cb_data) };
Operation::from_raw(ptr, cb_data as *mut Box<dyn FnMut(bool)>)
}
pub fn remove_proplist<F>(&mut self, keys: &[&str], callback: F) -> Operation<dyn FnMut(bool)>
where F: FnMut(bool) + 'static
{
let mut c_keys: Vec<CString> = Vec::with_capacity(keys.len());
for key in keys {
c_keys.push(CString::new(*key).unwrap());
}
let mut c_key_ptrs: Vec<*const c_char> = Vec::with_capacity(c_keys.len() + 1);
for c_key in &c_keys {
c_key_ptrs.push(c_key.as_ptr());
}
c_key_ptrs.push(null());
let cb_data = box_closure_get_capi_ptr::<dyn FnMut(bool)>(Box::new(callback));
let ptr = unsafe {
capi::pa_stream_proplist_remove(self.ptr, c_key_ptrs.as_ptr(),
Some(success_cb_proxy), cb_data)
};
Operation::from_raw(ptr, cb_data as *mut Box<dyn FnMut(bool)>)
}
pub fn set_monitor_stream(&mut self, sink_input_index: u32) -> Result<(), PAErr> {
match unsafe { capi::pa_stream_set_monitor_stream(self.ptr, sink_input_index) } {
0 => Ok(()),
e => Err(PAErr(e)),
}
}
pub fn get_monitor_stream(&self) -> Option<u32> {
match unsafe { capi::pa_stream_get_monitor_stream(self.ptr) } {
def::INVALID_INDEX => None,
r => Some(r),
}
}
}
impl Drop for Stream {
fn drop(&mut self) {
let _ = self.disconnect();
unsafe { capi::pa_stream_unref(self.ptr) };
self.ptr = null_mut::<StreamInternal>();
}
}
extern "C"
fn success_cb_proxy(_: *mut StreamInternal, success: i32, userdata: *mut c_void) {
let success_actual = match success { 0 => false, _ => true };
let _ = std::panic::catch_unwind(|| {
let mut callback = get_su_callback::<dyn FnMut(bool)>(userdata);
(callback)(success_actual);
});
}
extern "C"
fn request_cb_proxy(_: *mut StreamInternal, nbytes: usize, userdata: *mut c_void) {
let _ = std::panic::catch_unwind(|| {
let callback = RequestCb::get_callback(userdata);
(callback)(nbytes);
});
}
extern "C"
fn notify_cb_proxy(_: *mut StreamInternal, userdata: *mut c_void) {
let _ = std::panic::catch_unwind(|| {
let callback = NotifyCb::get_callback(userdata);
(callback)();
});
}
extern "C"
fn event_cb_proxy(_: *mut StreamInternal, name: *const c_char, proplist: *mut ProplistInternal,
userdata: *mut c_void)
{
let _ = std::panic::catch_unwind(|| {
assert!(!name.is_null());
let n = {
let tmp = unsafe { CStr::from_ptr(name) };
tmp.to_string_lossy().into_owned()
};
let pl = Proplist::from_raw_weak(proplist);
let callback = EventCb::get_callback(userdata);
(callback)(n, pl);
});
}