1 use std::{ffi, fmt, iter}; 2 use std::marker::Sized; 3 4 use libc; 5 6 use jack_enums::JackErr; 7 use jack_sys as j; 8 use port::port_flags::PortFlags; 9 use primitive_types as pt; 10 11 lazy_static! { 12 /// The maximum string length for port names. 13 pub static ref PORT_NAME_SIZE: usize = unsafe { j::jack_port_name_size() - 1 } as usize; 14 15 /// The maximum string length for jack type names. 16 pub static ref PORT_TYPE_SIZE: usize = unsafe { j::jack_port_type_size() - 1 } as usize; 17 } 18 19 /// Defines the configuration for a certain port to JACK, ie 32 bit floating 20 /// audio input, 8 bit raw 21 /// midi output, etc... 22 pub unsafe trait PortSpec: Sized { 23 /// String used by JACK upon port creation to identify the port 24 /// type. jack_port_type(&self) -> &str25 fn jack_port_type(&self) -> &str; 26 27 /// Flags used by jack upon port creation. jack_flags(&self) -> PortFlags28 fn jack_flags(&self) -> PortFlags; 29 30 /// Size used by jack upon port creation. jack_buffer_size(&self) -> libc::c_ulong31 fn jack_buffer_size(&self) -> libc::c_ulong; 32 } 33 34 /// An endpoint to interact with JACK data streams, for audio, midi, 35 /// etc... 36 /// 37 /// The `Port` struct contains mostly metadata and exposes data as raw 38 /// pointers. For a better data 39 /// consumption/production API, see the `AudioInPort`, `AudioOutPort`, 40 /// `MidiInPort`, and 41 /// `MidiOutPort`. 42 /// 43 /// Most JACK functionality is exposed, including the raw pointers, but it 44 /// should be possible to 45 /// create a client without the need for calling `unsafe` `Port` methods. 46 pub struct Port<PS: PortSpec> { 47 spec: PS, 48 client_ptr: *mut j::jack_client_t, 49 port_ptr: *mut j::jack_port_t, 50 } 51 52 unsafe impl<PS: PortSpec> Send for Port<PS> {} 53 unsafe impl<PS: PortSpec> Sync for Port<PS> {} 54 55 impl<PS: PortSpec> Port<PS> { 56 /// Returns the spec that was used to create this port. spec(&self) -> &PS57 pub fn spec(&self) -> &PS { 58 &self.spec 59 } 60 61 /// Return a copy of port as an unowned port that can still be used for 62 /// querying information. clone_unowned(&self) -> Port<Unowned>63 pub fn clone_unowned(&self) -> Port<Unowned> { 64 Port { 65 spec: Unowned, 66 client_ptr: self.client_ptr(), 67 port_ptr: self.as_ptr(), 68 } 69 } 70 71 /// Returns the full name of the port, including the "client_name:" prefix. name<'a>(&'a self) -> &'a str72 pub fn name<'a>(&'a self) -> &'a str { 73 unsafe { 74 ffi::CStr::from_ptr(j::jack_port_name(self.as_ptr())) 75 .to_str() 76 .unwrap() 77 } 78 } 79 80 /// Returns the short name of the port, it excludes the "client_name:" 81 /// prefix. short_name<'a>(&'a self) -> &'a str82 pub fn short_name<'a>(&'a self) -> &'a str { 83 unsafe { 84 ffi::CStr::from_ptr(j::jack_port_short_name(self.as_ptr())) 85 .to_str() 86 .unwrap() 87 } 88 } 89 90 /// The flags for the port. These are set when the port is registered with 91 /// its client. flags(&self) -> PortFlags92 pub fn flags(&self) -> PortFlags { 93 let bits = unsafe { j::jack_port_flags(self.as_ptr()) }; 94 PortFlags::from_bits(bits as j::Enum_JackPortFlags).unwrap() 95 } 96 97 /// The port type. JACK's built in types include `"32 bit float mono 98 /// audio`" and `"8 bit raw 99 /// midi"`. Custom types may also be used. port_type<'a>(&self) -> &'a str100 pub fn port_type<'a>(&self) -> &'a str { 101 unsafe { 102 ffi::CStr::from_ptr(j::jack_port_type(self.as_ptr())) 103 .to_str() 104 .unwrap() 105 } 106 } 107 108 /// Number of ports connected to/from `&self`. connected_count(&self) -> usize109 pub fn connected_count(&self) -> usize { 110 let n = unsafe { j::jack_port_connected(self.as_ptr()) }; 111 n as usize 112 } 113 114 /// Returns `true` if the port is directly connected to a port with the 115 /// name `port_name`. is_connected_to(&self, port_name: &str) -> bool116 pub fn is_connected_to(&self, port_name: &str) -> bool { 117 let res = unsafe { 118 let port_name = ffi::CString::new(port_name).unwrap(); 119 j::jack_port_connected_to(self.as_ptr(), port_name.as_ptr()) 120 }; 121 match res { 122 0 => false, 123 _ => true, 124 } 125 } 126 127 /// Remove connections to/from port `self`. disconnect(&self) -> Result<(), JackErr>128 pub fn disconnect(&self) -> Result<(), JackErr> { 129 let res = unsafe { j::jack_port_disconnect(self.client_ptr(), self.as_ptr()) }; 130 match res { 131 0 => Ok(()), 132 _ => Err(JackErr::PortDisconnectionError), 133 } 134 } 135 136 /// Get the alias names for `self`. 137 /// 138 /// Will return up to 2 strings. aliases(&self) -> Vec<String>139 pub fn aliases(&self) -> Vec<String> { 140 let mut a: Vec<libc::c_char> = iter::repeat(0).take(*PORT_NAME_SIZE + 1).collect(); 141 let mut b = a.clone(); 142 unsafe { 143 let mut ptrs: [*mut libc::c_char; 2] = [a.as_mut_ptr(), b.as_mut_ptr()]; 144 j::jack_port_get_aliases(self.as_ptr(), ptrs.as_mut_ptr()); 145 }; 146 [a, b] 147 .iter() 148 .map(|p| p.as_ptr()) 149 .map(|p| unsafe { 150 ffi::CStr::from_ptr(p).to_string_lossy().into_owned() 151 }) 152 .filter(|s| s.len() > 0) 153 .collect() 154 } 155 156 /// Returns `true` if monitoring has been requested for `self`. is_monitoring_input(&self) -> bool157 pub fn is_monitoring_input(&self) -> bool { 158 match unsafe { j::jack_port_monitoring_input(self.as_ptr()) } { 159 0 => false, 160 _ => true, 161 } 162 } 163 164 /// Turn input monitoring for the port on or off. 165 /// 166 /// This only works if the port has the `CAN_MONITOR` flag set. request_monitor(&self, enable_monitor: bool) -> Result<(), JackErr>167 pub fn request_monitor(&self, enable_monitor: bool) -> Result<(), JackErr> { 168 let onoff = match enable_monitor { 169 true => 1, 170 false => 0, 171 }; 172 let res = unsafe { j::jack_port_request_monitor(self.as_ptr(), onoff) }; 173 match res { 174 0 => Ok(()), 175 _ => Err(JackErr::PortMonitorError), 176 } 177 } 178 179 /// If the `CAN_MONITOR` flag is set for the port, then input monitoring is 180 /// turned on if it was 181 /// off, and turns it off if only one request has been made to turn it on. 182 /// Otherwise it does 183 /// nothing. ensure_monitor(&self, enable_monitor: bool) -> Result<(), JackErr>184 pub fn ensure_monitor(&self, enable_monitor: bool) -> Result<(), JackErr> { 185 let onoff = match enable_monitor { 186 true => 1, 187 false => 0, 188 }; 189 let res = unsafe { j::jack_port_ensure_monitor(self.as_ptr(), onoff) }; 190 match res { 191 0 => Ok(()), 192 _ => Err(JackErr::PortMonitorError), 193 } 194 } 195 196 /// Set's the short name of the port. If the full name is longer than 197 /// `PORT_NAME_SIZE`, then it 198 /// will be truncated. set_name(&mut self, short_name: &str) -> Result<(), JackErr>199 pub fn set_name(&mut self, short_name: &str) -> Result<(), JackErr> { 200 let short_name = ffi::CString::new(short_name).unwrap(); 201 let res = unsafe { j::jack_port_set_name(self.as_ptr(), short_name.as_ptr()) }; 202 match res { 203 0 => Ok(()), 204 _ => Err(JackErr::PortNamingError), 205 } 206 } 207 208 /// Sets `alias` as an alias for `self`. 209 /// 210 /// May be called at any time. If the alias is longer than 211 /// `PORT_NAME_SIZE`, it will be 212 /// truncated. 213 /// 214 /// After a successful call, and until JACK exists, or the alias is unset, 215 /// `alias` may be used 216 /// as an alternate name for the port. 217 /// 218 /// Ports can have up to two aliases - if both are already set, this 219 /// function will return an 220 /// error. set_alias(&mut self, alias: &str) -> Result<(), JackErr>221 pub fn set_alias(&mut self, alias: &str) -> Result<(), JackErr> { 222 let alias = ffi::CString::new(alias).unwrap(); 223 let res = unsafe { j::jack_port_set_alias(self.as_ptr(), alias.as_ptr()) }; 224 match res { 225 0 => Ok(()), 226 _ => Err(JackErr::PortAliasError), 227 } 228 } 229 230 /// Remove `alias` as an alias for port. May be called at any time. 231 /// 232 /// After a successful call, `alias` can no longer be used as an alternate 233 /// name for `self`. unset_alias(&mut self, alias: &str) -> Result<(), JackErr>234 pub fn unset_alias(&mut self, alias: &str) -> Result<(), JackErr> { 235 let alias = ffi::CString::new(alias).unwrap(); 236 let res = unsafe { j::jack_port_unset_alias(self.as_ptr(), alias.as_ptr()) }; 237 match res { 238 0 => Ok(()), 239 _ => Err(JackErr::PortAliasError), 240 } 241 } 242 243 /// Remove the port from the client, disconnecting any existing 244 /// connections. The port must have 245 /// been created with the provided client. unregister(self) -> Result<(), JackErr>246 pub fn unregister(self) -> Result<(), JackErr> { 247 let res = unsafe { j::jack_port_unregister(self.client_ptr, self.as_ptr()) }; 248 match res { 249 0 => Ok(()), 250 _ => Err(JackErr::PortDisconnectionError), 251 } 252 } 253 254 /// Create a Port from raw JACK pointers. 255 /// 256 /// This is mostly for use within the jack crate itself. from_raw( spec: PS, client_ptr: *mut j::jack_client_t, port_ptr: *mut j::jack_port_t, ) -> Self257 pub unsafe fn from_raw( 258 spec: PS, 259 client_ptr: *mut j::jack_client_t, 260 port_ptr: *mut j::jack_port_t, 261 ) -> Self { 262 Port { 263 spec: spec, 264 port_ptr: port_ptr, 265 client_ptr: client_ptr, 266 } 267 } 268 269 /// Obtain the client pointer that spawned this port. 270 /// 271 /// This is mostly for use within the jack crate itself. 272 #[inline(always)] client_ptr(&self) -> *mut j::jack_client_t273 pub fn client_ptr(&self) -> *mut j::jack_client_t { 274 self.client_ptr 275 } 276 277 /// Obtain the ffi port pointer. 278 /// 279 /// This is mostly for use within the jack crate itself. 280 #[inline(always)] as_ptr(&self) -> *mut j::jack_port_t281 pub fn as_ptr(&self) -> *mut j::jack_port_t { 282 self.port_ptr 283 } 284 285 /// Obtain the buffer that the Port is holding. For standard audio and midi 286 /// ports, consider 287 /// using the `AudioInPort`, `AudioOutPort`, `MidiInPort`, or `MidiOutPort` 288 /// adapter. For more 289 /// custom data, consider implementing your own adapter that safely uses 290 /// the `Port::buffer` 291 /// method. 292 #[inline(always)] buffer(&self, n_frames: pt::JackFrames) -> *mut libc::c_void293 pub unsafe fn buffer(&self, n_frames: pt::JackFrames) -> *mut libc::c_void { 294 j::jack_port_get_buffer(self.port_ptr, n_frames) 295 } 296 } 297 298 /// `PortSpec` for a port that holds has no readable or writeable data from 299 /// JACK on the created 300 /// client. It can be used for obtaining information about external ports. 301 #[derive(Debug, Default)] 302 pub struct Unowned; 303 304 /// `Port<UnownedSpec>` - Port that holds no data from Jack, though it can 305 /// still be used to query 306 /// information. 307 pub type UnownedPort = Port<Unowned>; 308 309 unsafe impl PortSpec for Unowned { 310 /// Panics on call since the `Unowned` spec can't be used to create ports. jack_port_type(&self) -> &str311 fn jack_port_type(&self) -> &str { 312 "" 313 } 314 315 /// Panics on call since the `Unowned` spec can't be used to create ports. jack_flags(&self) -> PortFlags316 fn jack_flags(&self) -> PortFlags { 317 PortFlags::empty() 318 } 319 320 /// Panics on call since the `Unowned` spec can't be used to create ports. jack_buffer_size(&self) -> libc::c_ulong321 fn jack_buffer_size(&self) -> libc::c_ulong { 322 unreachable!() 323 } 324 } 325 326 #[derive(Debug)] 327 struct PortInfo { 328 name: String, 329 connections: usize, 330 port_type: String, 331 port_flags: PortFlags, 332 aliases: Vec<String>, 333 } 334 335 impl PortInfo { new<PS: PortSpec>(p: &Port<PS>) -> PortInfo336 fn new<PS: PortSpec>(p: &Port<PS>) -> PortInfo { 337 let s = p.spec(); 338 PortInfo { 339 name: p.name().into(), 340 connections: p.connected_count(), 341 port_type: s.jack_port_type().to_string(), 342 port_flags: s.jack_flags(), 343 aliases: p.aliases(), 344 } 345 } 346 } 347 348 impl<PS: PortSpec> fmt::Debug for Port<PS> { fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>349 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { 350 write!(f, "{:?}", PortInfo::new(self)) 351 } 352 } 353