summaryrefslogtreecommitdiffstats
path: root/third_party/rust/audioipc2-server/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/audioipc2-server/src/lib.rs')
-rw-r--r--third_party/rust/audioipc2-server/src/lib.rs221
1 files changed, 221 insertions, 0 deletions
diff --git a/third_party/rust/audioipc2-server/src/lib.rs b/third_party/rust/audioipc2-server/src/lib.rs
new file mode 100644
index 0000000000..c90de38c66
--- /dev/null
+++ b/third_party/rust/audioipc2-server/src/lib.rs
@@ -0,0 +1,221 @@
+// Copyright © 2017 Mozilla Foundation
+//
+// This program is made available under an ISC-style license. See the
+// accompanying file LICENSE for details
+#![warn(unused_extern_crates)]
+
+#[macro_use]
+extern crate error_chain;
+#[macro_use]
+extern crate log;
+
+use audio_thread_priority::promote_current_thread_to_real_time;
+use audioipc::ipccore;
+use audioipc::sys;
+use audioipc::PlatformHandleType;
+use once_cell::sync::Lazy;
+use std::ffi::{CStr, CString};
+use std::os::raw::c_void;
+use std::ptr;
+use std::sync::Mutex;
+use std::thread;
+
+mod server;
+
+struct CubebContextParams {
+ context_name: CString,
+ backend_name: Option<CString>,
+}
+
+static G_CUBEB_CONTEXT_PARAMS: Lazy<Mutex<CubebContextParams>> = Lazy::new(|| {
+ Mutex::new(CubebContextParams {
+ context_name: CString::new("AudioIPC Server").unwrap(),
+ backend_name: None,
+ })
+});
+
+#[allow(deprecated)]
+pub mod errors {
+ #![allow(clippy::upper_case_acronyms)]
+ error_chain! {
+ links {
+ AudioIPC(::audioipc::errors::Error, ::audioipc::errors::ErrorKind);
+ }
+ foreign_links {
+ Cubeb(cubeb_core::Error);
+ Io(::std::io::Error);
+ }
+ }
+}
+
+use crate::errors::*;
+
+struct ServerWrapper {
+ rpc_thread: ipccore::EventLoopThread,
+ callback_thread: ipccore::EventLoopThread,
+ device_collection_thread: ipccore::EventLoopThread,
+}
+
+fn register_thread(callback: Option<extern "C" fn(*const ::std::os::raw::c_char)>) {
+ if let Some(func) = callback {
+ let name = CString::new(thread::current().name().unwrap()).unwrap();
+ func(name.as_ptr());
+ }
+}
+
+fn unregister_thread(callback: Option<extern "C" fn()>) {
+ if let Some(func) = callback {
+ func();
+ }
+}
+
+fn init_threads(
+ thread_create_callback: Option<extern "C" fn(*const ::std::os::raw::c_char)>,
+ thread_destroy_callback: Option<extern "C" fn()>,
+) -> Result<ServerWrapper> {
+ let rpc_name = "AudioIPC Server RPC";
+ let rpc_thread = ipccore::EventLoopThread::new(
+ rpc_name.to_string(),
+ None,
+ move || {
+ trace!("Starting {} thread", rpc_name);
+ register_thread(thread_create_callback);
+ audioipc::server_platform_init();
+ },
+ move || {
+ unregister_thread(thread_destroy_callback);
+ trace!("Stopping {} thread", rpc_name);
+ },
+ )
+ .map_err(|e| {
+ debug!("Failed to start {} thread: {:?}", rpc_name, e);
+ e
+ })?;
+
+ let callback_name = "AudioIPC Server Callback";
+ let callback_thread = ipccore::EventLoopThread::new(
+ callback_name.to_string(),
+ None,
+ move || {
+ trace!("Starting {} thread", callback_name);
+ if let Err(e) = promote_current_thread_to_real_time(0, 48000) {
+ debug!(
+ "Failed to promote {} thread to real-time: {:?}",
+ callback_name, e
+ );
+ }
+ register_thread(thread_create_callback);
+ },
+ move || {
+ unregister_thread(thread_destroy_callback);
+ trace!("Stopping {} thread", callback_name);
+ },
+ )
+ .map_err(|e| {
+ debug!("Failed to start {} thread: {:?}", callback_name, e);
+ e
+ })?;
+
+ let device_collection_name = "AudioIPC DeviceCollection RPC";
+ let device_collection_thread = ipccore::EventLoopThread::new(
+ device_collection_name.to_string(),
+ None,
+ move || {
+ trace!("Starting {} thread", device_collection_name);
+ register_thread(thread_create_callback);
+ },
+ move || {
+ unregister_thread(thread_destroy_callback);
+ trace!("Stopping {} thread", device_collection_name);
+ },
+ )
+ .map_err(|e| {
+ debug!("Failed to start {} thread: {:?}", device_collection_name, e);
+ e
+ })?;
+
+ Ok(ServerWrapper {
+ rpc_thread,
+ callback_thread,
+ device_collection_thread,
+ })
+}
+
+#[repr(C)]
+#[derive(Clone, Copy, Debug)]
+pub struct AudioIpcServerInitParams {
+ // Fields only need to be public for ipctest.
+ pub thread_create_callback: Option<extern "C" fn(*const ::std::os::raw::c_char)>,
+ pub thread_destroy_callback: Option<extern "C" fn()>,
+}
+
+#[allow(clippy::missing_safety_doc)]
+#[no_mangle]
+pub unsafe extern "C" fn audioipc2_server_start(
+ context_name: *const std::os::raw::c_char,
+ backend_name: *const std::os::raw::c_char,
+ init_params: *const AudioIpcServerInitParams,
+) -> *mut c_void {
+ assert!(!init_params.is_null());
+ let mut params = G_CUBEB_CONTEXT_PARAMS.lock().unwrap();
+ if !context_name.is_null() {
+ params.context_name = CStr::from_ptr(context_name).to_owned();
+ }
+ if !backend_name.is_null() {
+ let backend_string = CStr::from_ptr(backend_name).to_owned();
+ params.backend_name = Some(backend_string);
+ }
+ match init_threads(
+ (*init_params).thread_create_callback,
+ (*init_params).thread_destroy_callback,
+ ) {
+ Ok(server) => Box::into_raw(Box::new(server)) as *mut _,
+ Err(_) => ptr::null_mut() as *mut _,
+ }
+}
+
+// A `shm_area_size` of 0 allows the server to calculate an appropriate shm size for each stream.
+// A non-zero `shm_area_size` forces all allocations to the specified size.
+#[no_mangle]
+pub extern "C" fn audioipc2_server_new_client(
+ p: *mut c_void,
+ shm_area_size: usize,
+) -> PlatformHandleType {
+ let wrapper: &ServerWrapper = unsafe { &*(p as *mut _) };
+
+ // We create a connected pair of anonymous IPC endpoints. One side
+ // is registered with the event loop core, the other side is returned
+ // to the caller to be remoted to the client to complete setup.
+ let (server_pipe, client_pipe) = match sys::make_pipe_pair() {
+ Ok((server_pipe, client_pipe)) => (server_pipe, client_pipe),
+ Err(e) => {
+ error!(
+ "audioipc_server_new_client - make_pipe_pair failed: {:?}",
+ e
+ );
+ return audioipc::INVALID_HANDLE_VALUE;
+ }
+ };
+
+ let rpc_thread = wrapper.rpc_thread.handle();
+ let callback_thread = wrapper.callback_thread.handle();
+ let device_collection_thread = wrapper.device_collection_thread.handle();
+
+ let server = server::CubebServer::new(
+ callback_thread.clone(),
+ device_collection_thread.clone(),
+ shm_area_size,
+ );
+ if let Err(e) = rpc_thread.bind_server(server, server_pipe) {
+ error!("audioipc_server_new_client - bind_server failed: {:?}", e);
+ return audioipc::INVALID_HANDLE_VALUE;
+ }
+
+ unsafe { client_pipe.into_raw() }
+}
+
+#[no_mangle]
+pub extern "C" fn audioipc2_server_stop(p: *mut c_void) {
+ let wrapper = unsafe { Box::<ServerWrapper>::from_raw(p as *mut _) };
+ drop(wrapper);
+}