pub mod ext_device_manager;
pub mod ext_device_restore;
pub mod ext_stream_restore;
pub mod introspect;
pub mod scache;
pub mod subscribe;
use std;
use capi;
use std::os::raw::{c_char, c_void};
use std::ffi::{CStr, CString};
use std::ptr::{null, null_mut};
use mainloop::events::timer::{TimeEvent, TimeEventCb};
use operation::Operation;
use error::PAErr;
use timeval::MicroSeconds;
use proplist::Proplist;
use capi::pa_context as ContextInternal;
pub struct Context {
pub(crate) ptr: *mut ContextInternal,
weak: bool,
cb_ptrs: CallbackPointers,
}
#[derive(Default)]
struct CallbackPointers {
set_state: NotifyCb,
subscribe: self::subscribe::Callback,
event: EventCb,
}
type NotifyCb = ::callbacks::MultiUseCallback<FnMut(),
extern "C" fn(*mut ContextInternal, *mut c_void)>;
type EventCb = ::callbacks::MultiUseCallback<FnMut(String, Proplist),
extern "C" fn(*mut ContextInternal, name: *const c_char, pl: *mut ::proplist::ProplistInternal,
*mut c_void)>;
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum State {
Unconnected,
Connecting,
Authorizing,
SettingName,
Ready,
Failed,
Terminated,
}
impl From<State> for capi::pa_context_state_t {
fn from(s: State) -> Self {
unsafe { std::mem::transmute(s) }
}
}
impl From<capi::pa_context_state_t> for State {
fn from(s: capi::pa_context_state_t) -> Self {
unsafe { std::mem::transmute(s) }
}
}
impl State {
pub fn is_good(self) -> bool {
self == State::Connecting ||
self == State::Authorizing ||
self == State::SettingName ||
self == State::Ready
}
}
pub type FlagSet = capi::pa_context_flags_t;
pub mod flags {
use capi;
use super::FlagSet;
pub const NOFLAGS: FlagSet = capi::PA_CONTEXT_NOFLAGS;
pub const NOAUTOSPAWN: FlagSet = capi::PA_CONTEXT_NOAUTOSPAWN;
pub const NOFAIL: FlagSet = capi::PA_CONTEXT_NOFAIL;
}
impl Context {
pub fn new(mainloop_api: &mut ::mainloop::api::MainloopApi, name: &str) -> Option<Self> {
let c_name = CString::new(name.clone()).unwrap();
let ptr = unsafe { capi::pa_context_new(std::mem::transmute(mainloop_api), c_name.as_ptr()) };
if ptr.is_null() {
return None;
}
Some(Self::from_raw(ptr))
}
pub fn new_with_proplist(mainloop_api: &mut ::mainloop::api::MainloopApi, name: &str,
proplist: &Proplist) -> Option<Self>
{
let c_name = CString::new(name.clone()).unwrap();
let ptr = unsafe { capi::pa_context_new_with_proplist(
std::mem::transmute(mainloop_api), c_name.as_ptr(), proplist.ptr) };
if ptr.is_null() {
return None;
}
Some(Self::from_raw(ptr))
}
pub(crate) fn from_raw(ptr: *mut ContextInternal) -> Self {
assert_eq!(false, ptr.is_null());
Self { ptr: ptr, weak: false, cb_ptrs: Default::default() }
}
pub(crate) fn from_raw_weak(ptr: *mut ContextInternal) -> Self {
assert_eq!(false, ptr.is_null());
Self { ptr: ptr, weak: true, cb_ptrs: Default::default() }
}
pub fn set_state_callback(&mut self, callback: Option<Box<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_multi);
unsafe { capi::pa_context_set_state_callback(self.ptr, cb_fn, cb_data); }
}
pub fn set_event_callback(&mut self, callback: Option<Box<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_context_set_event_callback(self.ptr, cb_fn, cb_data); }
}
pub fn errno(&self) -> PAErr {
PAErr(unsafe { capi::pa_context_errno(self.ptr) })
}
pub fn is_pending(&self) -> bool {
unsafe { capi::pa_context_is_pending(self.ptr) != 0 }
}
pub fn get_state(&self) -> State {
unsafe { capi::pa_context_get_state(self.ptr).into() }
}
pub fn connect(&mut self, server: Option<&str>, flags: FlagSet, api: Option<&::def::SpawnApi>
) -> Result<(), PAErr>
{
let c_server = match server {
Some(server) => CString::new(server.clone()).unwrap(),
None => CString::new("").unwrap(),
};
let p_api: *const capi::pa_spawn_api = match api {
Some(api) => unsafe { std::mem::transmute(api) },
None => null::<capi::pa_spawn_api>(),
};
let p_server: *const c_char = match server {
Some(_) => c_server.as_ptr(),
None => null::<c_char>(),
};
match unsafe { capi::pa_context_connect(self.ptr, p_server, flags, p_api) } {
0 => Ok(()),
e => Err(PAErr(e)),
}
}
pub fn disconnect(&mut self) {
unsafe { capi::pa_context_disconnect(self.ptr); }
}
pub fn drain<F>(&mut self, callback: F) -> Operation
where F: FnMut() + 'static
{
let cb_data: *mut c_void = {
let boxed: *mut Box<FnMut()> = Box::into_raw(Box::new(Box::new(callback)));
boxed as *mut c_void
};
let ptr = unsafe { capi::pa_context_drain(self.ptr, Some(notify_cb_proxy_single), cb_data) };
assert!(!ptr.is_null());
Operation::from_raw(ptr)
}
pub fn exit_daemon<F>(&mut self, callback: F) -> Operation
where F: FnMut(bool) + 'static
{
let cb_data: *mut c_void = {
let boxed: *mut Box<FnMut(bool)> = Box::into_raw(Box::new(Box::new(callback)));
boxed as *mut c_void
};
let ptr = unsafe { capi::pa_context_exit_daemon(self.ptr, Some(success_cb_proxy), cb_data) };
assert!(!ptr.is_null());
Operation::from_raw(ptr)
}
pub fn set_default_sink<F>(&mut self, name: &str, callback: F) -> Operation
where F: FnMut(bool) + 'static
{
let c_name = CString::new(name.clone()).unwrap();
let cb_data: *mut c_void = {
let boxed: *mut Box<FnMut(bool)> = Box::into_raw(Box::new(Box::new(callback)));
boxed as *mut c_void
};
let ptr = unsafe { capi::pa_context_set_default_sink(self.ptr, c_name.as_ptr(),
Some(success_cb_proxy), cb_data) };
assert!(!ptr.is_null());
Operation::from_raw(ptr)
}
pub fn set_default_source<F>(&mut self, name: &str, callback: F) -> Operation
where F: FnMut(bool) + 'static
{
let c_name = CString::new(name.clone()).unwrap();
let cb_data: *mut c_void = {
let boxed: *mut Box<FnMut(bool)> = Box::into_raw(Box::new(Box::new(callback)));
boxed as *mut c_void
};
let ptr = unsafe { capi::pa_context_set_default_source(self.ptr, c_name.as_ptr(),
Some(success_cb_proxy), cb_data) };
assert!(!ptr.is_null());
Operation::from_raw(ptr)
}
pub fn is_local(&self) -> Option<bool> {
match unsafe { capi::pa_context_is_local(self.ptr) } {
1 => Some(true),
0 => Some(false),
_ => None,
}
}
pub fn set_name<F>(&mut self, name: &str, callback: F) -> Operation
where F: FnMut(bool) + 'static
{
let c_name = CString::new(name.clone()).unwrap();
let cb_data: *mut c_void = {
let boxed: *mut Box<FnMut(bool)> = Box::into_raw(Box::new(Box::new(callback)));
boxed as *mut c_void
};
let ptr = unsafe { capi::pa_context_set_name(self.ptr, c_name.as_ptr(),
Some(success_cb_proxy), cb_data) };
assert!(!ptr.is_null());
Operation::from_raw(ptr)
}
pub fn get_server(&self) -> Option<String> {
let ptr = unsafe { capi::pa_context_get_server(self.ptr) };
if ptr.is_null() {
return None;
}
Some(unsafe { CStr::from_ptr(ptr).to_string_lossy().into_owned() })
}
pub fn get_protocol_version(&self) -> u32 {
unsafe { capi::pa_context_get_protocol_version(self.ptr) }
}
pub fn get_server_protocol_version(&self) -> Option<u32> {
match unsafe { capi::pa_context_get_server_protocol_version(self.ptr) } {
::def::INVALID_INDEX => None,
r => Some(r),
}
}
pub fn proplist_update<F>(&mut self, mode: ::proplist::UpdateMode, p: &Proplist, callback: F
) -> Operation
where F: FnMut(bool) + 'static
{
let cb_data: *mut c_void = {
let boxed: *mut Box<FnMut(bool)> = Box::into_raw(Box::new(Box::new(callback)));
boxed as *mut c_void
};
let ptr = unsafe { capi::pa_context_proplist_update(self.ptr, mode, p.ptr,
Some(success_cb_proxy), cb_data) };
assert!(!ptr.is_null());
Operation::from_raw(ptr)
}
pub fn proplist_remove<F>(&mut self, keys: &[&str], callback: F) -> Operation
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.clone()).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: *mut c_void = {
let boxed: *mut Box<FnMut(bool)> = Box::into_raw(Box::new(Box::new(callback)));
boxed as *mut c_void
};
let ptr = unsafe { capi::pa_context_proplist_remove(self.ptr, c_key_ptrs.as_ptr(),
Some(success_cb_proxy), cb_data) };
assert!(!ptr.is_null());
Operation::from_raw(ptr)
}
pub fn get_index(&self) -> Option<u32> {
match unsafe { capi::pa_context_get_index(self.ptr) } {
::def::INVALID_INDEX => None,
r => Some(r),
}
}
pub fn rttime_new<T>(&self, mainloop: &::mainloop::api::Mainloop<MI=T::MI>,
time: MicroSeconds, cb: (TimeEventCb, *mut c_void)) -> Option<TimeEvent<T::MI>>
where T: ::mainloop::api::Mainloop
{
let ptr = unsafe { capi::pa_context_rttime_new(self.ptr, time.0, Some(cb.0), cb.1) };
if ptr.is_null() {
return None;
}
Some(TimeEvent::<T::MI>::from_raw(ptr, mainloop.inner().clone()))
}
pub fn rttime_restart<T>(&self, e: &TimeEvent<T::MI>, time: MicroSeconds)
where T: ::mainloop::api::Mainloop
{
unsafe { capi::pa_context_rttime_restart(self.ptr, e.get_ptr(), time.0); }
}
pub fn get_tile_size(&self, ss: &::sample::Spec) -> Option<usize> {
match unsafe { capi::pa_context_get_tile_size(self.ptr, std::mem::transmute(ss)) } {
std::usize::MAX => None,
r => Some(r),
}
}
pub fn load_cookie_from_file(&mut self, cookie_file_path: &str) -> Result<(), PAErr> {
let c_path = CString::new(cookie_file_path.clone()).unwrap();
match unsafe { capi::pa_context_load_cookie_from_file(self.ptr, c_path.as_ptr()) } {
0 => Ok(()),
e => Err(PAErr(e)),
}
}
}
impl Drop for Context {
fn drop(&mut self) {
if !self.weak {
unsafe { capi::pa_context_unref(self.ptr) };
}
self.ptr = null_mut::<ContextInternal>();
}
}
extern "C"
fn success_cb_proxy(_: *mut ContextInternal, success: i32, userdata: *mut c_void) {
assert!(!userdata.is_null());
let mut callback = unsafe { Box::from_raw(userdata as *mut Box<FnMut(bool)>) };
let success_actual = match success { 0 => false, _ => true };
callback(success_actual);
}
extern "C"
fn notify_cb_proxy_single(_: *mut ContextInternal, userdata: *mut c_void) {
assert!(!userdata.is_null());
let mut callback = unsafe { Box::from_raw(userdata as *mut Box<FnMut()>) };
callback();
}
extern "C"
fn notify_cb_proxy_multi(_: *mut ContextInternal, userdata: *mut c_void) {
assert!(!userdata.is_null());
let callback = unsafe { &mut *(userdata as *mut Box<FnMut()>) };
callback();
}
extern "C"
fn event_cb_proxy(_: *mut ContextInternal, name: *const c_char,
proplist: *mut ::proplist::ProplistInternal, userdata: *mut c_void)
{
assert!(!userdata.is_null());
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 = unsafe { &mut *(userdata as *mut Box<FnMut(String, Proplist)>) };
callback(n, pl);
}
extern "C"
fn ext_test_cb_proxy(_: *mut ContextInternal, version: u32, userdata: *mut c_void) {
assert!(!userdata.is_null());
let mut callback = unsafe { Box::from_raw(userdata as *mut Box<FnMut(u32)>) };
callback(version);
}
extern "C"
fn ext_subscribe_cb_proxy(_: *mut ContextInternal, userdata: *mut c_void) {
assert!(!userdata.is_null());
let callback = unsafe { &mut *(userdata as *mut Box<FnMut()>) };
callback();
}