rust_jack/
port.rs

1use std::{ffi, slice};
2use jack_sys as j;
3use flags::*;
4use enums::*;
5use utils;
6
7/// Converts a jack client handle and jack port handle in a `Port`. If either
8/// `client` or `port` is `null`, then `None` is returned.
9pub unsafe fn ptrs_to_port(client: *mut j::jack_client_t,
10                           port: *mut j::jack_port_t)
11                           -> Option<Port> {
12    if client.is_null() || port.is_null() {
13        None
14    } else {
15        Some(Port {
16            client: client,
17            port: port,
18        })
19    }
20}
21
22pub unsafe fn port_pointer(port: &Port) -> *mut j::jack_port_t {
23    port.port
24}
25
26/// An endpoint to interact with Jack data streams, for audio, midi, etc...
27#[derive(Debug, Clone, Copy)]
28pub struct Port {
29    client: *mut j::jack_client_t,
30    port: *mut j::jack_port_t,
31}
32
33impl Port {
34    /// The maximum length of a full Jack port name. Unlike the "C" Jack API,
35    /// this does not count the `NULL` character and corresponds to a string's
36    /// `.len()`.
37    ///
38    /// The port's full name contains the owning client name concatenated with a
39    /// colon (:) followed by its short name.
40    ///
41    /// This value is constant
42    pub fn name_size() -> usize {
43        let s = unsafe { j::jack_port_name_size() - 1 };
44        s as usize
45    }
46
47    /// The maximum length of a port type. Unlike the "C" Jack API, this does
48    /// not count the `NULL` character and corresponds to a string's `.len()`.
49    ///
50    /// This value is constant.
51    pub fn type_size() -> usize {
52        let s = unsafe { j::jack_port_type_size() - 1 };
53        s as usize
54    }
55
56    /// Remove the port from the client, disconnecting any existing connections.
57    pub fn unregister(self) -> Result<(), JackErr> {
58        let res = unsafe { j::jack_port_unregister(self.client, self.port) };
59        match res {
60            0 => Ok(()),
61            _ => Err(JackErr::CallbackDeregistrationError),
62        }
63    }
64
65    /// Returns the full name of the port, including the "client_name:" prefix.
66    pub fn name<'a>(&'a self) -> &'a str {
67        unsafe { ffi::CStr::from_ptr(j::jack_port_name(self.port)).to_str().unwrap() }
68    }
69
70    /// Returns the short name of the port, it excludes the "client_name:" prefix.
71    pub fn short_name<'a>(&'a self) -> &'a str {
72        unsafe { ffi::CStr::from_ptr(j::jack_port_short_name(self.port)).to_str().unwrap() }
73    }
74
75    /// Returns the uuid of the port as a u64.
76    pub fn uuid(&self) -> u64 {
77        unsafe { j::jack_port_uuid(self.port) }
78    }
79
80    /// The flags for the port. These are set when the port is registered with
81    /// its client.
82    pub fn flags(&self) -> PortFlags {
83        let bits = unsafe { j::jack_port_flags(self.port) };
84        PortFlags::from_bits(bits as u32).unwrap()
85    }
86
87    /// The port type. Jack's built in types include "32 bit float mono audio"
88    /// and "8 bit raw midi". Custom types may also be used.
89    pub fn port_type<'a>(&self) -> &'a str {
90        unsafe { ffi::CStr::from_ptr(j::jack_port_type(self.port)).to_str().unwrap() }
91    }
92
93    /// Number of ports connected to/from
94    pub fn connected_count(&self) -> usize {
95        let n = unsafe { j::jack_port_connected(self.port) };
96        n as usize
97    }
98
99    /// Returns `true` if the port is directly connected to a port with the name
100    /// `port_name`.
101    pub fn is_connected_to(&self, port_name: &str) -> bool {
102        let res = unsafe {
103            let port_name = ffi::CString::new(port_name).unwrap();
104            j::jack_port_connected_to(self.port, port_name.as_ptr())
105        };
106        match res {
107            0 => false,
108            _ => true,
109        }
110    }
111
112    /// Full port names to which `self` is connected to. This combines Jack's
113    /// `jack_port_get_all_connections()` and `jack_port_get_connections()`. If
114    /// the `client` from which `port` was spawned from is the owner, then it
115    /// may be used in the graph reordered callback or else it should not be
116    /// used.
117    ///
118    /// # Unsafe
119    ///
120    /// * Can't be used in the callback for graph reordering under certain
121    /// conditions.
122    pub unsafe fn connections(&self) -> Vec<String> {
123        let connections_ptr = {
124            let ptr = if j::jack_port_is_mine(self.client, self.port) != 0 {
125                j::jack_port_get_connections(self.port)
126            } else {
127                j::jack_port_get_all_connections(self.client, self.port)
128            };
129            utils::collect_strs(ptr)
130        };
131        connections_ptr
132    }
133
134    /// Get the alias names for `self`.
135    ///
136    /// Will return a vector of strings of up to 2 elements.
137    ///
138    /// # TODO: Implement
139    pub fn aliases(&self) -> Vec<String> {
140        unimplemented!();
141    }
142
143    /// Returns `true` if monitoring has been requested for `self`.
144    pub fn is_monitoring_input(&self) -> bool {
145        match unsafe { j::jack_port_monitoring_input(self.port) } {
146            0 => false,
147            _ => true,
148        }
149    }
150
151    /// Set's the short name of the port. If the full name is longer than
152    /// `Port::name_size()`, then it will be truncated.
153    pub fn set_name(&self, short_name: &str) -> Result<(), JackErr> {
154        let short_name = ffi::CString::new(short_name).unwrap();
155        let res = unsafe { j::jack_port_set_name(self.port, short_name.as_ptr()) };
156        match res {
157            0 => Ok(()),
158            _ => Err(JackErr::PortNamingError),
159        }
160    }
161
162    /// Sets `alias` as an alias for `self`.
163    ///
164    /// May be called at any time. If the alias is longer than
165    /// `Client::name_size()`, it will be truncated.
166    ///
167    /// After a successful call, and until Jack exists, or the alias is unset,
168    /// `alias` may be used as an alternate name for the port.
169    ///
170    /// Ports can have up to two aliases - if both are already set, this
171    /// function will return an error.
172    pub fn set_alias(&self, alias: &str) -> Result<(), JackErr> {
173        let alias = ffi::CString::new(alias).unwrap();
174        let res = unsafe { j::jack_port_set_alias(self.port, alias.as_ptr()) };
175        match res {
176            0 => Ok(()),
177            _ => Err(JackErr::PortAliasError),
178        }
179    }
180
181    /// Remove `alias` as an alias for port. May be called at any time.
182    ///
183    /// After a successful call, `alias` can no longer be used as an alternate
184    /// name for `self`.
185    pub fn unset_alias(&self, alias: &str) -> Result<(), JackErr> {
186        let alias = ffi::CString::new(alias).unwrap();
187        let res = unsafe { j::jack_port_unset_alias(self.port, alias.as_ptr()) };
188        match res {
189            0 => Ok(()),
190            _ => Err(JackErr::PortAliasError),
191        }
192    }
193
194    /// Turn input monitoring for the port on or off.
195    ///
196    /// This only works if the port has the `CAN_MONITOR` flag set.
197    pub fn request_monitor(&self, enable_monitor: bool) -> Result<(), JackErr> {
198        let onoff = match enable_monitor {
199            true => 1,
200            false => 0,
201        };
202        let res = unsafe { j::jack_port_request_monitor(self.port, onoff) };
203        match res {
204            0 => Ok(()),
205            _ => Err(JackErr::PortMonitorError),
206        }
207    }
208
209    /// If the `CAN_MONITOR` flag is set for the port, then input monitoring is
210    /// turned on if it was off, and turns it off if only one request has been
211    /// made to turn it on. Otherwise it does nothing.
212    pub fn ensure_monitor(&self, enable_monitor: bool) -> Result<(), JackErr> {
213        let onoff = match enable_monitor {
214            true => 1,
215            false => 0,
216        };
217        let res = unsafe { j::jack_port_ensure_monitor(self.port, onoff) };
218        match res {
219            0 => Ok(()),
220            _ => Err(JackErr::PortMonitorError),
221        }
222    }
223
224    /// Perform the same function as `Client::disconnect_ports()`, but with a
225    /// port handle instead.
226    ///
227    /// Avoids the name lookup inherent in the name-based version.
228    ///
229    /// Clients connecting their own ports are likely to use this function,
230    /// while generic connection clients (e.g. patchbays) would use
231    /// `Client::disconnect_ports()`.
232    pub fn disconnect(&self) -> Result<(), JackErr> {
233        match unsafe { j::jack_port_disconnect(self.client, self.port) } {
234            0 => Ok(()),
235            _ => Err(JackErr::PortDisconnectionError),
236        }
237    }
238
239    /// Returns a pointer to the memory area associated with the specified
240    /// port. For an output port, it will be a memory area that can be written
241    /// to; for an input port, it will be an area containing the data from the
242    /// port's connection(s), or zero-filled. If there are multiple inbound
243    /// connections, the data will be mixed appropriately.
244    ///
245    /// Do not cache the returned address across `process()` calls. Port buffers
246    /// have to be retrieved in each callback for proper functioning.
247    pub unsafe fn buffer(&self, n_frames: u32) -> *mut ::libc::c_void {
248        j::jack_port_get_buffer(self.port, n_frames)
249    }
250
251    /// Interprets the buffer as a slice of type `T` with length `n_frames`.
252    pub unsafe fn as_slice<T>(&self, n_frames: u32) -> &[T] {
253        let buffer = self.buffer(n_frames) as *const T;
254        slice::from_raw_parts(buffer, n_frames as usize)
255    }
256
257    /// Interprets the buffer as a mutable slice of type `T` with length
258    /// `n_frames`.
259    pub unsafe fn as_slice_mut<T>(&self, n_frames: u32) -> &mut [T] {
260        let buffer = self.buffer(n_frames) as *mut T;
261        slice::from_raw_parts_mut(buffer, n_frames as usize)
262    }
263}