use std;
use capi;
use std::os::raw::{c_char, c_void};
use std::ffi::{CStr, CString};
use std::borrow::Cow;
use std::ptr::{null, null_mut};
use super::{ContextInternal, Context};
use callbacks::{ListResult, box_closure_get_capi_ptr, callback_for_list_instance, ListInstanceCallback};
use operation::Operation;
use capi::pa_ext_stream_restore_info as InfoInternal;
#[derive(Debug)]
pub struct Info<'a> {
pub name: Option<Cow<'a, str>>,
pub channel_map: ::channelmap::Map,
pub volume: ::volume::ChannelVolumes,
pub device: Option<Cow<'a, str>>,
pub mute: bool,
}
impl<'a> Info<'a> {
fn new_from_raw(p: *const InfoInternal) -> Self {
assert!(!p.is_null());
let src = unsafe { p.as_ref().unwrap() };
unsafe {
Info {
name: match src.name.is_null() {
false => Some(CStr::from_ptr(src.name).to_string_lossy()),
true => None,
},
channel_map: std::mem::transmute(src.channel_map),
volume: std::mem::transmute(src.volume),
device: match src.name.is_null() {
false => Some(CStr::from_ptr(src.device).to_string_lossy()),
true => None,
},
mute: match src.mute { 0 => false, _ => true },
}
}
}
}
pub struct StreamRestore {
context: *mut ContextInternal,
cb_ptrs: CallbackPointers,
}
unsafe impl Send for StreamRestore {}
unsafe impl Sync for StreamRestore {}
#[derive(Default)]
struct CallbackPointers {
subscribe: super::ExtSubscribeCb,
}
impl Context {
pub fn stream_restore(&self) -> StreamRestore {
unsafe { capi::pa_context_ref(self.ptr) };
StreamRestore::from_raw(self.ptr)
}
}
impl StreamRestore {
fn from_raw(context: *mut ContextInternal) -> Self {
Self { context: context, cb_ptrs: Default::default() }
}
pub fn test<F>(&mut self, callback: F) -> Operation<dyn FnMut(u32)>
where F: FnMut(u32) + 'static
{
let cb_data = box_closure_get_capi_ptr::<dyn FnMut(u32)>(Box::new(callback));
let ptr = unsafe { capi::pa_ext_stream_restore_test(self.context,
Some(super::ext_test_cb_proxy), cb_data) };
assert!(!ptr.is_null());
Operation::from_raw(ptr, cb_data as *mut Box<dyn FnMut(u32)>)
}
pub fn read<F>(&mut self, callback: F) -> Operation<dyn FnMut(ListResult<&Info>)>
where F: FnMut(ListResult<&Info>) + 'static
{
let cb_data = box_closure_get_capi_ptr::<dyn FnMut(ListResult<&Info>)>(Box::new(callback));
let ptr = unsafe { capi::pa_ext_stream_restore_read(self.context, Some(read_list_cb_proxy),
cb_data) };
assert!(!ptr.is_null());
Operation::from_raw(ptr, cb_data as *mut Box<dyn FnMut(ListResult<&Info>)>)
}
pub fn write<F>(&mut self, mode: ::proplist::UpdateMode, data: &[&Info],
apply_immediately: bool, 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_ext_stream_restore_write(self.context, mode,
std::mem::transmute(data.as_ptr()), data.len() as u32, apply_immediately as i32,
Some(super::success_cb_proxy), cb_data)
};
assert!(!ptr.is_null());
Operation::from_raw(ptr, cb_data as *mut Box<dyn FnMut(bool)>)
}
pub fn delete<F>(&mut self, streams: &[&str], callback: F) -> Operation<dyn FnMut(bool)>
where F: FnMut(bool) + 'static
{
let mut c_streams: Vec<CString> = Vec::with_capacity(streams.len());
for stream in streams {
c_streams.push(CString::new(stream.clone()).unwrap());
}
let mut c_stream_ptrs: Vec<*const c_char> = Vec::with_capacity(c_streams.len() + 1);
for c_stream in c_streams {
c_stream_ptrs.push(c_stream.as_ptr());
}
c_stream_ptrs.push(null());
let cb_data = box_closure_get_capi_ptr::<dyn FnMut(bool)>(Box::new(callback));
let ptr = unsafe { capi::pa_ext_stream_restore_delete(self.context, c_stream_ptrs.as_ptr(),
Some(super::success_cb_proxy), cb_data) };
assert!(!ptr.is_null());
Operation::from_raw(ptr, cb_data as *mut Box<dyn FnMut(bool)>)
}
pub fn subscribe<F>(&mut self, enable: bool, 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_ext_stream_restore_subscribe(self.context, enable as i32,
Some(super::success_cb_proxy), cb_data) };
assert!(!ptr.is_null());
Operation::from_raw(ptr, cb_data as *mut Box<dyn FnMut(bool)>)
}
pub fn set_subscribe_cb<F>(&mut self, callback: F)
where F: FnMut() + 'static
{
let saved = &mut self.cb_ptrs.subscribe;
*saved = super::ExtSubscribeCb::new(Some(Box::new(callback)));
let (cb_fn, cb_data) = saved.get_capi_params(super::ext_subscribe_cb_proxy);
unsafe { capi::pa_ext_stream_restore_set_subscribe_cb(self.context, cb_fn, cb_data); }
}
}
impl Drop for StreamRestore {
fn drop(&mut self) {
unsafe { capi::pa_context_unref(self.context) };
self.context = null_mut::<ContextInternal>();
}
}
extern "C"
fn read_list_cb_proxy(_: *mut ContextInternal, i: *const InfoInternal, eol: i32,
userdata: *mut c_void)
{
let _ = std::panic::catch_unwind(|| {
match callback_for_list_instance::<dyn FnMut(ListResult<&Info>)>(eol, userdata) {
ListInstanceCallback::Entry(callback) => {
assert!(!i.is_null());
let obj = Info::new_from_raw(i);
(callback)(ListResult::Item(&obj));
},
ListInstanceCallback::End(mut callback) => { (callback)(ListResult::End); },
ListInstanceCallback::Error(mut callback) => { (callback)(ListResult::Error); },
}
});
}