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