summaryrefslogtreecommitdiffstats
path: root/third_party/rust/pulse/src/context.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /third_party/rust/pulse/src/context.rs
parentInitial commit. (diff)
downloadfirefox-esr-upstream.tar.xz
firefox-esr-upstream.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/pulse/src/context.rs')
-rw-r--r--third_party/rust/pulse/src/context.rs487
1 files changed, 487 insertions, 0 deletions
diff --git a/third_party/rust/pulse/src/context.rs b/third_party/rust/pulse/src/context.rs
new file mode 100644
index 0000000000..6c435c9c65
--- /dev/null
+++ b/third_party/rust/pulse/src/context.rs
@@ -0,0 +1,487 @@
+// Copyright © 2017 Mozilla Foundation
+//
+// This program is made available under an ISC-style license. See the
+// accompanying file LICENSE for details.
+
+use ffi;
+use std::ffi::CStr;
+use std::mem::{forget, MaybeUninit};
+use std::os::raw::{c_int, c_void};
+use std::ptr;
+use util::UnwrapCStr;
+use *;
+
+// A note about `wrapped` functions
+//
+// C FFI demands `unsafe extern fn(*mut pa_context, ...) -> i32`, etc,
+// but we want to allow such callbacks to be safe. This means no
+// `unsafe` or `extern`, and callbacks should be called with a safe
+// wrapper of `*mut pa_context`. Since the callback doesn't take
+// ownership, this is `&Context`. `fn wrapped<T>(...)` defines a
+// function that converts from our safe signature to the unsafe
+// signature.
+//
+// Currently, we use a property of Rust, namely that each function
+// gets its own unique type. These unique types can't be written
+// directly, so we use generic and a type parameter, and let the Rust
+// compiler fill in the name for us:
+//
+// fn get_sink_input_info<CB>(&self, ..., _: CB, ...) -> ...
+// where CB: Fn(&Context, *const SinkInputInfo, i32, *mut c_void)
+//
+// Because we aren't storing or passing any state, we assert, at run-time :-(,
+// that our functions are zero-sized:
+//
+// assert!(mem::size_of::<F>() == 0);
+//
+// We need to obtain a value of type F in order to call it. Since we
+// can't name the function, we have to unsafely construct that value
+// somehow - we do this using mem::uninitialized. Then, we call that
+// function with a reference to the Context, and save the result:
+//
+// | generate value || call it |
+// let result = ::std::mem::uninitialized::<F>()(&mut object);
+//
+// Lastly, since our Object is an owned type, we need to avoid
+// dropping it, then return the result we just generated.
+//
+// mem::forget(object);
+// result
+
+// Aid in returning Operation from callbacks
+macro_rules! op_or_err {
+ ($self_:ident, $e:expr) => {{
+ let o = unsafe { $e };
+ if o.is_null() {
+ Err(ErrorCode::from_error_code($self_.errno()))
+ } else {
+ Ok(unsafe { operation::from_raw_ptr(o) })
+ }
+ }};
+}
+
+#[repr(C)]
+#[derive(Debug)]
+pub struct Context(*mut ffi::pa_context);
+
+impl Context {
+ pub fn new<'a, OPT>(api: &MainloopApi, name: OPT) -> Option<Self>
+ where
+ OPT: Into<Option<&'a CStr>>,
+ {
+ let ptr = unsafe { ffi::pa_context_new(api.raw_mut(), name.unwrap_cstr()) };
+ if ptr.is_null() {
+ None
+ } else {
+ Some(Context(ptr))
+ }
+ }
+
+ #[doc(hidden)]
+ pub fn raw_mut(&self) -> &mut ffi::pa_context {
+ unsafe { &mut *self.0 }
+ }
+
+ pub fn unref(self) {
+ unsafe {
+ ffi::pa_context_unref(self.raw_mut());
+ }
+ }
+
+ pub fn clear_state_callback(&self) {
+ unsafe {
+ ffi::pa_context_set_state_callback(self.raw_mut(), None, ptr::null_mut());
+ }
+ }
+
+ pub fn set_state_callback<CB>(&self, _: CB, userdata: *mut c_void)
+ where
+ CB: Fn(&Context, *mut c_void),
+ {
+ assert_eq!(::std::mem::size_of::<CB>(), 0);
+
+ // See: A note about `wrapped` functions
+ unsafe extern "C" fn wrapped<F>(c: *mut ffi::pa_context, userdata: *mut c_void)
+ where
+ F: Fn(&Context, *mut c_void),
+ {
+ let ctx = context::from_raw_ptr(c);
+ let cb = MaybeUninit::<F>::uninit();
+ let result = (*cb.as_ptr())(&ctx, userdata);
+ forget(ctx);
+
+ result
+ }
+
+ unsafe {
+ ffi::pa_context_set_state_callback(self.raw_mut(), Some(wrapped::<CB>), userdata);
+ }
+ }
+
+ pub fn errno(&self) -> ffi::pa_error_code_t {
+ unsafe { ffi::pa_context_errno(self.raw_mut()) }
+ }
+
+ pub fn get_state(&self) -> ContextState {
+ ContextState::try_from(unsafe { ffi::pa_context_get_state(self.raw_mut()) })
+ .expect("pa_context_get_state returned invalid ContextState")
+ }
+
+ pub fn connect<'a, OPT>(
+ &self,
+ server: OPT,
+ flags: ContextFlags,
+ api: *const ffi::pa_spawn_api,
+ ) -> Result<()>
+ where
+ OPT: Into<Option<&'a CStr>>,
+ {
+ let r = unsafe {
+ ffi::pa_context_connect(
+ self.raw_mut(),
+ server.into().unwrap_cstr(),
+ flags.into(),
+ api,
+ )
+ };
+ error_result!((), r)
+ }
+
+ pub fn disconnect(&self) {
+ unsafe {
+ ffi::pa_context_disconnect(self.raw_mut());
+ }
+ }
+
+ pub fn drain<CB>(&self, _: CB, userdata: *mut c_void) -> Result<Operation>
+ where
+ CB: Fn(&Context, *mut c_void),
+ {
+ assert_eq!(::std::mem::size_of::<CB>(), 0);
+
+ // See: A note about `wrapped` functions
+ unsafe extern "C" fn wrapped<F>(c: *mut ffi::pa_context, userdata: *mut c_void)
+ where
+ F: Fn(&Context, *mut c_void),
+ {
+ let ctx = context::from_raw_ptr(c);
+ let cb = MaybeUninit::<F>::uninit();
+ let result = (*cb.as_ptr())(&ctx, userdata);
+ forget(ctx);
+
+ result
+ }
+
+ op_or_err!(
+ self,
+ ffi::pa_context_drain(self.raw_mut(), Some(wrapped::<CB>), userdata)
+ )
+ }
+
+ pub fn 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),
+ {
+ assert_eq!(::std::mem::size_of::<CB>(), 0);
+
+ // See: A note about `wrapped` functions
+ unsafe extern "C" fn wrapped<F>(
+ a: *mut ffi::pa_mainloop_api,
+ e: *mut ffi::pa_time_event,
+ tv: *const TimeVal,
+ userdata: *mut c_void,
+ ) where
+ F: Fn(&MainloopApi, *mut ffi::pa_time_event, &TimeVal, *mut c_void),
+ {
+ let api = mainloop_api::from_raw_ptr(a);
+ let timeval = &*tv;
+ let cb = MaybeUninit::<F>::uninit();
+ let result = (*cb.as_ptr())(&api, e, timeval, userdata);
+ forget(api);
+
+ result
+ }
+
+ unsafe { ffi::pa_context_rttime_new(self.raw_mut(), usec, Some(wrapped::<CB>), userdata) }
+ }
+
+ pub fn get_server_info<CB>(&self, _: CB, userdata: *mut c_void) -> Result<Operation>
+ where
+ CB: Fn(&Context, Option<&ServerInfo>, *mut c_void),
+ {
+ assert_eq!(::std::mem::size_of::<CB>(), 0);
+
+ // See: A note about `wrapped` functions
+ unsafe extern "C" fn wrapped<F>(
+ c: *mut ffi::pa_context,
+ i: *const ffi::pa_server_info,
+ userdata: *mut c_void,
+ ) where
+ F: Fn(&Context, Option<&ServerInfo>, *mut c_void),
+ {
+ let info = if i.is_null() { None } else { Some(&*i) };
+ let ctx = context::from_raw_ptr(c);
+ let cb = MaybeUninit::<F>::uninit();
+ let result = (*cb.as_ptr())(&ctx, info, userdata);
+ forget(ctx);
+
+ result
+ }
+
+ op_or_err!(
+ self,
+ ffi::pa_context_get_server_info(self.raw_mut(), Some(wrapped::<CB>), userdata)
+ )
+ }
+
+ pub fn 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>>,
+ {
+ assert_eq!(::std::mem::size_of::<CB>(), 0);
+
+ // See: A note about `wrapped` functions
+ unsafe extern "C" fn wrapped<F>(
+ c: *mut ffi::pa_context,
+ info: *const ffi::pa_sink_info,
+ eol: c_int,
+ userdata: *mut c_void,
+ ) where
+ F: Fn(&Context, *const SinkInfo, i32, *mut c_void),
+ {
+ let ctx = context::from_raw_ptr(c);
+ let cb = MaybeUninit::<F>::uninit();
+ let result = (*cb.as_ptr())(&ctx, info, eol, userdata);
+ forget(ctx);
+
+ result
+ }
+
+ op_or_err!(
+ self,
+ ffi::pa_context_get_sink_info_by_name(
+ self.raw_mut(),
+ name.into().unwrap_cstr(),
+ Some(wrapped::<CB>),
+ userdata
+ )
+ )
+ }
+
+ pub fn get_sink_info_list<CB>(&self, _: CB, userdata: *mut c_void) -> Result<Operation>
+ where
+ CB: Fn(&Context, *const SinkInfo, i32, *mut c_void),
+ {
+ assert_eq!(::std::mem::size_of::<CB>(), 0);
+
+ // See: A note about `wrapped` functions
+ unsafe extern "C" fn wrapped<F>(
+ c: *mut ffi::pa_context,
+ info: *const ffi::pa_sink_info,
+ eol: c_int,
+ userdata: *mut c_void,
+ ) where
+ F: Fn(&Context, *const SinkInfo, i32, *mut c_void),
+ {
+ let ctx = context::from_raw_ptr(c);
+ let cb = MaybeUninit::<F>::uninit();
+ let result = (*cb.as_ptr())(&ctx, info, eol, userdata);
+ forget(ctx);
+
+ result
+ }
+
+ op_or_err!(
+ self,
+ ffi::pa_context_get_sink_info_list(self.raw_mut(), Some(wrapped::<CB>), userdata)
+ )
+ }
+
+ pub fn 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),
+ {
+ assert_eq!(::std::mem::size_of::<CB>(), 0);
+
+ // See: A note about `wrapped` functions
+ unsafe extern "C" fn wrapped<F>(
+ c: *mut ffi::pa_context,
+ info: *const ffi::pa_sink_input_info,
+ eol: c_int,
+ userdata: *mut c_void,
+ ) where
+ F: Fn(&Context, *const SinkInputInfo, i32, *mut c_void),
+ {
+ let ctx = context::from_raw_ptr(c);
+ let cb = MaybeUninit::<F>::uninit();
+ let result = (*cb.as_ptr())(&ctx, info, eol, userdata);
+ forget(ctx);
+
+ result
+ }
+
+ op_or_err!(
+ self,
+ ffi::pa_context_get_sink_input_info(self.raw_mut(), idx, Some(wrapped::<CB>), userdata)
+ )
+ }
+
+ pub fn get_source_info_list<CB>(&self, _: CB, userdata: *mut c_void) -> Result<Operation>
+ where
+ CB: Fn(&Context, *const SourceInfo, i32, *mut c_void),
+ {
+ assert_eq!(::std::mem::size_of::<CB>(), 0);
+
+ // See: A note about `wrapped` functions
+ unsafe extern "C" fn wrapped<F>(
+ c: *mut ffi::pa_context,
+ info: *const ffi::pa_source_info,
+ eol: c_int,
+ userdata: *mut c_void,
+ ) where
+ F: Fn(&Context, *const SourceInfo, i32, *mut c_void),
+ {
+ let ctx = context::from_raw_ptr(c);
+ let cb = MaybeUninit::<F>::uninit();
+ let result = (*cb.as_ptr())(&ctx, info, eol, userdata);
+ forget(ctx);
+
+ result
+ }
+
+ op_or_err!(
+ self,
+ ffi::pa_context_get_source_info_list(self.raw_mut(), Some(wrapped::<CB>), userdata)
+ )
+ }
+
+ pub fn 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),
+ {
+ assert_eq!(::std::mem::size_of::<CB>(), 0);
+
+ // See: A note about `wrapped` functions
+ unsafe extern "C" fn wrapped<F>(
+ c: *mut ffi::pa_context,
+ success: c_int,
+ userdata: *mut c_void,
+ ) where
+ F: Fn(&Context, i32, *mut c_void),
+ {
+ let ctx = context::from_raw_ptr(c);
+ let cb = MaybeUninit::<F>::uninit();
+ let result = (*cb.as_ptr())(&ctx, success, userdata);
+ forget(ctx);
+
+ result
+ }
+
+ op_or_err!(
+ self,
+ ffi::pa_context_set_sink_input_volume(
+ self.raw_mut(),
+ idx,
+ volume,
+ Some(wrapped::<CB>),
+ userdata
+ )
+ )
+ }
+
+ pub fn subscribe<CB>(
+ &self,
+ m: SubscriptionMask,
+ _: CB,
+ userdata: *mut c_void,
+ ) -> Result<Operation>
+ where
+ CB: Fn(&Context, i32, *mut c_void),
+ {
+ assert_eq!(::std::mem::size_of::<CB>(), 0);
+
+ // See: A note about `wrapped` functions
+ unsafe extern "C" fn wrapped<F>(
+ c: *mut ffi::pa_context,
+ success: c_int,
+ userdata: *mut c_void,
+ ) where
+ F: Fn(&Context, i32, *mut c_void),
+ {
+ let ctx = context::from_raw_ptr(c);
+ let cb = MaybeUninit::<F>::uninit();
+ let result = (*cb.as_ptr())(&ctx, success, userdata);
+ forget(ctx);
+
+ result
+ }
+
+ op_or_err!(
+ self,
+ ffi::pa_context_subscribe(self.raw_mut(), m.into(), Some(wrapped::<CB>), userdata)
+ )
+ }
+
+ pub fn clear_subscribe_callback(&self) {
+ unsafe {
+ ffi::pa_context_set_subscribe_callback(self.raw_mut(), None, ptr::null_mut());
+ }
+ }
+
+ pub fn set_subscribe_callback<CB>(&self, _: CB, userdata: *mut c_void)
+ where
+ CB: Fn(&Context, SubscriptionEvent, u32, *mut c_void),
+ {
+ assert_eq!(::std::mem::size_of::<CB>(), 0);
+
+ // See: A note about `wrapped` functions
+ unsafe extern "C" fn wrapped<F>(
+ c: *mut ffi::pa_context,
+ t: ffi::pa_subscription_event_type_t,
+ idx: u32,
+ userdata: *mut c_void,
+ ) where
+ F: Fn(&Context, SubscriptionEvent, u32, *mut c_void),
+ {
+ let ctx = context::from_raw_ptr(c);
+ let event = SubscriptionEvent::try_from(t)
+ .expect("pa_context_subscribe_cb_t passed invalid pa_subscription_event_type_t");
+ let cb = MaybeUninit::<F>::uninit();
+ let result = (*cb.as_ptr())(&ctx, event, idx, userdata);
+ forget(ctx);
+
+ result
+ }
+
+ unsafe {
+ ffi::pa_context_set_subscribe_callback(self.raw_mut(), Some(wrapped::<CB>), userdata);
+ }
+ }
+}
+
+#[doc(hidden)]
+pub unsafe fn from_raw_ptr(ptr: *mut ffi::pa_context) -> Context {
+ Context(ptr)
+}