rust_jack/callbacks.rs
1use std::{ffi, mem};
2use libc::c_void;
3use jack_sys as j;
4use enums::*;
5use flags::*;
6
7/// Specifies callbacks for Jack.
8///
9/// All callbacks happen on the same thread (not concurrently), unless otherwise
10/// stated.
11///
12/// # TODO
13/// * convert C enum return values to Rust enums.
14pub trait JackHandler {
15 /// Called just once after the creation of the thread in which all other
16 /// callbacks will be handled.
17 ///
18 /// It does not need to be suitable for real-time execution.
19 fn thread_init(&mut self) {}
20
21 /// Called when the Jack server shuts down the client thread. The function
22 /// must be written as if it were an asynchronous POSIX signal handler ---
23 /// use only async-safe functions, and remember that it is executed from
24 /// another thread. A typical funcion might set a flag or write to a pipe so
25 /// that the rest of the application knows that the Jack client thread has
26 /// shut down.
27
28 fn shutdown(&mut self, _status: ClientStatus, _reason: &str) {}
29 /// Called whenever there is work to be done.
30 ///
31 /// It needs to be suitable for real-time execution. That means that it
32 /// cannot call functions that might block for a long time. This includes
33 /// all I/O functions (disk, TTY, network), malloc, free, printf,
34 /// pthread_mutex_lock, sleep, wait, poll, select, pthread_join,
35 /// pthread_cond_wait, etc, etc.
36 ///
37 /// Should return `0` on success, and non-zero on error.
38 fn process(&mut self, _n_frames: u32) -> JackControl {
39 JackControl::Continue
40 }
41
42 /// Called whenever "freewheel" mode is entered or leaving.
43 fn freewheel(&mut self, _is_freewheel_enabled: bool) {}
44
45 /// Called whenever the size of the buffer that will be passed to `process`
46 /// is about to change.
47 fn buffer_size(&mut self, _size: u32) -> JackControl {
48 JackControl::Continue
49 }
50
51 /// Called whenever the system sample rate changes.
52 fn sample_rate(&mut self, _srate: u32) -> JackControl {
53 JackControl::Continue
54 }
55
56 /// Called whenever a client is registered or unregistered
57 fn client_registration(&mut self, _name: &str, _is_registered: bool) {}
58
59 /// Called whenever a port is registered or unregistered
60 fn port_registration(&mut self, _port_id: u32, _is_registered: bool) {}
61
62 /// Called whenever a port is renamed.
63 ///
64 /// # TODO
65 /// * Possibly fix description, Jack API docs have same description
66 /// for this as port registration.
67 fn port_rename(&mut self, _port_id: u32, _old_name: &str, _new_name: &str) -> JackControl {
68 JackControl::Continue
69 }
70
71 /// Called whenever ports are connected/disconnected to/from each other.
72 fn ports_connected(&mut self, _port_id_a: u32, _port_id_b: u32, _are_connected: bool) {}
73
74 /// Called whenever the processing graph is reordered.
75 fn graph_reorder(&mut self) -> JackControl {
76 JackControl::Continue
77 }
78
79 /// Called whenever an xrun occurs.
80 ///
81 /// An xrun is a buffer under or over run, which means some data has been
82 /// missed.
83 fn xrun(&mut self) -> JackControl {
84 JackControl::Continue
85 }
86
87 /// Called whenever it is necessary to recompute the latencies for some or
88 /// all Jack ports.
89 ///
90 /// It will be called twice each time it is needed, once being passed
91 /// `CaptureLatency` and once with `PlayBackLatency. See managing and
92 /// determining latency for the definition of each type of latency and
93 /// related functions. TODO: clear up the "see managing and ..." in the
94 /// docstring.
95 ///
96 /// IMPORTANT: Most Jack clients do NOT need to register a latency callback.
97 ///
98 /// Clients that meed any of the following conditions do NOT need to
99 /// register a latency callback:
100 ///
101 /// * have only input ports
102 ///
103 /// * have only output ports
104 ///
105 /// * their output is totally unrelated to their input
106 ///
107 /// * their output is not delayed relative to their input (i.e. data that
108 /// arrives in a `process` is processed and output again in the same
109 /// callback)
110 ///
111 /// Clients NOT registering a latency callback MUST also satisfy this condition
112 ///
113 /// * have no multiple distinct internal signal pathways
114 ///
115 /// This means that if your client has more than 1 input and output port,
116 /// and considers them always "correlated" (e.g. as a stereo pair), then
117 /// there is only 1 (e.g. stereo) signal pathway through the client. This
118 /// would be true, for example, of a stereo FX rack client that has a
119 /// left/right input pair and a left/right output pair.
120 ///
121 /// However, this is somewhat a matter of perspective. The same FX rack
122 /// client could be connected so that its two input ports were connected to
123 /// entirely separate sources. Under these conditions, the fact that the
124 /// client does not register a latency callback MAY result in port latency
125 /// values being incorrect.
126 ///
127 /// Clients that do not meet any of those conditions SHOULD register a
128 /// latency callback.
129 ///
130 /// See the documentation for `jack_port_set_latency_range()` on how the
131 /// callback should operate. Remember that the mode argument given to the
132 /// latency callback will need to be passed into
133 /// jack_port_set_latency_range()
134 fn latency(&mut self, _mode: LatencyType) {}
135}
136
137unsafe fn from_void<'a, T: JackHandler>(ptr: *mut c_void) -> &'a mut T {
138 assert!(!ptr.is_null());
139 let obj_ptr: *mut T = mem::transmute(ptr);
140 &mut *obj_ptr
141}
142
143extern "C" fn thread_init_callback<T: JackHandler>(data: *mut c_void) {
144 let obj: &mut T = unsafe { from_void(data) };
145 obj.thread_init()
146}
147
148extern "C" fn shutdown<T: JackHandler>(code: j::jack_status_t,
149 reason: *const i8,
150 data: *mut c_void) {
151 let obj: &mut T = unsafe { from_void(data) };
152 let reason_str = unsafe {
153 let cstr = ffi::CStr::from_ptr(reason);
154 match cstr.to_str() {
155 Ok(s) => s,
156 Err(_) => "Failed to interpret error.",
157 }
158 };
159 obj.shutdown(ClientStatus::from_bits(code).unwrap_or(UNKNOWN_ERROR),
160 reason_str)
161}
162
163extern "C" fn process<T: JackHandler>(n_frames: u32, data: *mut c_void) -> i32 {
164 let obj: &mut T = unsafe { from_void(data) };
165 obj.process(n_frames).to_ffi()
166}
167
168extern "C" fn freewheel<T: JackHandler>(starting: i32, data: *mut c_void) {
169 let obj: &mut T = unsafe { from_void(data) };
170 let is_starting = match starting {
171 0 => false,
172 _ => true,
173 };
174 obj.freewheel(is_starting)
175}
176
177extern "C" fn buffer_size<T: JackHandler>(n_frames: u32, data: *mut c_void) -> i32 {
178 let obj: &mut T = unsafe { from_void(data) };
179 obj.buffer_size(n_frames).to_ffi()
180}
181
182extern "C" fn sample_rate<T: JackHandler>(n_frames: u32, data: *mut c_void) -> i32 {
183 let obj: &mut T = unsafe { from_void(data) };
184 obj.sample_rate(n_frames).to_ffi()
185}
186
187extern "C" fn client_registration<T: JackHandler>(name: *const i8,
188 register: i32,
189 data: *mut c_void) {
190 let obj: &mut T = unsafe { from_void(data) };
191 let name = unsafe { ffi::CStr::from_ptr(name).to_str().unwrap() };
192 let register = match register {
193 0 => false,
194 _ => true,
195 };
196 obj.client_registration(name, register)
197}
198
199extern "C" fn port_registration<T: JackHandler>(port_id: u32, register: i32, data: *mut c_void) {
200 let obj: &mut T = unsafe { from_void(data) };
201 let register = match register {
202 0 => false,
203 _ => true,
204 };
205 obj.port_registration(port_id, register)
206}
207
208#[allow(dead_code)] // TODO: remove once it can be registered
209extern "C" fn port_rename<T: JackHandler>(port_id: u32,
210 old_name: *const i8,
211 new_name: *const i8,
212 data: *mut c_void)
213 -> i32 {
214 let obj: &mut T = unsafe { from_void(data) };
215 let old_name = unsafe { ffi::CStr::from_ptr(old_name).to_str().unwrap() };
216 let new_name = unsafe { ffi::CStr::from_ptr(new_name).to_str().unwrap() };
217 obj.port_rename(port_id, old_name, new_name).to_ffi()
218}
219
220extern "C" fn port_connect<T: JackHandler>(port_id_a: u32,
221 port_id_b: u32,
222 connect: i32,
223 data: *mut c_void) {
224 let obj: &mut T = unsafe { from_void(data) };
225 let are_connected = match connect {
226 0 => false,
227 _ => true,
228 };
229 obj.ports_connected(port_id_a, port_id_b, are_connected)
230}
231
232extern "C" fn graph_order<T: JackHandler>(data: *mut c_void) -> i32 {
233 let obj: &mut T = unsafe { from_void(data) };
234 obj.graph_reorder().to_ffi()
235}
236
237extern "C" fn xrun<T: JackHandler>(data: *mut c_void) -> i32 {
238 let obj: &mut T = unsafe { from_void(data) };
239 obj.xrun().to_ffi()
240}
241
242extern "C" fn latency<T: JackHandler>(mode: j::jack_latency_callback_mode_t, data: *mut c_void) {
243 let obj: &mut T = unsafe { from_void(data) };
244 let mode = match mode {
245 j::JackCaptureLatency => LatencyType::Capture,
246 j::JackPlaybackLatency => LatencyType::Playback,
247 _ => unreachable!(),
248 };
249 obj.latency(mode)
250}
251
252/// Clears the callbacks registered to `client`.
253///
254/// Returns `Err(JackErr::CallbackDeregistrationError)` on failure.
255///
256/// # Unsafe
257/// * Uses ffi calls, be careful.
258///
259/// # TODO
260/// * Implement correctly. Freezes on my system.
261pub unsafe fn clear_callbacks(_client: *mut j::jack_client_t) -> Result<(), JackErr> {
262 // j::jack_set_thread_init_callback(client, None, ptr::null_mut());
263 // j::jack_set_process_callback(client, None, ptr::null_mut());
264 Ok(())
265}
266
267/// Registers methods from `handler` to be used by Jack with `client`.
268///
269/// Returns `Ok(handler_ptr)` on success, or
270/// `Err(JackErr::CallbackRegistrationError)` on failure.
271///
272/// Registers `handler` with jack. All jack calls to `client` will be handled by
273/// `handler`. `handler` is consumed, but it is not deallocated. `handler`
274/// should be manually deallocated when jack will no longer make calls to it,
275/// such as when registering new callbacks with the same client, or dropping the
276/// client.
277///
278/// # TODO
279/// * Handled failed registrations
280/// * Fix `jack_set_port_rename_callback`
281///
282/// # Unsafe
283/// * `handler` will not be automatically deallocated.
284pub unsafe fn register_callbacks<T: JackHandler>(client: *mut j::jack_client_t,
285 handler: T)
286 -> Result<*mut T, JackErr> {
287 let handler_ptr: *mut T = Box::into_raw(Box::new(handler));
288 let data_ptr = mem::transmute(handler_ptr);
289 j::jack_set_thread_init_callback(client, Some(thread_init_callback::<T>), data_ptr);
290 j::jack_on_info_shutdown(client, Some(shutdown::<T>), data_ptr);
291 j::jack_set_process_callback(client, Some(process::<T>), data_ptr);
292 j::jack_set_freewheel_callback(client, Some(freewheel::<T>), data_ptr);
293 j::jack_set_buffer_size_callback(client, Some(buffer_size::<T>), data_ptr);
294 j::jack_set_sample_rate_callback(client, Some(sample_rate::<T>), data_ptr);
295 j::jack_set_client_registration_callback(client, Some(client_registration::<T>), data_ptr);
296 j::jack_set_port_registration_callback(client, Some(port_registration::<T>), data_ptr);
297 // doesn't compile for testing
298 // j::jack_set_port_rename_callback(client, Some(port_rename::<T>), data_ptr);
299 j::jack_set_port_connect_callback(client, Some(port_connect::<T>), data_ptr);
300 j::jack_set_graph_order_callback(client, Some(graph_order::<T>), data_ptr);
301 j::jack_set_xrun_callback(client, Some(xrun::<T>), data_ptr);
302 j::jack_set_latency_callback(client, Some(latency::<T>), data_ptr);
303 Ok(handler_ptr)
304}