diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:22:09 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:22:09 +0000 |
commit | 43a97878ce14b72f0981164f87f2e35e14151312 (patch) | |
tree | 620249daf56c0258faa40cbdcf9cfba06de2a846 /third_party/rust/pulse/src/context.rs | |
parent | Initial commit. (diff) | |
download | firefox-43a97878ce14b72f0981164f87f2e35e14151312.tar.xz firefox-43a97878ce14b72f0981164f87f2e35e14151312.zip |
Adding upstream version 110.0.1.upstream/110.0.1upstream
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.rs | 487 |
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) +} |