1 // Copyright © 2017 Mozilla Foundation
2 //
3 // This program is made available under an ISC-style license.  See the
4 // accompanying file LICENSE for details.
5 
6 use ::*;
7 use ffi;
8 use std::ffi::CStr;
9 use std::mem::{forget, MaybeUninit};
10 use std::os::raw::{c_int, c_void};
11 use std::ptr;
12 use util::UnwrapCStr;
13 
14 // A note about `wrapped` functions
15 //
16 // C FFI demands `unsafe extern fn(*mut pa_context, ...) -> i32`, etc,
17 // but we want to allow such callbacks to be safe. This means no
18 // `unsafe` or `extern`, and callbacks should be called with a safe
19 // wrapper of `*mut pa_context`. Since the callback doesn't take
20 // ownership, this is `&Context`. `fn wrapped<T>(...)` defines a
21 // function that converts from our safe signature to the unsafe
22 // signature.
23 //
24 // Currently, we use a property of Rust, namely that each function
25 // gets its own unique type.  These unique types can't be written
26 // directly, so we use generic and a type parameter, and let the Rust
27 // compiler fill in the name for us:
28 //
29 // fn get_sink_input_info<CB>(&self, ..., _: CB, ...) -> ...
30 //     where CB: Fn(&Context, *const SinkInputInfo, i32, *mut c_void)
31 //
32 // Because we aren't storing or passing any state, we assert, at run-time :-(,
33 // that our functions are zero-sized:
34 //
35 //	assert!(mem::size_of::<F>() == 0);
36 //
37 // We need to obtain a value of type F in order to call it. Since we
38 // can't name the function, we have to unsafely construct that value
39 // somehow - we do this using mem::uninitialized. Then, we call that
40 // function with a reference to the Context, and save the result:
41 //
42 //              |       generate value        ||  call it  |
43 // let result = ::std::mem::uninitialized::<F>()(&mut object);
44 //
45 // Lastly, since our Object is an owned type, we need to avoid
46 // dropping it, then return the result we just generated.
47 //
48 //		mem::forget(object);
49 //		result
50 
51 // Aid in returning Operation from callbacks
52 macro_rules! op_or_err {
53     ($self_:ident, $e:expr) => {{
54         let o = unsafe { $e };
55         if o.is_null() {
56             Err(ErrorCode::from_error_code($self_.errno()))
57         } else {
58             Ok(unsafe { operation::from_raw_ptr(o) })
59         }
60     }}
61 }
62 
63 #[repr(C)]
64 #[derive(Debug)]
65 pub struct Context(*mut ffi::pa_context);
66 
67 impl Context {
new<'a, OPT>(api: &MainloopApi, name: OPT) -> Option<Self> where OPT: Into<Option<&'a CStr>>68     pub fn new<'a, OPT>(api: &MainloopApi, name: OPT) -> Option<Self>
69         where OPT: Into<Option<&'a CStr>>
70     {
71         let ptr = unsafe { ffi::pa_context_new(api.raw_mut(), name.unwrap_cstr()) };
72         if ptr.is_null() {
73             None
74         } else {
75             Some(Context(ptr))
76         }
77     }
78 
79     #[doc(hidden)]
raw_mut(&self) -> &mut ffi::pa_context80     pub fn raw_mut(&self) -> &mut ffi::pa_context {
81         unsafe { &mut *self.0 }
82     }
83 
unref(self)84     pub fn unref(self) {
85         unsafe {
86             ffi::pa_context_unref(self.raw_mut());
87         }
88     }
89 
clear_state_callback(&self)90     pub fn clear_state_callback(&self) {
91         unsafe {
92             ffi::pa_context_set_state_callback(self.raw_mut(), None, ptr::null_mut());
93         }
94     }
95 
set_state_callback<CB>(&self, _: CB, userdata: *mut c_void) where CB: Fn(&Context, *mut c_void)96     pub fn set_state_callback<CB>(&self, _: CB, userdata: *mut c_void)
97         where CB: Fn(&Context, *mut c_void)
98     {
99         assert_eq!(::std::mem::size_of::<CB>(), 0);
100 
101         // See: A note about `wrapped` functions
102         unsafe extern "C" fn wrapped<F>(c: *mut ffi::pa_context, userdata: *mut c_void)
103             where F: Fn(&Context, *mut c_void)
104         {
105             let ctx = context::from_raw_ptr(c);
106             let cb = MaybeUninit::<F>::uninit();
107             let result = (*cb.as_ptr())(&ctx, userdata);
108             forget(ctx);
109 
110             result
111         }
112 
113         unsafe {
114             ffi::pa_context_set_state_callback(self.raw_mut(), Some(wrapped::<CB>), userdata);
115         }
116     }
117 
errno(&self) -> ffi::pa_error_code_t118     pub fn errno(&self) -> ffi::pa_error_code_t {
119         unsafe { ffi::pa_context_errno(self.raw_mut()) }
120     }
121 
get_state(&self) -> ContextState122     pub fn get_state(&self) -> ContextState {
123         ContextState::try_from(unsafe {
124             ffi::pa_context_get_state(self.raw_mut())
125         }).expect("pa_context_get_state returned invalid ContextState")
126     }
127 
connect<'a, OPT>(&self, server: OPT, flags: ContextFlags, api: *const ffi::pa_spawn_api) -> Result<()> where OPT: Into<Option<&'a CStr>>128     pub fn connect<'a, OPT>(&self, server: OPT, flags: ContextFlags, api: *const ffi::pa_spawn_api) -> Result<()>
129         where OPT: Into<Option<&'a CStr>>
130     {
131         let r = unsafe {
132             ffi::pa_context_connect(self.raw_mut(),
133                                     server.into().unwrap_cstr(),
134                                     flags.into(),
135                                     api)
136         };
137         error_result!((), r)
138     }
139 
disconnect(&self)140     pub fn disconnect(&self) {
141         unsafe {
142             ffi::pa_context_disconnect(self.raw_mut());
143         }
144     }
145 
146 
drain<CB>(&self, _: CB, userdata: *mut c_void) -> Result<Operation> where CB: Fn(&Context, *mut c_void)147     pub fn drain<CB>(&self, _: CB, userdata: *mut c_void) -> Result<Operation>
148         where CB: Fn(&Context, *mut c_void)
149     {
150         assert_eq!(::std::mem::size_of::<CB>(), 0);
151 
152         // See: A note about `wrapped` functions
153         unsafe extern "C" fn wrapped<F>(c: *mut ffi::pa_context, userdata: *mut c_void)
154             where F: Fn(&Context, *mut c_void)
155         {
156             let ctx = context::from_raw_ptr(c);
157             let cb = MaybeUninit::<F>::uninit();
158             let result = (*cb.as_ptr())(&ctx, userdata);
159             forget(ctx);
160 
161             result
162         }
163 
164         op_or_err!(self,
165                    ffi::pa_context_drain(self.raw_mut(), Some(wrapped::<CB>), userdata))
166     }
167 
rttime_new<CB>(&self, usec: USec, _: CB, userdata: *mut c_void) -> *mut ffi::pa_time_event where CB: Fn(&MainloopApi, *mut ffi::pa_time_event, &TimeVal, *mut c_void)168     pub fn rttime_new<CB>(&self, usec: USec, _: CB, userdata: *mut c_void) -> *mut ffi::pa_time_event
169         where CB: Fn(&MainloopApi, *mut ffi::pa_time_event, &TimeVal, *mut c_void)
170     {
171         assert_eq!(::std::mem::size_of::<CB>(), 0);
172 
173         // See: A note about `wrapped` functions
174         unsafe extern "C" fn wrapped<F>(a: *mut ffi::pa_mainloop_api,
175                                         e: *mut ffi::pa_time_event,
176                                         tv: *const TimeVal,
177                                         userdata: *mut c_void)
178             where F: Fn(&MainloopApi, *mut ffi::pa_time_event, &TimeVal, *mut c_void)
179         {
180             let api = mainloop_api::from_raw_ptr(a);
181             let timeval = &*tv;
182             let cb = MaybeUninit::<F>::uninit();
183             let result = (*cb.as_ptr())(&api, e, timeval, userdata);
184             forget(api);
185 
186             result
187         }
188 
189         unsafe { ffi::pa_context_rttime_new(self.raw_mut(), usec, Some(wrapped::<CB>), userdata) }
190     }
191 
get_server_info<CB>(&self, _: CB, userdata: *mut c_void) -> Result<Operation> where CB: Fn(&Context, Option<&ServerInfo>, *mut c_void)192     pub fn get_server_info<CB>(&self, _: CB, userdata: *mut c_void) -> Result<Operation>
193         where CB: Fn(&Context, Option<&ServerInfo>, *mut c_void)
194     {
195         assert_eq!(::std::mem::size_of::<CB>(), 0);
196 
197         // See: A note about `wrapped` functions
198         unsafe extern "C" fn wrapped<F>(c: *mut ffi::pa_context, i: *const ffi::pa_server_info, userdata: *mut c_void)
199             where F: Fn(&Context, Option<&ServerInfo>, *mut c_void)
200         {
201             let info = if i.is_null() {
202                 None
203             } else {
204                 Some(&*i)
205             };
206             let ctx = context::from_raw_ptr(c);
207             let cb = MaybeUninit::<F>::uninit();
208             let result = (*cb.as_ptr())(&ctx, info, userdata);
209             forget(ctx);
210 
211             result
212         }
213 
214         op_or_err!(self,
215                    ffi::pa_context_get_server_info(self.raw_mut(), Some(wrapped::<CB>), userdata))
216     }
217 
get_sink_info_by_name<'str, CS, CB>(&self, name: CS, _: CB, userdata: *mut c_void) -> Result<Operation> where CB: Fn(&Context, *const SinkInfo, i32, *mut c_void), CS: Into<Option<&'str CStr>>,218     pub fn get_sink_info_by_name<'str, CS, CB>(&self, name: CS, _: CB, userdata: *mut c_void) -> Result<Operation>
219     where
220         CB: Fn(&Context, *const SinkInfo, i32, *mut c_void),
221         CS: Into<Option<&'str CStr>>,
222     {
223         assert_eq!(::std::mem::size_of::<CB>(), 0);
224 
225         // See: A note about `wrapped` functions
226         unsafe extern "C" fn wrapped<F>(c: *mut ffi::pa_context,
227                                         info: *const ffi::pa_sink_info,
228                                         eol: c_int,
229                                         userdata: *mut c_void)
230             where F: Fn(&Context, *const SinkInfo, i32, *mut c_void)
231         {
232             let ctx = context::from_raw_ptr(c);
233             let cb = MaybeUninit::<F>::uninit();
234             let result = (*cb.as_ptr())(&ctx, info, eol, userdata);
235             forget(ctx);
236 
237             result
238         }
239 
240         op_or_err!(self,
241                    ffi::pa_context_get_sink_info_by_name(self.raw_mut(),
242                                                         name.into().unwrap_cstr(),
243                                                         Some(wrapped::<CB>),
244                                                         userdata))
245     }
246 
get_sink_info_list<CB>(&self, _: CB, userdata: *mut c_void) -> Result<Operation> where CB: Fn(&Context, *const SinkInfo, i32, *mut c_void)247     pub fn get_sink_info_list<CB>(&self, _: CB, userdata: *mut c_void) -> Result<Operation>
248         where CB: Fn(&Context, *const SinkInfo, i32, *mut c_void)
249     {
250         assert_eq!(::std::mem::size_of::<CB>(), 0);
251 
252         // See: A note about `wrapped` functions
253         unsafe extern "C" fn wrapped<F>(c: *mut ffi::pa_context,
254                                         info: *const ffi::pa_sink_info,
255                                         eol: c_int,
256                                         userdata: *mut c_void)
257             where F: Fn(&Context, *const SinkInfo, i32, *mut c_void)
258         {
259             let ctx = context::from_raw_ptr(c);
260             let cb = MaybeUninit::<F>::uninit();
261             let result = (*cb.as_ptr())(&ctx, info, eol, userdata);
262             forget(ctx);
263 
264             result
265         }
266 
267         op_or_err!(self,
268                    ffi::pa_context_get_sink_info_list(self.raw_mut(), Some(wrapped::<CB>), userdata))
269     }
270 
get_sink_input_info<CB>(&self, idx: u32, _: CB, userdata: *mut c_void) -> Result<Operation> where CB: Fn(&Context, *const SinkInputInfo, i32, *mut c_void)271     pub fn get_sink_input_info<CB>(&self, idx: u32, _: CB, userdata: *mut c_void) -> Result<Operation>
272         where CB: Fn(&Context, *const SinkInputInfo, i32, *mut c_void)
273     {
274         assert_eq!(::std::mem::size_of::<CB>(), 0);
275 
276         // See: A note about `wrapped` functions
277         unsafe extern "C" fn wrapped<F>(c: *mut ffi::pa_context,
278                                         info: *const ffi::pa_sink_input_info,
279                                         eol: c_int,
280                                         userdata: *mut c_void)
281             where F: Fn(&Context, *const SinkInputInfo, i32, *mut c_void)
282         {
283             let ctx = context::from_raw_ptr(c);
284             let cb = MaybeUninit::<F>::uninit();
285             let result = (*cb.as_ptr())(&ctx, info, eol, userdata);
286             forget(ctx);
287 
288             result
289         }
290 
291         op_or_err!(self,
292                    ffi::pa_context_get_sink_input_info(self.raw_mut(), idx, Some(wrapped::<CB>), userdata))
293     }
294 
get_source_info_list<CB>(&self, _: CB, userdata: *mut c_void) -> Result<Operation> where CB: Fn(&Context, *const SourceInfo, i32, *mut c_void)295     pub fn get_source_info_list<CB>(&self, _: CB, userdata: *mut c_void) -> Result<Operation>
296         where CB: Fn(&Context, *const SourceInfo, i32, *mut c_void)
297     {
298         assert_eq!(::std::mem::size_of::<CB>(), 0);
299 
300         // See: A note about `wrapped` functions
301         unsafe extern "C" fn wrapped<F>(c: *mut ffi::pa_context,
302                                         info: *const ffi::pa_source_info,
303                                         eol: c_int,
304                                         userdata: *mut c_void)
305             where F: Fn(&Context, *const SourceInfo, i32, *mut c_void)
306         {
307             let ctx = context::from_raw_ptr(c);
308             let cb = MaybeUninit::<F>::uninit();
309             let result = (*cb.as_ptr())(&ctx, info, eol, userdata);
310             forget(ctx);
311 
312             result
313         }
314 
315         op_or_err!(self,
316                    ffi::pa_context_get_source_info_list(self.raw_mut(), Some(wrapped::<CB>), userdata))
317     }
318 
set_sink_input_volume<CB>(&self, idx: u32, volume: &CVolume, _: CB, userdata: *mut c_void) -> Result<Operation> where CB: Fn(&Context, i32, *mut c_void)319     pub fn set_sink_input_volume<CB>(&self,
320                                      idx: u32,
321                                      volume: &CVolume,
322                                      _: CB,
323                                      userdata: *mut c_void)
324                                      -> Result<Operation>
325         where CB: Fn(&Context, i32, *mut c_void)
326     {
327         assert_eq!(::std::mem::size_of::<CB>(), 0);
328 
329         // See: A note about `wrapped` functions
330         unsafe extern "C" fn wrapped<F>(c: *mut ffi::pa_context, success: c_int, userdata: *mut c_void)
331             where F: Fn(&Context, i32, *mut c_void)
332         {
333             let ctx = context::from_raw_ptr(c);
334             let cb = MaybeUninit::<F>::uninit();
335             let result = (*cb.as_ptr())(&ctx, success, userdata);
336             forget(ctx);
337 
338             result
339         }
340 
341         op_or_err!(self,
342                    ffi::pa_context_set_sink_input_volume(self.raw_mut(), idx, volume, Some(wrapped::<CB>), userdata))
343     }
344 
subscribe<CB>(&self, m: SubscriptionMask, _: CB, userdata: *mut c_void) -> Result<Operation> where CB: Fn(&Context, i32, *mut c_void)345     pub fn subscribe<CB>(&self, m: SubscriptionMask, _: CB, userdata: *mut c_void) -> Result<Operation>
346         where CB: Fn(&Context, i32, *mut c_void)
347     {
348         assert_eq!(::std::mem::size_of::<CB>(), 0);
349 
350         // See: A note about `wrapped` functions
351         unsafe extern "C" fn wrapped<F>(c: *mut ffi::pa_context, success: c_int, userdata: *mut c_void)
352             where F: Fn(&Context, i32, *mut c_void)
353         {
354             let ctx = context::from_raw_ptr(c);
355             let cb = MaybeUninit::<F>::uninit();
356             let result = (*cb.as_ptr())(&ctx, success, userdata);
357             forget(ctx);
358 
359             result
360         }
361 
362         op_or_err!(self,
363                    ffi::pa_context_subscribe(self.raw_mut(), m.into(), Some(wrapped::<CB>), userdata))
364     }
365 
clear_subscribe_callback(&self)366     pub fn clear_subscribe_callback(&self) {
367         unsafe {
368             ffi::pa_context_set_subscribe_callback(self.raw_mut(), None, ptr::null_mut());
369         }
370     }
371 
set_subscribe_callback<CB>(&self, _: CB, userdata: *mut c_void) where CB: Fn(&Context, SubscriptionEvent, u32, *mut c_void)372     pub fn set_subscribe_callback<CB>(&self, _: CB, userdata: *mut c_void)
373         where CB: Fn(&Context, SubscriptionEvent, u32, *mut c_void)
374     {
375         assert_eq!(::std::mem::size_of::<CB>(), 0);
376 
377         // See: A note about `wrapped` functions
378         unsafe extern "C" fn wrapped<F>(c: *mut ffi::pa_context,
379                                         t: ffi::pa_subscription_event_type_t,
380                                         idx: u32,
381                                         userdata: *mut c_void)
382             where F: Fn(&Context, SubscriptionEvent, u32, *mut c_void)
383         {
384             let ctx = context::from_raw_ptr(c);
385             let event = SubscriptionEvent::try_from(t)
386             .expect("pa_context_subscribe_cb_t passed invalid pa_subscription_event_type_t");
387             let cb = MaybeUninit::<F>::uninit();
388             let result = (*cb.as_ptr())(&ctx, event, idx, userdata);
389             forget(ctx);
390 
391             result
392         }
393 
394         unsafe {
395             ffi::pa_context_set_subscribe_callback(self.raw_mut(), Some(wrapped::<CB>), userdata);
396         }
397     }
398 }
399 
400 #[doc(hidden)]
from_raw_ptr(ptr: *mut ffi::pa_context) -> Context401 pub unsafe fn from_raw_ptr(ptr: *mut ffi::pa_context) -> Context {
402     Context(ptr)
403 }
404