use capi;
use std::ffi::{CStr, CString};
use std::borrow::Cow;
use std::os::raw::{c_char, c_void};
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_device_manager_info as InfoInternal;
use capi::pa_ext_device_manager_role_priority_info as RolePriorityInfoInternal;
#[derive(Debug)]
pub struct RolePriorityInfo<'a> {
pub role: Option<Cow<'a, str>>,
pub priority: u32,
}
impl<'a> RolePriorityInfo<'a> {
fn new_from_raw(p: *const RolePriorityInfoInternal) -> Self {
assert!(!p.is_null());
let src = unsafe { p.as_ref().unwrap() };
unsafe {
RolePriorityInfo {
role: match src.role.is_null() {
false => Some(CStr::from_ptr(src.role).to_string_lossy()),
true => None,
},
priority: src.priority,
}
}
}
}
#[derive(Debug)]
pub struct Info<'a> {
pub name: Option<Cow<'a, str>>,
pub description: Option<Cow<'a, str>>,
pub icon: Option<Cow<'a, str>>,
pub index: Option<u32>,
pub role_priorities: Vec<RolePriorityInfo<'a>>,
}
impl<'a> Info<'a> {
fn new_from_raw(p: *const InfoInternal) -> Self {
assert!(!p.is_null());
let src = unsafe { p.as_ref().unwrap() };
let mut rp_vec = Vec::with_capacity(src.n_role_priorities as usize);
assert!(src.n_role_priorities == 0 || !src.role_priorities.is_null());
for i in 0..src.n_role_priorities as isize {
let indexed_ptr = unsafe { src.role_priorities.offset(i) as *mut RolePriorityInfoInternal };
if !indexed_ptr.is_null() {
rp_vec.push(RolePriorityInfo::new_from_raw(indexed_ptr));
}
}
unsafe {
Info {
name: match src.name.is_null() {
false => Some(CStr::from_ptr(src.name).to_string_lossy()),
true => None,
},
description: match src.description.is_null() {
false => Some(CStr::from_ptr(src.description).to_string_lossy()),
true => None,
},
icon: match src.icon.is_null() {
false => Some(CStr::from_ptr(src.icon).to_string_lossy()),
true => None,
},
index: match src.index {
::def::INVALID_INDEX => None,
i => Some(i),
},
role_priorities: rp_vec,
}
}
}
}
pub struct DeviceManager {
context: *mut ContextInternal,
cb_ptrs: CallbackPointers,
}
#[derive(Default)]
struct CallbackPointers {
subscribe: super::ExtSubscribeCb,
}
impl Context {
pub fn device_manager(&self) -> DeviceManager {
unsafe { capi::pa_context_ref(self.ptr) };
DeviceManager::from_raw(self.ptr)
}
}
impl DeviceManager {
fn from_raw(context: *mut ContextInternal) -> Self {
Self { context: context, cb_ptrs: Default::default() }
}
pub fn test<F>(&mut self, callback: F) -> Operation<FnMut(u32)>
where F: FnMut(u32) + 'static
{
let cb_data = box_closure_get_capi_ptr::<FnMut(u32)>(Box::new(callback));
let ptr = unsafe { capi::pa_ext_device_manager_test(self.context,
Some(super::ext_test_cb_proxy), cb_data) };
assert!(!ptr.is_null());
Operation::from_raw(ptr, cb_data as *mut Box<FnMut(u32)>)
}
pub fn read<F>(&mut self, callback: F) -> Operation<FnMut(ListResult<&Info>)>
where F: FnMut(ListResult<&Info>) + 'static
{
let cb_data = box_closure_get_capi_ptr::<FnMut(ListResult<&Info>)>(Box::new(callback));
let ptr = unsafe { capi::pa_ext_device_manager_read(self.context, Some(read_list_cb_proxy),
cb_data) };
assert!(!ptr.is_null());
Operation::from_raw(ptr, cb_data as *mut Box<FnMut(ListResult<&Info>)>)
}
pub fn set_device_description<F>(&mut self, device: &str, description: &str, callback: F
) -> Operation<FnMut(bool)>
where F: FnMut(bool) + 'static
{
let c_dev = CString::new(device.clone()).unwrap();
let c_desc = CString::new(description.clone()).unwrap();
let cb_data = box_closure_get_capi_ptr::<FnMut(bool)>(Box::new(callback));
let ptr = unsafe {
capi::pa_ext_device_manager_set_device_description(self.context, c_dev.as_ptr(),
c_desc.as_ptr(), Some(super::success_cb_proxy), cb_data)
};
assert!(!ptr.is_null());
Operation::from_raw(ptr, cb_data as *mut Box<FnMut(bool)>)
}
pub fn delete<F>(&mut self, devices: &[&str], callback: F) -> Operation<FnMut(bool)>
where F: FnMut(bool) + 'static
{
let mut c_devs: Vec<CString> = Vec::with_capacity(devices.len());
for device in devices {
c_devs.push(CString::new(device.clone()).unwrap());
}
let mut c_dev_ptrs: Vec<*const c_char> = Vec::with_capacity(c_devs.len()+1);
for c_dev in c_devs {
c_dev_ptrs.push(c_dev.as_ptr());
}
c_dev_ptrs.push(null());
let cb_data = box_closure_get_capi_ptr::<FnMut(bool)>(Box::new(callback));
let ptr = unsafe { capi::pa_ext_device_manager_delete(self.context, c_dev_ptrs.as_ptr(),
Some(super::success_cb_proxy), cb_data) };
assert!(!ptr.is_null());
Operation::from_raw(ptr, cb_data as *mut Box<FnMut(bool)>)
}
pub fn enable_role_device_priority_routing<F>(&mut self, enable: bool, callback: F
) -> Operation<FnMut(bool)>
where F: FnMut(bool) + 'static
{
let cb_data = box_closure_get_capi_ptr::<FnMut(bool)>(Box::new(callback));
let ptr = unsafe {
capi::pa_ext_device_manager_enable_role_device_priority_routing(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<FnMut(bool)>)
}
pub fn reorder_devices_for_role<F>(&mut self, role: &str, devices: &[&str], callback: F
) -> Operation<FnMut(bool)>
where F: FnMut(bool) + 'static
{
let c_role = CString::new(role.clone()).unwrap();
let mut c_devs: Vec<CString> = Vec::with_capacity(devices.len());
for device in devices {
c_devs.push(CString::new(device.clone()).unwrap());
}
let mut c_dev_ptrs: Vec<*const c_char> = Vec::with_capacity(c_devs.len() + 1);
for c_dev in c_devs {
c_dev_ptrs.push(c_dev.as_ptr());
}
c_dev_ptrs.push(null());
let cb_data = box_closure_get_capi_ptr::<FnMut(bool)>(Box::new(callback));
let ptr = unsafe {
capi::pa_ext_device_manager_reorder_devices_for_role(self.context, c_role.as_ptr(),
c_dev_ptrs.as_ptr(), Some(super::success_cb_proxy), cb_data)
};
assert!(!ptr.is_null());
Operation::from_raw(ptr, cb_data as *mut Box<FnMut(bool)>)
}
pub fn subscribe<F>(&mut self, enable: bool, callback: F) -> Operation<FnMut(bool)>
where F: FnMut(bool) + 'static
{
let cb_data = box_closure_get_capi_ptr::<FnMut(bool)>(Box::new(callback));
let ptr = unsafe { capi::pa_ext_device_manager_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<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_device_manager_set_subscribe_cb(self.context, cb_fn, cb_data) };
}
}
impl Drop for DeviceManager {
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)
{
match callback_for_list_instance::<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); },
}
}