1use super::{JackNFrames, JackPort, JackStatus, JackConnection, Deactivated};
4use jack_sys::*;
5use std::panic::{AssertUnwindSafe, catch_unwind};
6use std::sync::atomic::{AtomicPtr, Ordering};
7use std::ffi::CStr;
8use libc;
9use errors::*;
10
11pub trait JackLoggingHandler: Send {
13 fn on_error(&mut self, msg: &str);
15 fn on_info(&mut self, msg: &str);
17}
18
19lazy_static! {
20 static ref LOGGING_HANDLER: AtomicPtr<*mut JackLoggingHandler> = AtomicPtr::new(::std::ptr::null_mut());
21}
22unsafe extern "C" fn error_callback(msg: *const libc::c_char) {
23 let handler = LOGGING_HANDLER.load(Ordering::Relaxed);
24 if !handler.is_null() {
25 let f = &mut (**handler);
26 let msg = CStr::from_ptr(msg);
27 let _ = catch_unwind(AssertUnwindSafe(|| {
28 f.on_error(&msg.to_string_lossy());
29 }));
30 }
31}
32unsafe extern "C" fn info_callback(msg: *const libc::c_char) {
33 let handler = LOGGING_HANDLER.load(Ordering::Relaxed);
34 if !handler.is_null() {
35 let f = &mut (**handler);
36 let msg = CStr::from_ptr(msg);
37 let _ = catch_unwind(AssertUnwindSafe(|| {
38 f.on_info(&msg.to_string_lossy());
39 }));
40 }
41}
42pub fn set_logging_handler<F>(handler: F) where F: JackLoggingHandler + 'static {
48 unsafe {
49 let trait_object_ptr = Box::into_raw(Box::new(handler) as Box<JackLoggingHandler>);
50 let ptr_ception = Box::into_raw(Box::new(trait_object_ptr));
51 LOGGING_HANDLER.store(ptr_ception, Ordering::Relaxed);
52 jack_set_error_function(Some(error_callback));
53 jack_set_info_function(Some(info_callback));
54 }
55}
56pub struct JackCallbackContext {
58 nframes: JackNFrames
59}
60
61impl JackCallbackContext {
62 #[inline(always)]
64 pub fn nframes(&self) -> u32 {
65 self.nframes
66 }
67 pub fn get_port_buffer(&self, port: &JackPort) -> Option<&mut [f32]> {
69 unsafe {
70 let buf = jack_port_get_buffer(port.as_ptr(), self.nframes);
71 if buf.is_null() {
72 None
73 }
74 else {
75 Some(::std::slice::from_raw_parts_mut(buf as *mut f32, self.nframes as usize))
76 }
77 }
78 }
79}
80
81#[derive(Copy, Clone, Debug)]
83pub enum JackControl {
84 Continue = 0,
86 Stop = -1
88}
89pub trait JackHandler: Send {
94 fn process(&mut self, _ctx: &JackCallbackContext) -> JackControl {
111 JackControl::Stop
112 }
113 fn buffer_size(&mut self, _new_size: JackNFrames) -> JackControl { JackControl::Continue }
117 fn sample_rate(&mut self, _new_rate: JackNFrames) -> JackControl { JackControl::Continue }
123 fn thread_init(&mut self) { }
126 fn shutdown(&mut self, _status: JackStatus, _reason: &str) { }
128 fn client_registered(&mut self, _name: &str, _registered: bool) { }
132 fn xrun(&mut self) -> JackControl { JackControl::Continue }
134}
135impl<F> JackHandler for F where F: FnMut(&JackCallbackContext) -> JackControl + Send + 'static {
155 fn process(&mut self, ctx: &JackCallbackContext) -> JackControl {
156 self(ctx)
157 }
158}
159unsafe extern "C" fn buffer_size_callback<T>(frames: JackNFrames, user: *mut libc::c_void) -> libc::c_int where T: JackHandler {
160 let callbacks = &mut *(user as *mut T);
161 catch_unwind(AssertUnwindSafe(|| {
162 callbacks.buffer_size(frames) as _
163 })).unwrap_or(-1)
164}
165unsafe extern "C" fn sample_rate_callback<T>(frames: JackNFrames, user: *mut libc::c_void) -> libc::c_int where T: JackHandler {
166 let callbacks = &mut *(user as *mut T);
167 catch_unwind(AssertUnwindSafe(|| {
168 callbacks.sample_rate(frames) as _
169 })).unwrap_or(-1)
170}
171unsafe extern "C" fn client_registration_callback<T>(name: *const libc::c_char, register: libc::c_int, user: *mut libc::c_void) where T: JackHandler {
172 let callbacks = &mut *(user as *mut T);
173 let name = CStr::from_ptr(name);
174 let _ = catch_unwind(AssertUnwindSafe(|| {
175 callbacks.client_registered(&name.to_string_lossy(), register != 0)
176 }));
177
178}
179unsafe extern "C" fn info_shutdown_callback<T>(code: jack_status_t, reason: *const libc::c_char, user: *mut libc::c_void) where T: JackHandler {
180 let callbacks = &mut *(user as *mut T);
181 let code = JackStatus::from_bits_truncate(code);
182 let reason = CStr::from_ptr(reason);
183 let _ = catch_unwind(AssertUnwindSafe(|| {
184 callbacks.shutdown(code, &reason.to_string_lossy())
185 }));
186
187}
188unsafe extern "C" fn thread_init_callback<T>(user: *mut libc::c_void) where T: JackHandler {
189 let callbacks = &mut *(user as *mut T);
190 let _ = catch_unwind(AssertUnwindSafe(|| {
191 callbacks.thread_init()
192 }));
193}
194unsafe extern "C" fn process_callback<T>(nframes: JackNFrames, user: *mut libc::c_void) -> libc::c_int where T: JackHandler {
195 let callbacks = &mut *(user as *mut T);
196 let ctx = JackCallbackContext {
197 nframes: nframes
198 };
199 catch_unwind(AssertUnwindSafe(|| {
200 callbacks.process(&ctx) as _
201 })).unwrap_or(-1)
202}
203unsafe extern "C" fn xrun_callback<T>(user: *mut libc::c_void) -> libc::c_int where T: JackHandler {
204 let callbacks = &mut *(user as *mut T);
205 catch_unwind(AssertUnwindSafe(|| {
206 callbacks.xrun() as _
207 })).unwrap_or(-1)
208}
209pub fn set_handler<F>(conn: &mut JackConnection<Deactivated>, handler: F) -> JackResult<()> where F: JackHandler {
210 let user_ptr = Box::into_raw(Box::new(handler));
211 let user_ptr = user_ptr as *mut libc::c_void;
212 unsafe {
213 let code = jack_set_process_callback(conn.handle, Some(process_callback::<F>), user_ptr);
214 if code != 0 { Err(JackError::UnknownErrorCode { from: "set_process_callback() - process", code: code })? }
215 let code = jack_set_thread_init_callback(conn.handle, Some(thread_init_callback::<F>), user_ptr);
216 if code != 0 { Err(JackError::UnknownErrorCode { from: "set_process_callback() - thread_init", code: code })? }
217 let code = jack_set_buffer_size_callback(conn.handle, Some(buffer_size_callback::<F>), user_ptr);
218 if code != 0 { Err(JackError::UnknownErrorCode { from: "set_process_callback() - buffer_size", code: code })? }
219 let code = jack_set_sample_rate_callback(conn.handle, Some(sample_rate_callback::<F>), user_ptr);
220 if code != 0 { Err(JackError::UnknownErrorCode { from: "set_process_callback() - sample_rate", code: code })? }
221 let code = jack_set_xrun_callback(conn.handle, Some(xrun_callback::<F>), user_ptr);
222 if code != 0 { Err(JackError::UnknownErrorCode { from: "set_process_callback() - xrun", code: code })? }
223 let code = jack_set_client_registration_callback(conn.handle, Some(client_registration_callback::<F>), user_ptr);
224 if code != 0 { Err(JackError::UnknownErrorCode { from: "set_process_callback() - client_registration", code: code })? }
225 jack_on_info_shutdown(conn.handle, Some(info_shutdown_callback::<F>), user_ptr);
226 }
227 Ok(())
228}