use jack_sys as j;
use std::fmt;
use std::fmt::Debug;
use std::mem;
use super::callbacks::clear_callbacks;
use super::callbacks::{CallbackContext, NotificationHandler, ProcessHandler};
use crate::client::client_impl::Client;
use crate::client::common::{sleep_on_test, CREATE_OR_DESTROY_CLIENT_MUTEX};
use crate::Error;
#[must_use = "The jack client is shut down when the AsyncClient is dropped. You most likely want to keep this alive and manually tear down with `AsyncClient::deactivate`."]
pub struct AsyncClient<N, P> {
callback: Option<Box<CallbackContext<N, P>>>,
}
unsafe impl<N, P> Send for AsyncClient<N, P> {}
unsafe impl<N, P> Sync for AsyncClient<N, P> {}
impl<N, P> AsyncClient<N, P>
where
N: 'static + Send + Sync + NotificationHandler,
P: 'static + Send + ProcessHandler,
{
pub fn new(client: Client, notification_handler: N, process_handler: P) -> Result<Self, Error> {
let _m = CREATE_OR_DESTROY_CLIENT_MUTEX.lock().unwrap();
unsafe {
sleep_on_test();
let mut callback_context = Box::new(CallbackContext {
client,
notification: notification_handler,
process: process_handler,
});
CallbackContext::register_callbacks(&mut callback_context)?;
sleep_on_test();
let res = j::jack_activate(callback_context.client.raw());
for _ in 0..4 {
sleep_on_test();
}
match res {
0 => Ok(AsyncClient {
callback: Some(callback_context),
}),
_ => {
mem::forget(callback_context);
Err(Error::ClientActivationError)
}
}
}
}
}
impl<N, P> AsyncClient<N, P> {
#[inline(always)]
pub fn as_client(&self) -> &Client {
let callback = self.callback.as_ref().unwrap();
&callback.client
}
pub fn deactivate(self) -> Result<(Client, N, P), Error> {
let mut c = self;
unsafe {
c.maybe_deactivate()
.map(|c| (c.client, c.notification, c.process))
}
}
unsafe fn maybe_deactivate(&mut self) -> Result<CallbackContext<N, P>, Error> {
let _m = CREATE_OR_DESTROY_CLIENT_MUTEX.lock().unwrap();
if self.callback.is_none() {
return Err(Error::ClientIsNoLongerAlive);
}
let client = self.callback.as_ref().unwrap().client.raw();
let callback = Box::into_raw(self.callback.take().unwrap());
sleep_on_test();
if j::jack_deactivate(client) != 0 {
return Err(Error::ClientDeactivationError);
}
sleep_on_test();
clear_callbacks(client)?;
Ok(*Box::from_raw(callback))
}
}
impl<N, P> Drop for AsyncClient<N, P> {
fn drop(&mut self) {
let _ = unsafe { self.maybe_deactivate() };
}
}
impl<N, P> Debug for AsyncClient<N, P> {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
f.debug_tuple("AsyncClient")
.field(&self.as_client())
.finish()
}
}