rust_jack/
client.rs

1use std::{ffi, ptr};
2use jack_sys as j;
3use callbacks;
4use port;
5use enums::*;
6use flags::*;
7use port::*;
8use utils;
9use callbacks::JackHandler;
10
11#[derive(Clone, Copy, Debug)]
12pub struct CycleTimes {
13    pub current_frames: u32,
14    pub current_usecs: u64,
15    pub next_usecs: u64,
16    pub period_usecs: f32,
17}
18
19/// A client to interact with a Jack server.
20///
21/// # Example
22/// ```
23/// // TODO: make example
24/// ```
25#[derive(Debug)]
26pub struct Client<T: JackHandler> {
27    client: *mut j::jack_client_t,
28    handler: *mut T,
29    status: ClientStatus,
30}
31
32impl<T: JackHandler> Client<T> {
33    /// The maximum length of the Jack client name string. Unlike the "C" Jack
34    /// API, this does not take into account the final `NULL` character and
35    /// instead corresponds directly to `.len()`. This value is constant.
36    pub fn name_size() -> usize {
37        let s = unsafe { j::jack_client_name_size() - 1 };
38        s as usize
39    }
40
41    /// The buffer size of a port type
42    ///
43    /// # Unsafe
44    ///
45    /// * This function may only be called in a buffer size callback.
46    pub unsafe fn type_buffer_size(&self, port_type: &str) -> usize {
47        let port_type = ffi::CString::new(port_type).unwrap();
48        let n = j::jack_port_type_get_buffer_size(self.client, port_type.as_ptr());
49        n
50    }
51
52    /// Opens a Jack client with the given name and options. If the client is
53    /// successfully opened, then `Ok(client)` is returned. If there is a
54    /// failure, then `Err(JackErr::ClientError(status))` will be returned.
55    ///
56    /// Although the client may be successful in opening, there still may be
57    /// some errors minor errors when attempting to opening. To access these,
58    /// check `Client::status()`.
59    pub fn open(client_name: &str, options: ClientOptions) -> Result<Self, JackErr> {
60        let mut status_bits = 0;
61        let client = unsafe {
62            let client_name = ffi::CString::new(client_name).unwrap();
63            j::jack_client_open(ffi::CString::new(client_name).unwrap().as_ptr(),
64                                options.bits(),
65                                &mut status_bits)
66        };
67        let status = ClientStatus::from_bits(status_bits).unwrap_or(UNKNOWN_ERROR);
68        if client.is_null() {
69            Err(JackErr::ClientError(status))
70        } else {
71            Ok(Client {
72                client: client,
73                handler: ptr::null_mut(),
74                status: status,
75            })
76        }
77    }
78
79    /// Disconnects the client from the Jack server. This does not need to
80    /// manually be called, as the client will automatically close when the
81    /// client object is dropped.
82    pub fn close(self) {}
83
84    /// Get the status of the client.
85    pub fn status(&self) -> ClientStatus {
86        self.status
87    }
88
89    /// Get the name of the current client. This may differ from the name
90    /// requested by `Client::open` as Jack will may rename a client if
91    /// necessary (ie: name collision, name too long). If the name has changed,
92    /// it should be indicated by `Client::status`.
93    pub fn name<'a>(&'a self) -> &'a str {
94        unsafe {
95            let ptr = j::jack_get_client_name(self.client);
96            let cstr = ffi::CStr::from_ptr(ptr);
97            cstr.to_str().unwrap()
98        }
99    }
100
101    /// Get the uuid of the current client.
102    pub fn uuid<'a>(&'a self) -> &'a str {
103        self.uuid_by_name(self.name()).unwrap()
104    }
105
106    /// Get the pthread ID of the thread running the Jack client side code.
107    ///
108    /// # TODO
109    /// * Integrate a pthread library
110    /// * Implement, do people need this though?
111    pub fn thread_id<P>(&self) -> P {
112        unimplemented!();
113    }
114
115    /// Get the name of the client with the UUID specified by `uuid`. If the
116    /// client is found then `Some(name)` is returned, if not, then `None` is
117    /// returned.
118    pub fn name_by_uuid<'a>(&'a self, uuid: &str) -> Option<&'a str> {
119        unsafe {
120            let uuid = ffi::CString::new(uuid).unwrap();
121            let name_ptr = j::jack_get_client_name_by_uuid(self.client, uuid.as_ptr());
122            if name_ptr.is_null() {
123                None
124            } else {
125                Some(ffi::CStr::from_ptr(name_ptr).to_str().unwrap())
126            }
127        }
128    }
129
130    /// Get the uuid of the client with the name specified by `name`. If the
131    /// client is found then `Some(uuid)` is returned, if not, then `None` is
132    /// returned.
133    pub fn uuid_by_name<'a>(&'a self, name: &str) -> Option<&'a str> {
134        unsafe {
135            let name = ffi::CString::new(name).unwrap();
136            let uuid_ptr = j::jack_get_client_name_by_uuid(self.client, name.as_ptr());
137            if uuid_ptr.is_null() {
138                None
139            } else {
140                Some(ffi::CStr::from_ptr(uuid_ptr).to_str().unwrap())
141            }
142        }
143    }
144
145    /// Returns a vector of ports that match the specified arguments
146    ///
147    /// `port_name_pattern` - A regular expression used to select ports by
148    /// name. If `None` or zero lengthed, no selection based on name will be
149    /// carried out.
150    ///
151    /// `type_name_pattern` - A regular expression used to select ports by
152    /// type. If `None` or zero lengthed, no selection based on type will be
153    /// carried out.
154    ///
155    /// `flags` - A value used to select ports by their flags. Use
156    /// `PortFlags::empty()` for no flag selection.
157    pub fn ports(&self,
158                 port_name_pattern: Option<&str>,
159                 type_name_pattern: Option<&str>,
160                 flags: PortFlags)
161                 -> Vec<String> {
162        let pnp = ffi::CString::new(port_name_pattern.unwrap_or("")).unwrap();
163        let tnp = ffi::CString::new(type_name_pattern.unwrap_or("")).unwrap();
164        let flags = flags.bits() as u64;
165        unsafe {
166            utils::collect_strs(j::jack_get_ports(self.client, pnp.as_ptr(), tnp.as_ptr(), flags))
167        }
168    }
169
170    /// Get a `Port` by its port name.
171    pub fn port_by_name(&self, port_name: &str) -> Option<Port> {
172        let port_name = ffi::CString::new(port_name).unwrap();
173        unsafe {
174            ptrs_to_port(self.client,
175                         j::jack_port_by_name(self.client, port_name.as_ptr()))
176        }
177    }
178
179    /// Get a `Port` by its port id.
180    pub fn port_by_id(&self, port_id: u32) -> Option<Port> {
181        unsafe { ptrs_to_port(self.client, j::jack_port_by_id(self.client, port_id)) }
182    }
183
184    /// Tell the Jack server that the program is ready to start processing
185    /// audio. Jack will call the methods specified by the `JackHandler` trait, from `handler`.
186    ///
187    /// On failure, either `Err(JackErr::CallbackRegistrationError)` or
188    /// `Err(JackErr::ClientActivationError)` is returned.
189    ///
190    /// `handler` is consumed, but it is returned when `Client::deactivate` is
191    /// called.
192    pub fn activate(&mut self, handler: T) -> Result<(), JackErr> {
193        let handler = try!(unsafe { callbacks::register_callbacks(self.client, handler) });
194        if handler.is_null() {
195            Err(JackErr::CallbackRegistrationError)
196        } else {
197            let res = unsafe { j::jack_activate(self.client) };
198            match res {
199                0 => {
200                    self.handler = handler;
201                    Ok(())
202                }
203                _ => {
204                    unsafe { Box::from_raw(handler) };
205                    Err(JackErr::ClientActivationError)
206                }
207            }
208        }
209    }
210
211    /// Tell the Jack server to remove this client from the process graph. Also,
212    /// disconnect all ports belonging to it since inactive clients have no port
213    /// connections.
214    ///
215    /// The `handler` that was used for `Client::activate` is returned on
216    /// success. Its state may have changed due to Jack calling its methods.
217    pub fn deactivate(&mut self) -> Result<Box<T>, JackErr> {
218        if self.handler.is_null() {
219            return Err(JackErr::InvalidDeactivation);
220        }
221        let res = unsafe { j::jack_deactivate(self.client) };
222        let handler_ptr = self.handler;
223        self.handler = ptr::null_mut();
224        try!(unsafe { callbacks::clear_callbacks(self.client) });
225        match res {
226            0 => Ok(unsafe { Box::from_raw(handler_ptr) }),
227            _ => Err(JackErr::ClientDeactivationError),
228        }
229    }
230
231    /// Create a new port for the client. This is an object used for moving data
232    /// of any type in or out of the client. Ports may be connected in various
233    /// ways.
234    ///
235    /// Each port has a short name. The port's full name contains the name of
236    /// the client concatenated with a colon (:) followed by its short
237    /// name. `Port::name_size()` is the maximum length of the full
238    /// name. Exceeding that will cause the port registration to fail and return
239    /// `Err(())`.
240    ///
241    /// The `port_name` must be unique among all ports owned by this client. If
242    /// the name is not unique, the registration will fail.
243    ///
244    /// All ports have a type, which may be any non empty string, passed as an
245    /// argument. Some port types are built into the Jack API, like
246    /// `DEFAULT_AUDIO_TYPE` and `DEFAULT_MIDI_TYPE`.
247    ///
248    /// # Parameters
249    ///
250    /// `port_name` - non-empty short name for the new port (not including the
251    /// lading "client_name:"). Must be unique.
252    ///
253    /// `port_type` - port type name. If longer than `Port::type_size()`, only
254    /// that many characters are significant.
255    ///
256    /// `flags` - `PortFlags` bit mask.
257    ///
258    /// `buffer_size` - Must be `Some(n)` if this is not a built-in
259    /// `port_type`. Otherwise, it is ignored.
260    pub fn register_port(&mut self,
261                         port_name: &str,
262                         port_type: &str,
263                         flags: PortFlags,
264                         buffer_size: Option<usize>)
265                         -> Result<Port, JackErr> {
266        let port_name = ffi::CString::new(port_name).unwrap();
267        let port_type = ffi::CString::new(port_type).unwrap();
268        let port_flags = flags.bits() as u64;
269        let buffer_size = buffer_size.unwrap_or(0) as u64;
270        let port = unsafe {
271            let ptr = j::jack_port_register(self.client,
272                                            port_name.as_ptr(),
273                                            port_type.as_ptr(),
274                                            port_flags,
275                                            buffer_size);
276            ptrs_to_port(self.client, ptr)
277        };
278        match port {
279            Some(p) => Ok(p),
280            None => Err(JackErr::PortRegistrationError),
281        }
282    }
283
284    /// Returns `true` if the port `port` belongs to this client.
285    pub fn is_mine(&self, port: &Port) -> bool {
286        match unsafe { j::jack_port_is_mine(self.client, port::port_pointer(port)) } {
287            0 => false,
288            _ => true,
289        }
290    }
291
292    /// Toggle input monitoring for the port with name `port_name`.
293    ///
294    /// `Err(JackErr::PortMonitorError)` is returned on failure.
295    ///
296    /// Only works if the port has the `CAN_MONITOR` flag, or else nothing
297    /// happens.
298    pub fn request_monitor(&self, port_name: &str, enable_monitor: bool) -> Result<(), JackErr> {
299        let port_name = ffi::CString::new(port_name).unwrap();
300        let onoff = match enable_monitor {
301            true => 1,
302            false => 0,
303        };
304        let res =
305            unsafe { j::jack_port_request_monitor_by_name(self.client, port_name.as_ptr(), onoff) };
306        match res {
307            0 => Ok(()),
308            _ => Err(JackErr::PortMonitorError),
309        }
310    }
311
312    /// Establish a connection between two ports.
313    ///
314    /// When a connection exists, data written to the source port will be
315    /// available to be read at the destination port.
316    ///
317    /// On failure, either a `PortNotFound` or `PortConnectionError` is returned.
318    ///
319    /// # Preconditions
320    /// 1. The port types must be identical
321    /// 2. The port flags of the `source_port` must include `IS_OUTPUT`
322    /// 3. The port flags of the `destination_port` must include `IS_INPUT`.
323    pub fn connect_ports(&self, source_port: &str, destination_port: &str) -> Result<(), JackErr> {
324        let source_port = ffi::CString::new(source_port).unwrap();
325        let destination_port = ffi::CString::new(destination_port).unwrap();
326
327        let res = unsafe {
328            j::jack_connect(self.client, source_port.as_ptr(), destination_port.as_ptr())
329        };
330        match res {
331            0 => Ok(()),
332            ::libc::EEXIST => Err(JackErr::PortNotFound),
333            _ => Err(JackErr::PortConnectionError),
334        }
335    }
336
337    /// Remove a connection between two ports.
338    pub fn disconnect_ports(&self,
339                            source_port: &str,
340                            destination_port: &str)
341                            -> Result<(), JackErr> {
342        let source_port = ffi::CString::new(source_port).unwrap();
343        let destination_port = ffi::CString::new(destination_port).unwrap();
344        let res = unsafe {
345            j::jack_disconnect(self.client, source_port.as_ptr(), destination_port.as_ptr())
346        };
347        match res {
348            0 => Ok(()),
349            _ => Err(JackErr::PortDisconnectionError),
350        }
351    }
352
353    /// The sample rate of the jack system, as set by the user when jackd was
354    /// started.
355    pub fn sample_rate(&self) -> usize {
356        let srate = unsafe { j::jack_get_sample_rate(self.client) };
357        srate as usize
358    }
359
360    /// The current maximum size that will every be passed to the process
361    /// callback.
362    ///
363    /// It should only be used *before* the client has been activated. This size
364    /// may change,c lients that depend on it must register a buffer size
365    /// callback so they will be notified if it does.
366    pub fn buffer_size(&self) -> usize {
367        let bsize = unsafe { j::jack_get_buffer_size(self.client) };
368        bsize as usize
369    }
370
371    /// The current CPU load estimated by Jack.
372    ///
373    /// This is a running average of the time it takes to execute a full process
374    /// cycle for all clients as a percentage of the real time available per
375    /// cycle determined by the buffer size and sample rate.
376    pub fn cpu_load(&self) -> f32 {
377        let load = unsafe { j::jack_cpu_load(self.client) };
378        load
379    }
380
381    /// Start/Stop Jack's "freewheel" mode.
382    ///
383    /// When in "freewheel" mode, Jack no longer waits for any external event to
384    /// begin the start of the next process cycle. As a result, freewheel mode
385    /// causes "faster than real-time" execution of a Jack graph. If possessed,
386    /// real-time scheduling is dropped when entering freewheel mode, and if
387    /// appropriate it is reacquired when stopping.
388    ///
389    /// IMPORTANT: on systems using capabilities to provide real-time scheduling
390    /// (i.e. Linux Kernel 2.4), if enabling freewheel, this function must be
391    /// called from the thread that originally called `self.activate()`. This
392    /// restriction does not apply to other systems (e.g. Linux Kernel 2.6 or OS
393    /// X).
394    pub fn set_freewheel(&self, enable: bool) -> Result<(), JackErr> {
395        let onoff = match enable {
396            true => 0,
397            false => 1,
398        };
399        match unsafe { j::jack_set_freewheel(self.client, onoff) } {
400            0 => Ok(()),
401            _ => Err(JackErr::FreewheelError),
402        }
403    }
404
405    /// Change the buffer size passed to the process callback.
406    ///
407    /// This operation stops the jack engine process cycle, then calls all
408    /// registered buffer size callback functions before restarting the process
409    /// cycle. This will cause a gap in the audio flow, so it should only be
410    /// done at appropriate stopping points.
411    pub fn set_buffer_size(&self, n_frames: usize) -> Result<(), JackErr> {
412        let n_frames = n_frames as u32;
413        let res = unsafe { j::jack_set_buffer_size(self.client, n_frames) };
414        match res {
415            0 => Ok(()),
416            _ => Err(JackErr::SetBufferSizeError),
417        }
418    }
419
420    /// The estimated time in frames that has passed since the Jack server began
421    /// the current process cycle.
422    pub fn frames_since_cycle_start(&self) -> u32 {
423        unsafe { j::jack_frames_since_cycle_start(self.client) }
424    }
425
426    /// The estimated current time in frames. This function is intended for use
427    /// in other threads (not the process callback). The return value can be
428    /// compared with the value of `last_frame_time` to relate time in other
429    /// threads to Jack time.
430    pub fn frame_time(&self) -> u32 {
431        unsafe { j::jack_frame_time(self.client) }
432    }
433
434    /// The precise time at the start of the current process cycle. This
435    /// function may only be used from the process callback, and can be used to
436    /// interpret timestamps generated by `self.frame_time()` in other threads,
437    /// with respect to the current process cycle.
438    pub fn last_frame_time(&self) -> u32 {
439        unsafe { j::jack_last_frame_time(self.client) }
440    }
441
442    /// This function may only be used from the process callback. It provides
443    /// the internal cycle timing information as used by most of the other time
444    /// related functions. This allows the caller to map between frame counts
445    /// and microseconds with full precision (i.e. without rounding frame times
446    /// to integers), and also provides e.g. the microseconds time of the start
447    /// of the current cycle directly (it has to be computed otherwise).
448    ///
449    /// `Err(JackErr::TimeError)` is returned on failure.
450    pub fn cycle_times(&self) -> Result<CycleTimes, JackErr> {
451        let mut current_frames: u32 = 0;
452        let mut current_usecs: u64 = 0;
453        let mut next_usecs: u64 = 0;
454        let mut period_usecs: f32 = 0.0;
455        let res = unsafe {
456            j::jack_get_cycle_times(self.client,
457                                    &mut current_frames,
458                                    &mut current_usecs,
459                                    &mut next_usecs,
460                                    &mut period_usecs)
461        };
462        match res {
463            0 => {
464                Ok(CycleTimes {
465                    current_frames: current_frames,
466                    current_usecs: current_usecs,
467                    next_usecs: next_usecs,
468                    period_usecs: period_usecs,
469                })
470            },
471            _ => Err(JackErr::TimeError),
472        }
473    }
474
475    /// The estimated time in microseconds of the specified frame time
476    pub fn frames_to_time(&self, n_frames: u32) -> u64 {
477        unsafe { j::jack_frames_to_time(self.client, n_frames) }
478    }
479
480    /// The estimated time in frames for the specified system time.
481    pub fn time_to_frames(&self, t: u64) -> u32 {
482        unsafe { j::jack_time_to_frames(self.client, t) }
483    }
484
485}
486
487/// Closes the client, no need to manually call `Client::close()`.
488impl<T: JackHandler> Drop for Client<T> {
489    fn drop(&mut self) {
490        let _ = self.deactivate(); // may be Ok or Err, doesn't matter. TODO: fix style
491        if !self.client.is_null() {
492            let res = unsafe { j::jack_client_close(self.client) };
493            assert_eq!(res, 0);
494            self.client = ptr::null_mut();
495        }
496    }
497}