summaryrefslogtreecommitdiffstats
path: root/media/audioipc/server/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'media/audioipc/server/src/lib.rs')
-rw-r--r--media/audioipc/server/src/lib.rs166
1 files changed, 166 insertions, 0 deletions
diff --git a/media/audioipc/server/src/lib.rs b/media/audioipc/server/src/lib.rs
new file mode 100644
index 0000000000..4d49c8fc08
--- /dev/null
+++ b/media/audioipc/server/src/lib.rs
@@ -0,0 +1,166 @@
+// 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::core;
+use audioipc::platformhandle_passing::framed_with_platformhandles;
+use audioipc::rpc;
+use audioipc::{MessageStream, PlatformHandle, PlatformHandleType};
+use futures::sync::oneshot;
+use futures::Future;
+use once_cell::sync::Lazy;
+use std::ffi::{CStr, CString};
+use std::os::raw::c_void;
+use std::ptr;
+use std::sync::Mutex;
+use tokio::reactor;
+
+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 {
+ error_chain! {
+ links {
+ AudioIPC(::audioipc::errors::Error, ::audioipc::errors::ErrorKind);
+ }
+ foreign_links {
+ Cubeb(cubeb_core::Error);
+ Io(::std::io::Error);
+ Canceled(::futures::sync::oneshot::Canceled);
+ }
+ }
+}
+
+use crate::errors::*;
+
+struct ServerWrapper {
+ core_thread: core::CoreThread,
+ callback_thread: core::CoreThread,
+}
+
+fn run() -> Result<ServerWrapper> {
+ trace!("Starting up cubeb audio server event loop thread...");
+
+ let callback_thread = core::spawn_thread(
+ "AudioIPC Callback RPC",
+ || {
+ match promote_current_thread_to_real_time(0, 48000) {
+ Ok(_) => {}
+ Err(_) => {
+ debug!("Failed to promote audio callback thread to real-time.");
+ }
+ }
+ trace!("Starting up cubeb audio callback event loop thread...");
+ Ok(())
+ },
+ || {},
+ )
+ .or_else(|e| {
+ debug!(
+ "Failed to start cubeb audio callback event loop thread: {:?}",
+ e
+ );
+ Err(e)
+ })?;
+
+ let core_thread = core::spawn_thread(
+ "AudioIPC Server RPC",
+ move || {
+ audioipc::server_platform_init();
+ Ok(())
+ },
+ || {},
+ )
+ .or_else(|e| {
+ debug!("Failed to cubeb audio core event loop thread: {:?}", e);
+ Err(e)
+ })?;
+
+ Ok(ServerWrapper {
+ core_thread,
+ callback_thread,
+ })
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn audioipc_server_start(
+ context_name: *const std::os::raw::c_char,
+ backend_name: *const std::os::raw::c_char,
+) -> *mut c_void {
+ 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 run() {
+ Ok(server) => Box::into_raw(Box::new(server)) as *mut _,
+ Err(_) => ptr::null_mut() as *mut _,
+ }
+}
+
+#[no_mangle]
+pub extern "C" fn audioipc_server_new_client(p: *mut c_void) -> PlatformHandleType {
+ let (wait_tx, wait_rx) = oneshot::channel();
+ let wrapper: &ServerWrapper = unsafe { &*(p as *mut _) };
+
+ let core_handle = wrapper.callback_thread.handle();
+
+ // We create a connected pair of anonymous IPC endpoints. One side
+ // is registered with the reactor core, the other side is returned
+ // to the caller.
+ MessageStream::anonymous_ipc_pair()
+ .and_then(|(ipc_server, ipc_client)| {
+ // Spawn closure to run on same thread as reactor::Core
+ // via remote handle.
+ wrapper
+ .core_thread
+ .handle()
+ .spawn(futures::future::lazy(|| {
+ trace!("Incoming connection");
+ let handle = reactor::Handle::default();
+ ipc_server.into_tokio_ipc(&handle)
+ .and_then(|sock| {
+ let transport = framed_with_platformhandles(sock, Default::default());
+ rpc::bind_server(transport, server::CubebServer::new(core_handle));
+ Ok(())
+ }).map_err(|_| ())
+ // Notify waiting thread that server has been registered.
+ .and_then(|_| wait_tx.send(()))
+ }))
+ .expect("Failed to spawn CubebServer");
+ // Wait for notification that server has been registered
+ // with reactor::Core.
+ let _ = wait_rx.wait();
+ Ok(unsafe { PlatformHandle::from(ipc_client).into_raw() })
+ })
+ .unwrap_or(audioipc::INVALID_HANDLE_VALUE)
+}
+
+#[no_mangle]
+pub extern "C" fn audioipc_server_stop(p: *mut c_void) {
+ let wrapper = unsafe { Box::<ServerWrapper>::from_raw(p as *mut _) };
+ drop(wrapper);
+}