jack/client/
async_client.rs1use jack_sys as j;
2use std::fmt;
3use std::fmt::Debug;
4use std::mem;
5use std::sync::atomic::AtomicBool;
6
7use super::callbacks::clear_callbacks;
8use super::callbacks::{CallbackContext, NotificationHandler, ProcessHandler};
9use crate::client::client_impl::Client;
10use crate::client::common::CREATE_OR_DESTROY_CLIENT_MUTEX;
11use crate::Error;
12
13#[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`."]
36pub struct AsyncClient<N, P> {
37    callback: Option<Box<CallbackContext<N, P>>>,
38}
39
40unsafe impl<N, P> Send for AsyncClient<N, P> {}
41unsafe impl<N, P> Sync for AsyncClient<N, P> {}
42
43impl<N, P> AsyncClient<N, P>
44where
45    N: 'static + Send + Sync + NotificationHandler,
46    P: 'static + Send + ProcessHandler,
47{
48    pub fn new(client: Client, notification_handler: N, process_handler: P) -> Result<Self, Error> {
57        let _m = CREATE_OR_DESTROY_CLIENT_MUTEX.lock().ok();
58        unsafe {
59            let mut callback_context = Box::new(CallbackContext {
60                client,
61                notification: notification_handler,
62                process: process_handler,
63                is_valid_for_callback: AtomicBool::new(true),
64                has_panic: AtomicBool::new(false),
65            });
66            CallbackContext::register_callbacks(&mut callback_context)?;
67            let res = j::jack_activate(callback_context.client.raw());
68            match res {
69                0 => Ok(AsyncClient {
70                    callback: Some(callback_context),
71                }),
72                _ => {
73                    mem::forget(callback_context);
74                    Err(Error::ClientActivationError)
75                }
76            }
77        }
78    }
79}
80
81impl<N, P> AsyncClient<N, P> {
82    #[inline(always)]
84    pub fn as_client(&self) -> &Client {
85        let callback = self.callback.as_ref().unwrap();
86        &callback.client
87    }
88
89    pub fn deactivate(self) -> Result<(Client, N, P), Error> {
98        let mut c = self;
99        c.maybe_deactivate()
100            .map(|c| (c.client, c.notification, c.process))
101    }
102
103    fn maybe_deactivate(&mut self) -> Result<Box<CallbackContext<N, P>>, Error> {
106        let m = CREATE_OR_DESTROY_CLIENT_MUTEX.lock();
107        if self.callback.is_none() {
108            drop(m);
109            return Err(Error::ClientIsNoLongerAlive);
110        }
111        let cb = self.callback.take().ok_or(Error::ClientIsNoLongerAlive)?;
112        if unsafe { j::jack_deactivate(cb.client.raw()) } != 0 {
114            drop(m);
115            return Err(Error::ClientDeactivationError);
116        }
117
118        unsafe { clear_callbacks(cb.client.raw()) }?;
120        if cb.has_panic.load(std::sync::atomic::Ordering::Relaxed) {
122            drop(m);
123            return Err(Error::ClientPanicked);
124        }
125        Ok(cb)
126    }
127}
128
129impl<N, P> Drop for AsyncClient<N, P> {
131    fn drop(&mut self) {
133        let _ = self.maybe_deactivate();
134    }
135}
136
137impl<N, P> Debug for AsyncClient<N, P> {
138    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
139        f.debug_tuple("AsyncClient")
140            .field(&self.as_client())
141            .finish()
142    }
143}