libpulse_binding/context/
ext_device_manager.rs1use std::ffi::{CStr, CString};
17use std::borrow::Cow;
18use std::os::raw::{c_char, c_void};
19use std::ptr::{null, null_mut};
20use capi::pa_ext_device_manager_info as InfoInternal;
21use capi::pa_ext_device_manager_role_priority_info as RolePriorityInfoInternal;
22use super::{ContextInternal, Context};
23use crate::def;
24use crate::callbacks::{ListResult, box_closure_get_capi_ptr, callback_for_list_instance};
25use crate::operation::Operation;
26
27#[derive(Debug)]
29pub struct RolePriorityInfo<'a> {
30 pub role: Option<Cow<'a, str>>,
32 pub priority: u32,
34}
35
36impl<'a> RolePriorityInfo<'a> {
37 fn new_from_raw(p: *const RolePriorityInfoInternal) -> Self {
38 assert!(!p.is_null());
39 let src = unsafe { p.as_ref().unwrap() };
40 unsafe {
41 RolePriorityInfo {
42 role: match src.role.is_null() {
43 false => Some(CStr::from_ptr(src.role).to_string_lossy()),
44 true => None,
45 },
46 priority: src.priority,
47 }
48 }
49 }
50}
51
52#[derive(Debug)]
55pub struct Info<'a> {
56 pub name: Option<Cow<'a, str>>,
59 pub description: Option<Cow<'a, str>>,
61 pub icon: Option<Cow<'a, str>>,
63 pub index: Option<u32>,
65 pub role_priorities: Vec<RolePriorityInfo<'a>>,
67}
68
69impl<'a> Info<'a> {
70 fn new_from_raw(p: *const InfoInternal) -> Self {
71 assert!(!p.is_null());
72 let src = unsafe { p.as_ref().unwrap() };
73
74 let mut rp_vec = Vec::with_capacity(src.n_role_priorities as usize);
75 assert!(src.n_role_priorities == 0 || !src.role_priorities.is_null());
76 for i in 0..src.n_role_priorities as isize {
77 let indexed_ptr = unsafe { src.role_priorities.offset(i) as *mut RolePriorityInfoInternal };
78 if !indexed_ptr.is_null() {
79 rp_vec.push(RolePriorityInfo::new_from_raw(indexed_ptr));
80 }
81 }
82
83 unsafe {
84 Info {
85 name: match src.name.is_null() {
86 false => Some(CStr::from_ptr(src.name).to_string_lossy()),
87 true => None,
88 },
89 description: match src.description.is_null() {
90 false => Some(CStr::from_ptr(src.description).to_string_lossy()),
91 true => None,
92 },
93 icon: match src.icon.is_null() {
94 false => Some(CStr::from_ptr(src.icon).to_string_lossy()),
95 true => None,
96 },
97 index: match src.index {
98 def::INVALID_INDEX => None,
99 i => Some(i),
100 },
101 role_priorities: rp_vec,
102 }
103 }
104 }
105}
106
107pub struct DeviceManager {
111 context: *mut ContextInternal,
112 cb_ptrs: CallbackPointers,
114}
115
116unsafe impl Send for DeviceManager {}
117unsafe impl Sync for DeviceManager {}
118
119#[derive(Default)]
122struct CallbackPointers {
123 subscribe: super::ExtSubscribeCb,
124}
125
126impl Context {
127 pub fn device_manager(&self) -> DeviceManager {
132 unsafe { capi::pa_context_ref(self.ptr) };
133 DeviceManager::from_raw(self.ptr)
134 }
135}
136
137impl DeviceManager {
138 fn from_raw(context: *mut ContextInternal) -> Self {
140 Self { context: context, cb_ptrs: Default::default() }
141 }
142
143 pub fn test<F>(&mut self, callback: F) -> Operation<dyn FnMut(u32)>
147 where F: FnMut(u32) + 'static
148 {
149 let cb_data = box_closure_get_capi_ptr::<dyn FnMut(u32)>(Box::new(callback));
150 let ptr = unsafe { capi::pa_ext_device_manager_test(self.context,
151 Some(super::ext_test_cb_proxy), cb_data) };
152 Operation::from_raw(ptr, cb_data as *mut Box<dyn FnMut(u32)>)
153 }
154
155 pub fn read<F>(&mut self, callback: F) -> Operation<dyn FnMut(ListResult<&Info>)>
159 where F: FnMut(ListResult<&Info>) + 'static
160 {
161 let cb_data = box_closure_get_capi_ptr::<dyn FnMut(ListResult<&Info>)>(Box::new(callback));
162 let ptr = unsafe { capi::pa_ext_device_manager_read(self.context, Some(read_list_cb_proxy),
163 cb_data) };
164 Operation::from_raw(ptr, cb_data as *mut Box<dyn FnMut(ListResult<&Info>)>)
165 }
166
167 pub fn set_device_description<F>(&mut self, device: &str, description: &str, callback: F)
173 -> Operation<dyn FnMut(bool)>
174 where F: FnMut(bool) + 'static
175 {
176 let c_dev = CString::new(device).unwrap();
179 let c_desc = CString::new(description).unwrap();
180
181 let cb_data = box_closure_get_capi_ptr::<dyn FnMut(bool)>(Box::new(callback));
182 let ptr = unsafe {
183 capi::pa_ext_device_manager_set_device_description(self.context, c_dev.as_ptr(),
184 c_desc.as_ptr(), Some(super::success_cb_proxy), cb_data)
185 };
186 Operation::from_raw(ptr, cb_data as *mut Box<dyn FnMut(bool)>)
187 }
188
189 pub fn delete<F>(&mut self, devices: &[&str], callback: F) -> Operation<dyn FnMut(bool)>
195 where F: FnMut(bool) + 'static
196 {
197 let mut c_devs: Vec<CString> = Vec::with_capacity(devices.len());
200 for device in devices {
201 c_devs.push(CString::new(*device).unwrap());
202 }
203
204 let mut c_dev_ptrs: Vec<*const c_char> = Vec::with_capacity(c_devs.len() + 1);
207 for c_dev in &c_devs {
208 c_dev_ptrs.push(c_dev.as_ptr());
209 }
210 c_dev_ptrs.push(null());
211
212 let cb_data = box_closure_get_capi_ptr::<dyn FnMut(bool)>(Box::new(callback));
213 let ptr = unsafe { capi::pa_ext_device_manager_delete(self.context, c_dev_ptrs.as_ptr(),
214 Some(super::success_cb_proxy), cb_data) };
215 Operation::from_raw(ptr, cb_data as *mut Box<dyn FnMut(bool)>)
216 }
217
218 pub fn enable_role_device_priority_routing<F>(&mut self, enable: bool, callback: F)
224 -> Operation<dyn FnMut(bool)>
225 where F: FnMut(bool) + 'static
226 {
227 let cb_data = box_closure_get_capi_ptr::<dyn FnMut(bool)>(Box::new(callback));
228 let ptr = unsafe {
229 capi::pa_ext_device_manager_enable_role_device_priority_routing(self.context,
230 enable as i32, Some(super::success_cb_proxy), cb_data)
231 };
232 Operation::from_raw(ptr, cb_data as *mut Box<dyn FnMut(bool)>)
233 }
234
235 pub fn reorder_devices_for_role<F>(&mut self, role: &str, devices: &[&str], callback: F)
241 -> Operation<dyn FnMut(bool)>
242 where F: FnMut(bool) + 'static
243 {
244 let c_role = CString::new(role).unwrap();
247 let mut c_devs: Vec<CString> = Vec::with_capacity(devices.len());
248 for device in devices {
249 c_devs.push(CString::new(*device).unwrap());
250 }
251
252 let mut c_dev_ptrs: Vec<*const c_char> = Vec::with_capacity(c_devs.len() + 1);
255 for c_dev in &c_devs {
256 c_dev_ptrs.push(c_dev.as_ptr());
257 }
258 c_dev_ptrs.push(null());
259
260 let cb_data = box_closure_get_capi_ptr::<dyn FnMut(bool)>(Box::new(callback));
261 let ptr = unsafe {
262 capi::pa_ext_device_manager_reorder_devices_for_role(self.context, c_role.as_ptr(),
263 c_dev_ptrs.as_ptr(), Some(super::success_cb_proxy), cb_data)
264 };
265 Operation::from_raw(ptr, cb_data as *mut Box<dyn FnMut(bool)>)
266 }
267
268 pub fn subscribe<F>(&mut self, enable: bool, callback: F) -> Operation<dyn FnMut(bool)>
274 where F: FnMut(bool) + 'static
275 {
276 let cb_data = box_closure_get_capi_ptr::<dyn FnMut(bool)>(Box::new(callback));
277 let ptr = unsafe { capi::pa_ext_device_manager_subscribe(self.context, enable as i32,
278 Some(super::success_cb_proxy), cb_data) };
279 Operation::from_raw(ptr, cb_data as *mut Box<dyn FnMut(bool)>)
280 }
281
282 pub fn set_subscribe_cb<F>(&mut self, callback: F)
285 where F: FnMut() + 'static
286 {
287 let saved = &mut self.cb_ptrs.subscribe;
288 *saved = super::ExtSubscribeCb::new(Some(Box::new(callback)));
289 let (cb_fn, cb_data) = saved.get_capi_params(super::ext_subscribe_cb_proxy);
290 unsafe { capi::pa_ext_device_manager_set_subscribe_cb(self.context, cb_fn, cb_data) };
291 }
292}
293
294impl Drop for DeviceManager {
295 fn drop(&mut self) {
296 unsafe { capi::pa_context_unref(self.context) };
297 self.context = null_mut::<ContextInternal>();
298 }
299}
300
301extern "C"
305fn read_list_cb_proxy(_: *mut ContextInternal, i: *const InfoInternal, eol: i32,
306 userdata: *mut c_void)
307{
308 let _ = std::panic::catch_unwind(|| {
309 callback_for_list_instance(i, eol, userdata, Info::new_from_raw);
310 });
311}