From f1249616466fe7779d32548e1dddbed74a2c279f Mon Sep 17 00:00:00 2001 From: Will Medrano Date: Wed, 28 Oct 2026 19:57:07 -0700 Subject: [PATCH] Fix issues found in the 1.0 audit - Clear every registered callback on deactivate to prevent use-after-free - Free RingBuffer when both reader and writer are dropped - Handle NULL and non-UTF-8 keys in property change callbacks - Return an error instead of panicking when a required JACK symbol is missing - Declare variadic JACK functions as variadic in jack-sys - Resolve optional JACK functions at runtime when statically linking - Skip pkg-config when dynamic_loading is enabled and fix jack-sys default features - Stop taking the client creation lock in connect_ports - Reject NaN and infinite values in TransportBBT validation - Export CodeOrMessage and contrib::ProcessCallbacks - Remove deprecated APIs, make set_bbt_offset infallible, and document from_raw safety - Fix incorrect documentation, resolve doc TODOs, and implement Client::set_freewheel - Mark Error and TransportState non_exhaustive, drop unused error variants, and fix typos - Derive common traits for ClientOptions and drop options that need variadic arguments - Make NotificationHandler::shutdown a safe method - Register the port rename callback and rename ports with jack_port_rename - Accept both errno sign conventions from jack_midi_event_write - Document that connected audio input and output buffers may alias - Return errors instead of panicking on invalid strings and unexpected JACK values - Stop calling handlers after Quit or panic, and keep slow-sync clients running when sync returns false - Share CallbackContext across JACK threads instead of aliasing &mut - Check callback registration results and close the client when activation fails - Make tests independent of a shared client and of server timing - Defer pthread cancellation inside JACK callbacks so PipeWire cannot abort the process - Keep the client open for the duration of Port and Transport calls --- CHANGELOG.md | 6 + Cargo.toml | 2 +- build.rs | 7 - examples/playback_capture.rs | 2 +- jack-sys/Cargo.toml | 2 +- jack-sys/build.rs | 14 +- jack-sys/src/functions/dynamic_linking.rs | 127 +- jack-sys/src/functions/dynamic_loading.rs | 4742 +++++++++++---------- jack-sys/src/lib.rs | 16 +- src/client/async_client.rs | 51 +- src/client/callbacks.rs | 449 +- src/client/client_impl.rs | 195 +- src/client/client_options.rs | 20 +- src/client/client_status.rs | 5 +- src/client/common.rs | 57 +- src/client/handler_impls.rs | 5 - src/client/mod.rs | 5 +- src/contrib/closure.rs | 18 + src/jack_enums.rs | 50 +- src/jack_utils.rs | 75 + src/lib.rs | 33 +- src/logging.rs | 9 + src/port/audio.rs | 30 +- src/port/midi.rs | 48 +- src/port/port_flags.rs | 4 +- src/port/port_impl.rs | 113 +- src/properties.rs | 117 +- src/ringbuffer.rs | 83 +- src/tests/client.rs | 110 +- src/tests/invalid_input.rs | 77 + src/tests/mod.rs | 37 +- src/tests/port.rs | 56 + src/tests/processing.rs | 159 + src/tests/ringbuffer.rs | 49 + src/tests/time.rs | 53 +- src/tests/transport.rs | 70 +- src/transport.rs | 54 +- 37 files changed, 4142 insertions(+), 2808 deletions(-) delete mode 100644 build.rs create mode 100644 src/tests/invalid_input.rs create mode 100644 src/tests/port.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index e53fb6a7b..91ba92c25 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,12 @@ non-UTF-8 keys, values or types. Invalid bytes are replaced with `U+FFFD`. - Actually stop processing if buffer size callback returns Quit. This was not respected in Pipewire. +- `Port` and `Transport` methods no longer call into a client that is being closed on another + thread. Dropping a `Client` now waits for in-flight `Port` and `Transport` calls to finish. +- `Port::flags`, `get_latency_range`, `set_latency_range`, `get_connections` and + `get_connected_client_uuids` now return a `Result`, with `Err(Error::ClientIsNoLongerAlive)` + once the client has been closed, instead of reading freed memory. +- `Port::from_raw` is no longer public. ## 0.9.0 diff --git a/Cargo.toml b/Cargo.toml index 3f1fbf83e..e7e651074 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ version = "0.13.5" [dependencies] bitflags = "2" -jack-sys = {version = "0.5", path = "./jack-sys"} +jack-sys = {version = "0.5", path = "./jack-sys", default-features = false} lazy_static = "1.4" libc = "0.2" log = { version = "0.4", optional = true} diff --git a/build.rs b/build.rs deleted file mode 100644 index 57dae5aec..000000000 --- a/build.rs +++ /dev/null @@ -1,7 +0,0 @@ -fn main() { - println!("cargo:rerun-if-env-changed=RUST_JACK_DLOPEN"); - let dlopen = std::env::var("RUST_JACK_DLOPEN").is_ok(); - if dlopen { - println!("cargo:rustc-cfg=feature=\"dlopen\""); - } -} diff --git a/examples/playback_capture.rs b/examples/playback_capture.rs index a15f7aaf0..08e22d7f6 100644 --- a/examples/playback_capture.rs +++ b/examples/playback_capture.rs @@ -54,7 +54,7 @@ impl jack::NotificationHandler for Notifications { } /// Not much we can do here, see https://man7.org/linux/man-pages/man7/signal-safety.7.html. - unsafe fn shutdown(&mut self, _: jack::ClientStatus, _: &str) {} + fn shutdown(&mut self, _: jack::ClientStatus, _: &str) {} fn freewheel(&mut self, _: &jack::Client, is_enabled: bool) { println!( diff --git a/jack-sys/Cargo.toml b/jack-sys/Cargo.toml index 2bcee51d3..79f6d8bc4 100644 --- a/jack-sys/Cargo.toml +++ b/jack-sys/Cargo.toml @@ -19,5 +19,5 @@ bitflags = "2" pkg-config = "0.3" [features] -default_features = ["dynamic_loading"] +default = ["dynamic_loading"] dynamic_loading = [] diff --git a/jack-sys/build.rs b/jack-sys/build.rs index e66c38602..4fa36e303 100644 --- a/jack-sys/build.rs +++ b/jack-sys/build.rs @@ -1,7 +1,19 @@ fn main() { + // With `dynamic_loading`, libjack is opened at runtime with `dlopen`, so it is neither needed + // nor linked at build time. + if std::env::var_os("CARGO_FEATURE_DYNAMIC_LOADING").is_some() { + return; + } let target_os = std::env::var("CARGO_CFG_TARGET_OS"); let library_found = pkg_config::find_library("jack"); if target_os.as_ref().map(|s| s.as_str()) == Ok("linux") { - library_found.unwrap(); + if let Err(err) = library_found { + panic!( + "Could not find the JACK library with pkg-config. Install the JACK development \ + package (for example libjack-jackd2-dev or pipewire-jack), or enable the \ + `dynamic_loading` feature to load JACK at runtime instead.\n{}", + err + ); + } } } diff --git a/jack-sys/src/functions/dynamic_linking.rs b/jack-sys/src/functions/dynamic_linking.rs index 61fe13f59..a907f24b8 100644 --- a/jack-sys/src/functions/dynamic_linking.rs +++ b/jack-sys/src/functions/dynamic_linking.rs @@ -1,12 +1,61 @@ use crate::types::*; + +/// Resolve an optional JACK function at runtime. +/// +/// Some JACK functions are missing from older or alternative JACK implementations, so they can't +/// be linked directly without breaking the build there. Since libjack is already linked into the +/// process, look them up with `dlsym(RTLD_DEFAULT)` instead. The result is cached in `cache`, so +/// only the first call does the lookup; later calls are lock-free and realtime safe. +/// +/// # Safety +/// `F` must be the correct function pointer type for `name`, which must be NUL terminated. +#[cfg(unix)] +unsafe fn optional_function( + cache: &'static std::sync::OnceLock, + name: &'static [u8], +) -> Option { + debug_assert_eq!(name.last(), Some(&0)); + debug_assert_eq!(std::mem::size_of::(), std::mem::size_of::()); + let addr = + *cache.get_or_init(|| libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr().cast()) as usize); + if addr == 0 { + None + } else { + Some(std::mem::transmute_copy::(&addr)) + } +} + +#[cfg(not(unix))] +unsafe fn optional_function( + _cache: &'static std::sync::OnceLock, + _name: &'static [u8], +) -> Option { + None +} + pub unsafe fn jack_get_cycle_times( - _client: *const jack_client_t, - _current_frames: *mut jack_nframes_t, - _current_usecs: *mut jack_time_t, - _next_usecs: *mut jack_time_t, - _period_usecs: *mut ::libc::c_float, + client: *const jack_client_t, + current_frames: *mut jack_nframes_t, + current_usecs: *mut jack_time_t, + next_usecs: *mut jack_time_t, + period_usecs: *mut ::libc::c_float, ) -> Option<::libc::c_int> { - None + static CACHE: std::sync::OnceLock = std::sync::OnceLock::new(); + type F = unsafe extern "C" fn( + *const jack_client_t, + *mut jack_nframes_t, + *mut jack_time_t, + *mut jack_time_t, + *mut ::libc::c_float, + ) -> ::libc::c_int; + let f: F = optional_function(&CACHE, b"jack_get_cycle_times\0")?; + Some(f( + client, + current_frames, + current_usecs, + next_usecs, + period_usecs, + )) } pub unsafe fn jack_internal_client_new( _client_name: *const ::libc::c_char, @@ -239,21 +288,42 @@ pub unsafe fn jack_internal_client_handle( ) -> Option { None } +/// `jack_internal_client_load` is variadic in C. This wrapper always passes both `load_name` and +/// `load_init`, so `options` should contain `JackLoadName | JackLoadInit`. pub unsafe fn jack_internal_client_load( - _client: *mut jack_client_t, - _client_name: *const ::libc::c_char, - _options: jack_options_t, - _status: *mut jack_status_t, - _load_name: *const ::libc::c_char, - _load_init: *const ::libc::c_char, + client: *mut jack_client_t, + client_name: *const ::libc::c_char, + options: jack_options_t, + status: *mut jack_status_t, + load_name: *const ::libc::c_char, + load_init: *const ::libc::c_char, ) -> Option { - None + static CACHE: std::sync::OnceLock = std::sync::OnceLock::new(); + type F = unsafe extern "C" fn( + *mut jack_client_t, + *const ::libc::c_char, + jack_options_t, + *mut jack_status_t, + ... + ) -> jack_intclient_t; + let f: F = optional_function(&CACHE, b"jack_internal_client_load\0")?; + Some(f( + client, + client_name, + options, + status, + load_name, + load_init, + )) } pub unsafe fn jack_internal_client_unload( - _client: *mut jack_client_t, - _intclient: jack_intclient_t, + client: *mut jack_client_t, + intclient: jack_intclient_t, ) -> Option { - None + static CACHE: std::sync::OnceLock = std::sync::OnceLock::new(); + type F = unsafe extern "C" fn(*mut jack_client_t, jack_intclient_t) -> jack_status_t; + let f: F = optional_function(&CACHE, b"jack_internal_client_unload\0")?; + Some(f(client, intclient)) } #[link(name = "jack")] extern "C" { @@ -294,10 +364,13 @@ extern "C" { client: *mut jack_client_t, tinfo: *mut jack_transport_info_t, ) -> (); + /// Variadic: the optional arguments selected by `options` (such as the server name for + /// `JackServerName`) follow `status`. pub fn jack_client_open( client_name: *const ::libc::c_char, options: jack_options_t, status: *mut jack_status_t, + ... ) -> *mut jack_client_t; pub fn jack_client_new(client_name: *const ::libc::c_char) -> *mut jack_client_t; pub fn jack_client_close(client: *mut jack_client_t) -> ::libc::c_int; @@ -441,6 +514,12 @@ extern "C" { port: *mut jack_port_t, port_name: *const ::libc::c_char, ) -> ::libc::c_int; + #[link_name = "jack_port_rename"] + fn jack_port_rename_impl( + client: *mut jack_client_t, + port: *mut jack_port_t, + port_name: *const ::libc::c_char, + ) -> ::libc::c_int; pub fn jack_port_set_alias( port: *mut jack_port_t, alias: *const ::libc::c_char, @@ -659,3 +738,19 @@ extern "C" { pub fn jack_uuid_unparse(arg1: jack_uuid_t, buf: *mut ::std::os::raw::c_char) -> (); pub fn jack_uuid_empty(arg1: jack_uuid_t) -> ::std::os::raw::c_int; } + +/// Load the JACK library and all of its required functions. +/// +/// With static linking, the library is loaded by the system linker, so this always succeeds. +pub fn ensure_loaded() -> Result<(), &'static str> { + Ok(()) +} + +/// Rename `port`. Unlike `jack_port_set_name`, this notifies port rename callbacks. +pub unsafe fn jack_port_rename( + client: *mut jack_client_t, + port: *mut jack_port_t, + port_name: *const ::libc::c_char, +) -> Option<::libc::c_int> { + Some(jack_port_rename_impl(client, port, port_name)) +} diff --git a/jack-sys/src/functions/dynamic_loading.rs b/jack-sys/src/functions/dynamic_loading.rs index 3a266ab98..fdbc3dda3 100644 --- a/jack-sys/src/functions/dynamic_loading.rs +++ b/jack-sys/src/functions/dynamic_loading.rs @@ -43,6 +43,7 @@ pub struct JackFunctions { *const ::libc::c_char, jack_options_t, *mut jack_status_t, + ... ) -> *mut jack_client_t, jack_client_new_impl: unsafe extern "C" fn(*const ::libc::c_char) -> *mut jack_client_t, jack_client_close_impl: unsafe extern "C" fn(*mut jack_client_t) -> ::libc::c_int, @@ -180,6 +181,13 @@ pub struct JackFunctions { jack_port_untie_impl: unsafe extern "C" fn(*mut jack_port_t) -> ::libc::c_int, jack_port_set_name_impl: unsafe extern "C" fn(*mut jack_port_t, *const ::libc::c_char) -> ::libc::c_int, + jack_port_rename_impl: Option< + unsafe extern "C" fn( + *mut jack_client_t, + *mut jack_port_t, + *const ::libc::c_char, + ) -> ::libc::c_int, + >, jack_port_set_alias_impl: unsafe extern "C" fn(*mut jack_port_t, *const ::libc::c_char) -> ::libc::c_int, jack_port_unset_alias_impl: @@ -416,8 +424,7 @@ pub struct JackFunctions { *const ::libc::c_char, jack_options_t, *mut jack_status_t, - *const ::libc::c_char, - *const ::libc::c_char, + ... ) -> jack_intclient_t, >, jack_internal_client_unload_impl: @@ -486,2339 +493,2358 @@ pub struct JackFunctions { } lazy_static! { - static ref FUNCTIONS: JackFunctions = unsafe { - let library = crate::library().unwrap(); - let jack_release_timebase_impl = library - .get:: ::libc::c_int>( - b"jack_release_timebase", - ) - .unwrap(); - let jack_release_timebase_impl = jack_release_timebase_impl.into_raw(); - let jack_release_timebase_impl = *jack_release_timebase_impl.deref() - as unsafe extern "C" fn(client: *mut jack_client_t) -> ::libc::c_int; - let jack_get_cycle_times_impl = library - .get:: = match crate::library() { + Ok(library) => unsafe { load_functions(library) }, + Err(err) => Err(err.to_string()), + }; +} + +/// Load every JACK function from `library`. +/// +/// Returns an error describing the first required symbol that is missing. Optional symbols, such +/// as those only present in some JACK versions, are loaded as `None` instead. +unsafe fn load_functions(library: &libloading::Library) -> Result { + use std::ops::Deref; + let jack_release_timebase_impl = library + .get:: ::libc::c_int>( + b"jack_release_timebase", + ) + .map_err(|err| err.to_string())?; + let jack_release_timebase_impl = jack_release_timebase_impl.into_raw(); + let jack_release_timebase_impl = *jack_release_timebase_impl.deref() + as unsafe extern "C" fn(client: *mut jack_client_t) -> ::libc::c_int; + let jack_get_cycle_times_impl = library + .get:: ::libc::c_int>(b"jack_get_cycle_times") + .ok(); + let jack_get_cycle_times_impl = jack_get_cycle_times_impl.map(|sym| sym.into_raw()); + let jack_get_cycle_times_impl = jack_get_cycle_times_impl.map(|sym| { + *sym.deref() + as unsafe extern "C" fn( client: *const jack_client_t, current_frames: *mut jack_nframes_t, current_usecs: *mut jack_time_t, next_usecs: *mut jack_time_t, period_usecs: *mut ::libc::c_float, - ) -> ::libc::c_int>(b"jack_get_cycle_times") - .ok(); - let jack_get_cycle_times_impl = jack_get_cycle_times_impl.map(|sym| sym.into_raw()); - let jack_get_cycle_times_impl = jack_get_cycle_times_impl.map(|sym| { - *sym.deref() - as unsafe extern "C" fn( - client: *const jack_client_t, - current_frames: *mut jack_nframes_t, - current_usecs: *mut jack_time_t, - next_usecs: *mut jack_time_t, - period_usecs: *mut ::libc::c_float, - ) -> ::libc::c_int - }); - let jack_set_sync_callback_impl = library - .get:: ::libc::c_int>(b"jack_set_sync_callback") - .unwrap(); - let jack_set_sync_callback_impl = jack_set_sync_callback_impl.into_raw(); - let jack_set_sync_callback_impl = *jack_set_sync_callback_impl.deref() - as unsafe extern "C" fn( - client: *mut jack_client_t, - sync_callback: JackSyncCallback, - sync_arg: *mut ::libc::c_void, - ) -> ::libc::c_int; - let jack_set_sync_timeout_impl = + ) -> ::libc::c_int + }); + let jack_set_sync_callback_impl = library + .get:: ::libc::c_int>(b"jack_set_sync_callback") + .map_err(|err| err.to_string())?; + let jack_set_sync_callback_impl = jack_set_sync_callback_impl.into_raw(); + let jack_set_sync_callback_impl = *jack_set_sync_callback_impl.deref() + as unsafe extern "C" fn( + client: *mut jack_client_t, + sync_callback: JackSyncCallback, + sync_arg: *mut ::libc::c_void, + ) -> ::libc::c_int; + let jack_set_sync_timeout_impl = library .get:: ::libc::c_int>(b"jack_set_sync_timeout") - .unwrap(); - let jack_set_sync_timeout_impl = jack_set_sync_timeout_impl.into_raw(); - let jack_set_sync_timeout_impl = *jack_set_sync_timeout_impl.deref() - as unsafe extern "C" fn( - client: *mut jack_client_t, - timeout: jack_time_t, - ) -> ::libc::c_int; - let jack_set_timebase_callback_impl = library - .get:: ::libc::c_int>(b"jack_set_timebase_callback") - .unwrap(); - let jack_set_timebase_callback_impl = jack_set_timebase_callback_impl.into_raw(); - let jack_set_timebase_callback_impl = *jack_set_timebase_callback_impl.deref() - as unsafe extern "C" fn( - client: *mut jack_client_t, - conditional: ::libc::c_int, - timebase_callback: TimebaseCallback, - arg: *mut ::libc::c_void, - ) -> ::libc::c_int; - let jack_transport_locate_impl = + .map_err(|err| err.to_string())?; + let jack_set_sync_timeout_impl = jack_set_sync_timeout_impl.into_raw(); + let jack_set_sync_timeout_impl = *jack_set_sync_timeout_impl.deref() + as unsafe extern "C" fn(client: *mut jack_client_t, timeout: jack_time_t) -> ::libc::c_int; + let jack_set_timebase_callback_impl = library + .get:: ::libc::c_int>(b"jack_set_timebase_callback") + .map_err(|err| err.to_string())?; + let jack_set_timebase_callback_impl = jack_set_timebase_callback_impl.into_raw(); + let jack_set_timebase_callback_impl = *jack_set_timebase_callback_impl.deref() + as unsafe extern "C" fn( + client: *mut jack_client_t, + conditional: ::libc::c_int, + timebase_callback: TimebaseCallback, + arg: *mut ::libc::c_void, + ) -> ::libc::c_int; + let jack_transport_locate_impl = library .get:: ::libc::c_int>(b"jack_transport_locate") - .unwrap(); - let jack_transport_locate_impl = jack_transport_locate_impl.into_raw(); - let jack_transport_locate_impl = *jack_transport_locate_impl.deref() - as unsafe extern "C" fn( - client: *mut jack_client_t, - frame: jack_nframes_t, - ) -> ::libc::c_int; - let jack_transport_query_impl = library - .get:: jack_transport_state_t>(b"jack_transport_query") - .unwrap(); - let jack_transport_query_impl = jack_transport_query_impl.into_raw(); - let jack_transport_query_impl = *jack_transport_query_impl.deref() - as unsafe extern "C" fn( - client: *const jack_client_t, - pos: *mut jack_position_t, - ) -> jack_transport_state_t; - let jack_get_current_transport_frame_impl = library - .get:: jack_nframes_t>( - b"jack_get_current_transport_frame", - ) - .unwrap(); - let jack_get_current_transport_frame_impl = - jack_get_current_transport_frame_impl.into_raw(); - let jack_get_current_transport_frame_impl = *jack_get_current_transport_frame_impl.deref() - as unsafe extern "C" fn(client: *const jack_client_t) -> jack_nframes_t; - let jack_transport_reposition_impl = library - .get:: ::libc::c_int>(b"jack_transport_reposition") - .unwrap(); - let jack_transport_reposition_impl = jack_transport_reposition_impl.into_raw(); - let jack_transport_reposition_impl = *jack_transport_reposition_impl.deref() - as unsafe extern "C" fn( - client: *mut jack_client_t, - pos: *const jack_position_t, - ) -> ::libc::c_int; - let jack_transport_start_impl = library - .get:: ()>(b"jack_transport_start") - .unwrap(); - let jack_transport_start_impl = jack_transport_start_impl.into_raw(); - let jack_transport_start_impl = *jack_transport_start_impl.deref() - as unsafe extern "C" fn(client: *mut jack_client_t) -> (); - let jack_transport_stop_impl = library - .get:: ()>(b"jack_transport_stop") - .unwrap(); - let jack_transport_stop_impl = jack_transport_stop_impl.into_raw(); - let jack_transport_stop_impl = *jack_transport_stop_impl.deref() - as unsafe extern "C" fn(client: *mut jack_client_t) -> (); - let jack_get_transport_info_impl = library + .map_err(|err| err.to_string())?; + let jack_transport_locate_impl = jack_transport_locate_impl.into_raw(); + let jack_transport_locate_impl = *jack_transport_locate_impl.deref() + as unsafe extern "C" fn(client: *mut jack_client_t, frame: jack_nframes_t) -> ::libc::c_int; + let jack_transport_query_impl = library + .get:: jack_transport_state_t>(b"jack_transport_query") + .map_err(|err| err.to_string())?; + let jack_transport_query_impl = jack_transport_query_impl.into_raw(); + let jack_transport_query_impl = *jack_transport_query_impl.deref() + as unsafe extern "C" fn( + client: *const jack_client_t, + pos: *mut jack_position_t, + ) -> jack_transport_state_t; + let jack_get_current_transport_frame_impl = library + .get:: jack_nframes_t>( + b"jack_get_current_transport_frame", + ) + .map_err(|err| err.to_string())?; + let jack_get_current_transport_frame_impl = jack_get_current_transport_frame_impl.into_raw(); + let jack_get_current_transport_frame_impl = *jack_get_current_transport_frame_impl.deref() + as unsafe extern "C" fn(client: *const jack_client_t) -> jack_nframes_t; + let jack_transport_reposition_impl = library + .get:: ::libc::c_int>(b"jack_transport_reposition") + .map_err(|err| err.to_string())?; + let jack_transport_reposition_impl = jack_transport_reposition_impl.into_raw(); + let jack_transport_reposition_impl = *jack_transport_reposition_impl.deref() + as unsafe extern "C" fn( + client: *mut jack_client_t, + pos: *const jack_position_t, + ) -> ::libc::c_int; + let jack_transport_start_impl = library + .get:: ()>(b"jack_transport_start") + .map_err(|err| err.to_string())?; + let jack_transport_start_impl = jack_transport_start_impl.into_raw(); + let jack_transport_start_impl = *jack_transport_start_impl.deref() + as unsafe extern "C" fn(client: *mut jack_client_t) -> (); + let jack_transport_stop_impl = library + .get:: ()>(b"jack_transport_stop") + .map_err(|err| err.to_string())?; + let jack_transport_stop_impl = jack_transport_stop_impl.into_raw(); + let jack_transport_stop_impl = + *jack_transport_stop_impl.deref() as unsafe extern "C" fn(client: *mut jack_client_t) -> (); + let jack_get_transport_info_impl = + library .get:: ()>(b"jack_get_transport_info") - .unwrap(); - let jack_get_transport_info_impl = jack_get_transport_info_impl.into_raw(); - let jack_get_transport_info_impl = *jack_get_transport_info_impl.deref() - as unsafe extern "C" fn( - client: *mut jack_client_t, - tinfo: *mut jack_transport_info_t, - ) -> (); - let jack_set_transport_info_impl = library + .map_err(|err| err.to_string())?; + let jack_get_transport_info_impl = jack_get_transport_info_impl.into_raw(); + let jack_get_transport_info_impl = *jack_get_transport_info_impl.deref() + as unsafe extern "C" fn( + client: *mut jack_client_t, + tinfo: *mut jack_transport_info_t, + ) -> (); + let jack_set_transport_info_impl = + library .get:: ()>(b"jack_set_transport_info") - .unwrap(); - let jack_set_transport_info_impl = jack_set_transport_info_impl.into_raw(); - let jack_set_transport_info_impl = *jack_set_transport_info_impl.deref() - as unsafe extern "C" fn( - client: *mut jack_client_t, - tinfo: *mut jack_transport_info_t, - ) -> (); - let jack_client_open_impl = library - .get:: *mut jack_client_t>(b"jack_client_open") - .unwrap(); - let jack_client_open_impl = jack_client_open_impl.into_raw(); - let jack_client_open_impl = *jack_client_open_impl.deref() + .map_err(|err| err.to_string())?; + let jack_set_transport_info_impl = jack_set_transport_info_impl.into_raw(); + let jack_set_transport_info_impl = *jack_set_transport_info_impl.deref() + as unsafe extern "C" fn( + client: *mut jack_client_t, + tinfo: *mut jack_transport_info_t, + ) -> (); + let jack_client_open_impl = library + .get:: *mut jack_client_t>(b"jack_client_open") + .map_err(|err| err.to_string())?; + let jack_client_open_impl = jack_client_open_impl.into_raw(); + let jack_client_open_impl = *jack_client_open_impl.deref() + as unsafe extern "C" fn( + client_name: *const ::libc::c_char, + options: jack_options_t, + status: *mut jack_status_t, + ... + ) -> *mut jack_client_t; + let jack_client_new_impl = library + .get:: *mut jack_client_t>( + b"jack_client_new", + ) + .map_err(|err| err.to_string())?; + let jack_client_new_impl = jack_client_new_impl.into_raw(); + let jack_client_new_impl = *jack_client_new_impl.deref() + as unsafe extern "C" fn(client_name: *const ::libc::c_char) -> *mut jack_client_t; + let jack_client_close_impl = library + .get:: ::libc::c_int>( + b"jack_client_close", + ) + .map_err(|err| err.to_string())?; + let jack_client_close_impl = jack_client_close_impl.into_raw(); + let jack_client_close_impl = *jack_client_close_impl.deref() + as unsafe extern "C" fn(client: *mut jack_client_t) -> ::libc::c_int; + let jack_client_name_size_impl = library + .get:: ::libc::c_int>(b"jack_client_name_size") + .map_err(|err| err.to_string())?; + let jack_client_name_size_impl = jack_client_name_size_impl.into_raw(); + let jack_client_name_size_impl = + *jack_client_name_size_impl.deref() as unsafe extern "C" fn() -> ::libc::c_int; + let jack_get_client_name_impl = library + .get:: *mut ::libc::c_char>( + b"jack_get_client_name", + ) + .map_err(|err| err.to_string())?; + let jack_get_client_name_impl = jack_get_client_name_impl.into_raw(); + let jack_get_client_name_impl = *jack_get_client_name_impl.deref() + as unsafe extern "C" fn(client: *mut jack_client_t) -> *mut ::libc::c_char; + let jack_get_uuid_for_client_name_impl = library + .get:: *mut ::libc::c_char>(b"jack_get_uuid_for_client_name") + .map_err(|err| err.to_string())?; + let jack_get_uuid_for_client_name_impl = jack_get_uuid_for_client_name_impl.into_raw(); + let jack_get_uuid_for_client_name_impl = *jack_get_uuid_for_client_name_impl.deref() + as unsafe extern "C" fn( + client: *mut jack_client_t, + client_name: *const ::libc::c_char, + ) -> *mut ::libc::c_char; + let jack_get_client_name_by_uuid_impl = library + .get:: *mut ::libc::c_char>(b"jack_get_client_name_by_uuid") + .map_err(|err| err.to_string())?; + let jack_get_client_name_by_uuid_impl = jack_get_client_name_by_uuid_impl.into_raw(); + let jack_get_client_name_by_uuid_impl = *jack_get_client_name_by_uuid_impl.deref() + as unsafe extern "C" fn( + client: *mut jack_client_t, + client_uuid: *const ::libc::c_char, + ) -> *mut ::libc::c_char; + let jack_internal_client_new_impl = library + .get:: ::libc::c_int>(b"jack_internal_client_new") + .ok(); + let jack_internal_client_new_impl = jack_internal_client_new_impl.map(|sym| sym.into_raw()); + let jack_internal_client_new_impl = jack_internal_client_new_impl.map(|sym| { + *sym.deref() as unsafe extern "C" fn( - client_name: *const ::libc::c_char, - options: jack_options_t, - status: *mut jack_status_t, - ) -> *mut jack_client_t; - let jack_client_new_impl = library - .get:: *mut jack_client_t>( - b"jack_client_new", - ) - .unwrap(); - let jack_client_new_impl = jack_client_new_impl.into_raw(); - let jack_client_new_impl = *jack_client_new_impl.deref() - as unsafe extern "C" fn(client_name: *const ::libc::c_char) -> *mut jack_client_t; - let jack_client_close_impl = library - .get:: ::libc::c_int>( - b"jack_client_close", - ) - .unwrap(); - let jack_client_close_impl = jack_client_close_impl.into_raw(); - let jack_client_close_impl = *jack_client_close_impl.deref() - as unsafe extern "C" fn(client: *mut jack_client_t) -> ::libc::c_int; - let jack_client_name_size_impl = library - .get:: ::libc::c_int>(b"jack_client_name_size") - .unwrap(); - let jack_client_name_size_impl = jack_client_name_size_impl.into_raw(); - let jack_client_name_size_impl = - *jack_client_name_size_impl.deref() as unsafe extern "C" fn() -> ::libc::c_int; - let jack_get_client_name_impl = library - .get:: *mut ::libc::c_char>( - b"jack_get_client_name", - ) - .unwrap(); - let jack_get_client_name_impl = jack_get_client_name_impl.into_raw(); - let jack_get_client_name_impl = *jack_get_client_name_impl.deref() - as unsafe extern "C" fn(client: *mut jack_client_t) -> *mut ::libc::c_char; - let jack_get_uuid_for_client_name_impl = library - .get:: *mut ::libc::c_char>(b"jack_get_uuid_for_client_name") - .unwrap(); - let jack_get_uuid_for_client_name_impl = jack_get_uuid_for_client_name_impl.into_raw(); - let jack_get_uuid_for_client_name_impl = *jack_get_uuid_for_client_name_impl.deref() - as unsafe extern "C" fn( - client: *mut jack_client_t, - client_name: *const ::libc::c_char, - ) -> *mut ::libc::c_char; - let jack_get_client_name_by_uuid_impl = library - .get:: *mut ::libc::c_char>(b"jack_get_client_name_by_uuid") - .unwrap(); - let jack_get_client_name_by_uuid_impl = jack_get_client_name_by_uuid_impl.into_raw(); - let jack_get_client_name_by_uuid_impl = *jack_get_client_name_by_uuid_impl.deref() - as unsafe extern "C" fn( - client: *mut jack_client_t, - client_uuid: *const ::libc::c_char, - ) -> *mut ::libc::c_char; - let jack_internal_client_new_impl = library - .get:: ::libc::c_int>(b"jack_internal_client_new") - .ok(); - let jack_internal_client_new_impl = jack_internal_client_new_impl.map(|sym| sym.into_raw()); - let jack_internal_client_new_impl = jack_internal_client_new_impl.map(|sym| { - *sym.deref() - as unsafe extern "C" fn( - client_name: *const ::libc::c_char, - load_name: *const ::libc::c_char, - load_init: *const ::libc::c_char, - ) -> ::libc::c_int - }); - let jack_internal_client_close_impl = library - .get:: ()>( - b"jack_internal_client_close", - ) - .ok(); - let jack_internal_client_close_impl = - jack_internal_client_close_impl.map(|sym| sym.into_raw()); - let jack_internal_client_close_impl = jack_internal_client_close_impl.map(|sym| { - *sym.deref() as unsafe extern "C" fn(client_name: *const ::libc::c_char) -> () - }); - let jack_activate_impl = library - .get:: ::libc::c_int>( - b"jack_activate", - ) - .unwrap(); - let jack_activate_impl = jack_activate_impl.into_raw(); - let jack_activate_impl = *jack_activate_impl.deref() - as unsafe extern "C" fn(client: *mut jack_client_t) -> ::libc::c_int; - let jack_deactivate_impl = library - .get:: ::libc::c_int>( - b"jack_deactivate", - ) - .unwrap(); - let jack_deactivate_impl = jack_deactivate_impl.into_raw(); - let jack_deactivate_impl = *jack_deactivate_impl.deref() - as unsafe extern "C" fn(client: *mut jack_client_t) -> ::libc::c_int; - let jack_get_client_pid_impl = library - .get:: ::libc::c_int>( - b"jack_get_client_pid", - ) - .ok(); - let jack_get_client_pid_impl = jack_get_client_pid_impl.map(|sym| sym.into_raw()); - let jack_get_client_pid_impl = jack_get_client_pid_impl.map(|sym| { - *sym.deref() as unsafe extern "C" fn(name: *const ::libc::c_char) -> ::libc::c_int - }); - let jack_is_realtime_impl = library - .get:: ::libc::c_int>( - b"jack_is_realtime", - ) - .unwrap(); - let jack_is_realtime_impl = jack_is_realtime_impl.into_raw(); - let jack_is_realtime_impl = *jack_is_realtime_impl.deref() - as unsafe extern "C" fn(client: *mut jack_client_t) -> ::libc::c_int; - let jack_thread_wait_impl = library + ) -> ::libc::c_int + }); + let jack_internal_client_close_impl = library + .get:: ()>( + b"jack_internal_client_close", + ) + .ok(); + let jack_internal_client_close_impl = jack_internal_client_close_impl.map(|sym| sym.into_raw()); + let jack_internal_client_close_impl = jack_internal_client_close_impl + .map(|sym| *sym.deref() as unsafe extern "C" fn(client_name: *const ::libc::c_char) -> ()); + let jack_activate_impl = library + .get:: ::libc::c_int>(b"jack_activate") + .map_err(|err| err.to_string())?; + let jack_activate_impl = jack_activate_impl.into_raw(); + let jack_activate_impl = *jack_activate_impl.deref() + as unsafe extern "C" fn(client: *mut jack_client_t) -> ::libc::c_int; + let jack_deactivate_impl = library + .get:: ::libc::c_int>( + b"jack_deactivate", + ) + .map_err(|err| err.to_string())?; + let jack_deactivate_impl = jack_deactivate_impl.into_raw(); + let jack_deactivate_impl = *jack_deactivate_impl.deref() + as unsafe extern "C" fn(client: *mut jack_client_t) -> ::libc::c_int; + let jack_get_client_pid_impl = library + .get:: ::libc::c_int>( + b"jack_get_client_pid", + ) + .ok(); + let jack_get_client_pid_impl = jack_get_client_pid_impl.map(|sym| sym.into_raw()); + let jack_get_client_pid_impl = jack_get_client_pid_impl.map(|sym| { + *sym.deref() as unsafe extern "C" fn(name: *const ::libc::c_char) -> ::libc::c_int + }); + let jack_is_realtime_impl = library + .get:: ::libc::c_int>( + b"jack_is_realtime", + ) + .map_err(|err| err.to_string())?; + let jack_is_realtime_impl = jack_is_realtime_impl.into_raw(); + let jack_is_realtime_impl = *jack_is_realtime_impl.deref() + as unsafe extern "C" fn(client: *mut jack_client_t) -> ::libc::c_int; + let jack_thread_wait_impl = + library .get:: jack_nframes_t>(b"jack_thread_wait") - .unwrap(); - let jack_thread_wait_impl = jack_thread_wait_impl.into_raw(); - let jack_thread_wait_impl = *jack_thread_wait_impl.deref() - as unsafe extern "C" fn( - client: *mut jack_client_t, - status: ::libc::c_int, - ) -> jack_nframes_t; - let jack_cycle_wait_impl = library - .get:: jack_nframes_t>( - b"jack_cycle_wait", - ) - .unwrap(); - let jack_cycle_wait_impl = jack_cycle_wait_impl.into_raw(); - let jack_cycle_wait_impl = *jack_cycle_wait_impl.deref() - as unsafe extern "C" fn(client: *mut jack_client_t) -> jack_nframes_t; - let jack_cycle_signal_impl = library - .get:: ()>( - b"jack_cycle_signal", - ) - .unwrap(); - let jack_cycle_signal_impl = jack_cycle_signal_impl.into_raw(); - let jack_cycle_signal_impl = *jack_cycle_signal_impl.deref() - as unsafe extern "C" fn(client: *mut jack_client_t, status: ::libc::c_int) -> (); - let jack_set_process_thread_impl = library - .get:: ::libc::c_int>(b"jack_set_process_thread") - .unwrap(); - let jack_set_process_thread_impl = jack_set_process_thread_impl.into_raw(); - let jack_set_process_thread_impl = *jack_set_process_thread_impl.deref() - as unsafe extern "C" fn( - client: *mut jack_client_t, - thread_callback: JackThreadCallback, - arg: *mut ::libc::c_void, - ) -> ::libc::c_int; - let jack_set_thread_init_callback_impl = library - .get:: ::libc::c_int>(b"jack_set_thread_init_callback") - .unwrap(); - let jack_set_thread_init_callback_impl = jack_set_thread_init_callback_impl.into_raw(); - let jack_set_thread_init_callback_impl = *jack_set_thread_init_callback_impl.deref() - as unsafe extern "C" fn( - client: *mut jack_client_t, - thread_init_callback: JackThreadInitCallback, - arg: *mut ::libc::c_void, - ) -> ::libc::c_int; - let jack_on_shutdown_impl = library - .get:: ()>(b"jack_on_shutdown") - .unwrap(); - let jack_on_shutdown_impl = jack_on_shutdown_impl.into_raw(); - let jack_on_shutdown_impl = *jack_on_shutdown_impl.deref() - as unsafe extern "C" fn( - client: *mut jack_client_t, - callback: JackShutdownCallback, - arg: *mut ::libc::c_void, - ) -> (); - let jack_on_info_shutdown_impl = library - .get:: ()>(b"jack_on_info_shutdown") - .unwrap(); - let jack_on_info_shutdown_impl = jack_on_info_shutdown_impl.into_raw(); - let jack_on_info_shutdown_impl = *jack_on_info_shutdown_impl.deref() - as unsafe extern "C" fn( - client: *mut jack_client_t, - callback: JackInfoShutdownCallback, - arg: *mut ::libc::c_void, - ) -> (); - let jack_set_process_callback_impl = library - .get:: ::libc::c_int>(b"jack_set_process_callback") - .unwrap(); - let jack_set_process_callback_impl = jack_set_process_callback_impl.into_raw(); - let jack_set_process_callback_impl = *jack_set_process_callback_impl.deref() - as unsafe extern "C" fn( - client: *mut jack_client_t, - process_callback: JackProcessCallback, - arg: *mut ::libc::c_void, - ) -> ::libc::c_int; - let jack_set_freewheel_callback_impl = library - .get:: ::libc::c_int>(b"jack_set_freewheel_callback") - .unwrap(); - let jack_set_freewheel_callback_impl = jack_set_freewheel_callback_impl.into_raw(); - let jack_set_freewheel_callback_impl = *jack_set_freewheel_callback_impl.deref() - as unsafe extern "C" fn( - client: *mut jack_client_t, - freewheel_callback: JackFreewheelCallback, - arg: *mut ::libc::c_void, - ) -> ::libc::c_int; - let jack_set_buffer_size_callback_impl = library - .get:: ::libc::c_int>(b"jack_set_buffer_size_callback") - .unwrap(); - let jack_set_buffer_size_callback_impl = jack_set_buffer_size_callback_impl.into_raw(); - let jack_set_buffer_size_callback_impl = *jack_set_buffer_size_callback_impl.deref() - as unsafe extern "C" fn( - client: *mut jack_client_t, - bufsize_callback: JackBufferSizeCallback, - arg: *mut ::libc::c_void, - ) -> ::libc::c_int; - let jack_get_sample_rate_impl = library - .get:: ::libc::c_int>( - b"jack_get_sample_rate", - ) - .unwrap(); - let jack_get_sample_rate_impl = jack_get_sample_rate_impl.into_raw(); - let jack_get_sample_rate_impl = *jack_get_sample_rate_impl.deref() - as unsafe extern "C" fn(client: *mut jack_client_t) -> ::libc::c_int; - let jack_set_sample_rate_callback_impl = library - .get:: ::libc::c_int>(b"jack_set_sample_rate_callback") - .unwrap(); - let jack_set_sample_rate_callback_impl = jack_set_sample_rate_callback_impl.into_raw(); - let jack_set_sample_rate_callback_impl = *jack_set_sample_rate_callback_impl.deref() - as unsafe extern "C" fn( - client: *mut jack_client_t, - srate_callback: JackSampleRateCallback, - arg: *mut ::libc::c_void, - ) -> ::libc::c_int; - let jack_set_client_registration_callback_impl = library - .get:: ::libc::c_int>(b"jack_set_client_registration_callback") - .unwrap(); - let jack_set_client_registration_callback_impl = - jack_set_client_registration_callback_impl.into_raw(); - let jack_set_client_registration_callback_impl = *jack_set_client_registration_callback_impl - .deref() - as unsafe extern "C" fn( - client: *mut jack_client_t, - registration_callback: JackClientRegistrationCallback, - arg: *mut ::libc::c_void, - ) -> ::libc::c_int; - let jack_set_port_registration_callback_impl = library - .get:: ::libc::c_int>(b"jack_set_port_registration_callback") - .unwrap(); - let jack_set_port_registration_callback_impl = - jack_set_port_registration_callback_impl.into_raw(); - let jack_set_port_registration_callback_impl = *jack_set_port_registration_callback_impl - .deref() - as unsafe extern "C" fn( - client: *mut jack_client_t, - registration_callback: JackPortRegistrationCallback, - arg: *mut ::libc::c_void, - ) -> ::libc::c_int; - let jack_set_port_connect_callback_impl = library - .get:: ::libc::c_int>(b"jack_set_port_connect_callback") - .unwrap(); - let jack_set_port_connect_callback_impl = jack_set_port_connect_callback_impl.into_raw(); - let jack_set_port_connect_callback_impl = *jack_set_port_connect_callback_impl.deref() - as unsafe extern "C" fn( - client: *mut jack_client_t, - connect_callback: JackPortConnectCallback, - arg: *mut ::libc::c_void, - ) -> ::libc::c_int; - let jack_set_port_rename_callback_impl = library - .get:: ::libc::c_int>(b"jack_set_port_rename_callback") - .unwrap(); - let jack_set_port_rename_callback_impl = jack_set_port_rename_callback_impl.into_raw(); - let jack_set_port_rename_callback_impl = *jack_set_port_rename_callback_impl.deref() - as unsafe extern "C" fn( - client: *mut jack_client_t, - rename_callback: JackPortRenameCallback, - arg: *mut ::libc::c_void, - ) -> ::libc::c_int; - let jack_set_graph_order_callback_impl = library - .get:: ::libc::c_int>(b"jack_set_graph_order_callback") - .unwrap(); - let jack_set_graph_order_callback_impl = jack_set_graph_order_callback_impl.into_raw(); - let jack_set_graph_order_callback_impl = *jack_set_graph_order_callback_impl.deref() - as unsafe extern "C" fn( - client: *mut jack_client_t, - graph_callback: JackGraphOrderCallback, - arg: *mut ::libc::c_void, - ) -> ::libc::c_int; - let jack_set_xrun_callback_impl = library - .get:: ::libc::c_int>(b"jack_set_xrun_callback") - .unwrap(); - let jack_set_xrun_callback_impl = jack_set_xrun_callback_impl.into_raw(); - let jack_set_xrun_callback_impl = *jack_set_xrun_callback_impl.deref() - as unsafe extern "C" fn( - client: *mut jack_client_t, - xrun_callback: JackXRunCallback, - arg: *mut ::libc::c_void, - ) -> ::libc::c_int; - let jack_set_latency_callback_impl = library - .get:: ::libc::c_int>(b"jack_set_latency_callback") - .unwrap(); - let jack_set_latency_callback_impl = jack_set_latency_callback_impl.into_raw(); - let jack_set_latency_callback_impl = *jack_set_latency_callback_impl.deref() - as unsafe extern "C" fn( - client: *mut jack_client_t, - latency_callback: JackLatencyCallback, - arg: *mut ::libc::c_void, - ) -> ::libc::c_int; - let jack_set_freewheel_impl = + .map_err(|err| err.to_string())?; + let jack_thread_wait_impl = jack_thread_wait_impl.into_raw(); + let jack_thread_wait_impl = *jack_thread_wait_impl.deref() + as unsafe extern "C" fn( + client: *mut jack_client_t, + status: ::libc::c_int, + ) -> jack_nframes_t; + let jack_cycle_wait_impl = library + .get:: jack_nframes_t>( + b"jack_cycle_wait", + ) + .map_err(|err| err.to_string())?; + let jack_cycle_wait_impl = jack_cycle_wait_impl.into_raw(); + let jack_cycle_wait_impl = *jack_cycle_wait_impl.deref() + as unsafe extern "C" fn(client: *mut jack_client_t) -> jack_nframes_t; + let jack_cycle_signal_impl = library + .get:: ()>( + b"jack_cycle_signal", + ) + .map_err(|err| err.to_string())?; + let jack_cycle_signal_impl = jack_cycle_signal_impl.into_raw(); + let jack_cycle_signal_impl = *jack_cycle_signal_impl.deref() + as unsafe extern "C" fn(client: *mut jack_client_t, status: ::libc::c_int) -> (); + let jack_set_process_thread_impl = library + .get:: ::libc::c_int>(b"jack_set_process_thread") + .map_err(|err| err.to_string())?; + let jack_set_process_thread_impl = jack_set_process_thread_impl.into_raw(); + let jack_set_process_thread_impl = *jack_set_process_thread_impl.deref() + as unsafe extern "C" fn( + client: *mut jack_client_t, + thread_callback: JackThreadCallback, + arg: *mut ::libc::c_void, + ) -> ::libc::c_int; + let jack_set_thread_init_callback_impl = library + .get:: ::libc::c_int>(b"jack_set_thread_init_callback") + .map_err(|err| err.to_string())?; + let jack_set_thread_init_callback_impl = jack_set_thread_init_callback_impl.into_raw(); + let jack_set_thread_init_callback_impl = *jack_set_thread_init_callback_impl.deref() + as unsafe extern "C" fn( + client: *mut jack_client_t, + thread_init_callback: JackThreadInitCallback, + arg: *mut ::libc::c_void, + ) -> ::libc::c_int; + let jack_on_shutdown_impl = library + .get:: ()>(b"jack_on_shutdown") + .map_err(|err| err.to_string())?; + let jack_on_shutdown_impl = jack_on_shutdown_impl.into_raw(); + let jack_on_shutdown_impl = *jack_on_shutdown_impl.deref() + as unsafe extern "C" fn( + client: *mut jack_client_t, + callback: JackShutdownCallback, + arg: *mut ::libc::c_void, + ) -> (); + let jack_on_info_shutdown_impl = library + .get:: ()>(b"jack_on_info_shutdown") + .map_err(|err| err.to_string())?; + let jack_on_info_shutdown_impl = jack_on_info_shutdown_impl.into_raw(); + let jack_on_info_shutdown_impl = *jack_on_info_shutdown_impl.deref() + as unsafe extern "C" fn( + client: *mut jack_client_t, + callback: JackInfoShutdownCallback, + arg: *mut ::libc::c_void, + ) -> (); + let jack_set_process_callback_impl = library + .get:: ::libc::c_int>(b"jack_set_process_callback") + .map_err(|err| err.to_string())?; + let jack_set_process_callback_impl = jack_set_process_callback_impl.into_raw(); + let jack_set_process_callback_impl = *jack_set_process_callback_impl.deref() + as unsafe extern "C" fn( + client: *mut jack_client_t, + process_callback: JackProcessCallback, + arg: *mut ::libc::c_void, + ) -> ::libc::c_int; + let jack_set_freewheel_callback_impl = library + .get:: ::libc::c_int>(b"jack_set_freewheel_callback") + .map_err(|err| err.to_string())?; + let jack_set_freewheel_callback_impl = jack_set_freewheel_callback_impl.into_raw(); + let jack_set_freewheel_callback_impl = *jack_set_freewheel_callback_impl.deref() + as unsafe extern "C" fn( + client: *mut jack_client_t, + freewheel_callback: JackFreewheelCallback, + arg: *mut ::libc::c_void, + ) -> ::libc::c_int; + let jack_set_buffer_size_callback_impl = library + .get:: ::libc::c_int>(b"jack_set_buffer_size_callback") + .map_err(|err| err.to_string())?; + let jack_set_buffer_size_callback_impl = jack_set_buffer_size_callback_impl.into_raw(); + let jack_set_buffer_size_callback_impl = *jack_set_buffer_size_callback_impl.deref() + as unsafe extern "C" fn( + client: *mut jack_client_t, + bufsize_callback: JackBufferSizeCallback, + arg: *mut ::libc::c_void, + ) -> ::libc::c_int; + let jack_get_sample_rate_impl = library + .get:: ::libc::c_int>( + b"jack_get_sample_rate", + ) + .map_err(|err| err.to_string())?; + let jack_get_sample_rate_impl = jack_get_sample_rate_impl.into_raw(); + let jack_get_sample_rate_impl = *jack_get_sample_rate_impl.deref() + as unsafe extern "C" fn(client: *mut jack_client_t) -> ::libc::c_int; + let jack_set_sample_rate_callback_impl = library + .get:: ::libc::c_int>(b"jack_set_sample_rate_callback") + .map_err(|err| err.to_string())?; + let jack_set_sample_rate_callback_impl = jack_set_sample_rate_callback_impl.into_raw(); + let jack_set_sample_rate_callback_impl = *jack_set_sample_rate_callback_impl.deref() + as unsafe extern "C" fn( + client: *mut jack_client_t, + srate_callback: JackSampleRateCallback, + arg: *mut ::libc::c_void, + ) -> ::libc::c_int; + let jack_set_client_registration_callback_impl = library + .get:: ::libc::c_int>(b"jack_set_client_registration_callback") + .map_err(|err| err.to_string())?; + let jack_set_client_registration_callback_impl = + jack_set_client_registration_callback_impl.into_raw(); + let jack_set_client_registration_callback_impl = *jack_set_client_registration_callback_impl + .deref() + as unsafe extern "C" fn( + client: *mut jack_client_t, + registration_callback: JackClientRegistrationCallback, + arg: *mut ::libc::c_void, + ) -> ::libc::c_int; + let jack_set_port_registration_callback_impl = library + .get:: ::libc::c_int>(b"jack_set_port_registration_callback") + .map_err(|err| err.to_string())?; + let jack_set_port_registration_callback_impl = + jack_set_port_registration_callback_impl.into_raw(); + let jack_set_port_registration_callback_impl = *jack_set_port_registration_callback_impl.deref() + as unsafe extern "C" fn( + client: *mut jack_client_t, + registration_callback: JackPortRegistrationCallback, + arg: *mut ::libc::c_void, + ) -> ::libc::c_int; + let jack_set_port_connect_callback_impl = library + .get:: ::libc::c_int>(b"jack_set_port_connect_callback") + .map_err(|err| err.to_string())?; + let jack_set_port_connect_callback_impl = jack_set_port_connect_callback_impl.into_raw(); + let jack_set_port_connect_callback_impl = *jack_set_port_connect_callback_impl.deref() + as unsafe extern "C" fn( + client: *mut jack_client_t, + connect_callback: JackPortConnectCallback, + arg: *mut ::libc::c_void, + ) -> ::libc::c_int; + let jack_set_port_rename_callback_impl = library + .get:: ::libc::c_int>(b"jack_set_port_rename_callback") + .map_err(|err| err.to_string())?; + let jack_set_port_rename_callback_impl = jack_set_port_rename_callback_impl.into_raw(); + let jack_set_port_rename_callback_impl = *jack_set_port_rename_callback_impl.deref() + as unsafe extern "C" fn( + client: *mut jack_client_t, + rename_callback: JackPortRenameCallback, + arg: *mut ::libc::c_void, + ) -> ::libc::c_int; + let jack_set_graph_order_callback_impl = library + .get:: ::libc::c_int>(b"jack_set_graph_order_callback") + .map_err(|err| err.to_string())?; + let jack_set_graph_order_callback_impl = jack_set_graph_order_callback_impl.into_raw(); + let jack_set_graph_order_callback_impl = *jack_set_graph_order_callback_impl.deref() + as unsafe extern "C" fn( + client: *mut jack_client_t, + graph_callback: JackGraphOrderCallback, + arg: *mut ::libc::c_void, + ) -> ::libc::c_int; + let jack_set_xrun_callback_impl = library + .get:: ::libc::c_int>(b"jack_set_xrun_callback") + .map_err(|err| err.to_string())?; + let jack_set_xrun_callback_impl = jack_set_xrun_callback_impl.into_raw(); + let jack_set_xrun_callback_impl = *jack_set_xrun_callback_impl.deref() + as unsafe extern "C" fn( + client: *mut jack_client_t, + xrun_callback: JackXRunCallback, + arg: *mut ::libc::c_void, + ) -> ::libc::c_int; + let jack_set_latency_callback_impl = library + .get:: ::libc::c_int>(b"jack_set_latency_callback") + .map_err(|err| err.to_string())?; + let jack_set_latency_callback_impl = jack_set_latency_callback_impl.into_raw(); + let jack_set_latency_callback_impl = *jack_set_latency_callback_impl.deref() + as unsafe extern "C" fn( + client: *mut jack_client_t, + latency_callback: JackLatencyCallback, + arg: *mut ::libc::c_void, + ) -> ::libc::c_int; + let jack_set_freewheel_impl = library .get:: ::libc::c_int>(b"jack_set_freewheel") - .unwrap(); - let jack_set_freewheel_impl = jack_set_freewheel_impl.into_raw(); - let jack_set_freewheel_impl = *jack_set_freewheel_impl.deref() - as unsafe extern "C" fn( - client: *mut jack_client_t, - onoff: ::libc::c_int, - ) -> ::libc::c_int; - let jack_set_buffer_size_impl = library + .map_err(|err| err.to_string())?; + let jack_set_freewheel_impl = jack_set_freewheel_impl.into_raw(); + let jack_set_freewheel_impl = *jack_set_freewheel_impl.deref() + as unsafe extern "C" fn(client: *mut jack_client_t, onoff: ::libc::c_int) -> ::libc::c_int; + let jack_set_buffer_size_impl = + library .get:: ::libc::c_int>(b"jack_set_buffer_size") - .unwrap(); - let jack_set_buffer_size_impl = jack_set_buffer_size_impl.into_raw(); - let jack_set_buffer_size_impl = *jack_set_buffer_size_impl.deref() - as unsafe extern "C" fn( - client: *mut jack_client_t, - nframes: jack_nframes_t, - ) -> ::libc::c_int; - let jack_get_buffer_size_impl = library - .get:: jack_nframes_t>( - b"jack_get_buffer_size", - ) - .unwrap(); - let jack_get_buffer_size_impl = jack_get_buffer_size_impl.into_raw(); - let jack_get_buffer_size_impl = *jack_get_buffer_size_impl.deref() - as unsafe extern "C" fn(client: *mut jack_client_t) -> jack_nframes_t; - let jack_engine_takeover_timebase_impl = library - .get:: ::libc::c_int>( - b"jack_engine_takeover_timebase", - ) - .unwrap(); - let jack_engine_takeover_timebase_impl = jack_engine_takeover_timebase_impl.into_raw(); - let jack_engine_takeover_timebase_impl = *jack_engine_takeover_timebase_impl.deref() - as unsafe extern "C" fn(client: *mut jack_client_t) -> ::libc::c_int; - let jack_cpu_load_impl = library - .get:: ::libc::c_float>( - b"jack_cpu_load", - ) - .unwrap(); - let jack_cpu_load_impl = jack_cpu_load_impl.into_raw(); - let jack_cpu_load_impl = *jack_cpu_load_impl.deref() - as unsafe extern "C" fn(client: *mut jack_client_t) -> ::libc::c_float; - let jack_port_register_impl = library - .get:: *mut jack_port_t>(b"jack_port_register") - .unwrap(); - let jack_port_register_impl = jack_port_register_impl.into_raw(); - let jack_port_register_impl = *jack_port_register_impl.deref() - as unsafe extern "C" fn( - client: *mut jack_client_t, - port_name: *const ::libc::c_char, - port_type: *const ::libc::c_char, - flags: ::libc::c_ulong, - buffer_size: ::libc::c_ulong, - ) -> *mut jack_port_t; - let jack_port_unregister_impl = library + .map_err(|err| err.to_string())?; + let jack_set_buffer_size_impl = jack_set_buffer_size_impl.into_raw(); + let jack_set_buffer_size_impl = *jack_set_buffer_size_impl.deref() + as unsafe extern "C" fn( + client: *mut jack_client_t, + nframes: jack_nframes_t, + ) -> ::libc::c_int; + let jack_get_buffer_size_impl = library + .get:: jack_nframes_t>( + b"jack_get_buffer_size", + ) + .map_err(|err| err.to_string())?; + let jack_get_buffer_size_impl = jack_get_buffer_size_impl.into_raw(); + let jack_get_buffer_size_impl = *jack_get_buffer_size_impl.deref() + as unsafe extern "C" fn(client: *mut jack_client_t) -> jack_nframes_t; + let jack_engine_takeover_timebase_impl = library + .get:: ::libc::c_int>( + b"jack_engine_takeover_timebase", + ) + .map_err(|err| err.to_string())?; + let jack_engine_takeover_timebase_impl = jack_engine_takeover_timebase_impl.into_raw(); + let jack_engine_takeover_timebase_impl = *jack_engine_takeover_timebase_impl.deref() + as unsafe extern "C" fn(client: *mut jack_client_t) -> ::libc::c_int; + let jack_cpu_load_impl = library + .get:: ::libc::c_float>( + b"jack_cpu_load", + ) + .map_err(|err| err.to_string())?; + let jack_cpu_load_impl = jack_cpu_load_impl.into_raw(); + let jack_cpu_load_impl = *jack_cpu_load_impl.deref() + as unsafe extern "C" fn(client: *mut jack_client_t) -> ::libc::c_float; + let jack_port_register_impl = library + .get:: *mut jack_port_t>(b"jack_port_register") + .map_err(|err| err.to_string())?; + let jack_port_register_impl = jack_port_register_impl.into_raw(); + let jack_port_register_impl = *jack_port_register_impl.deref() + as unsafe extern "C" fn( + client: *mut jack_client_t, + port_name: *const ::libc::c_char, + port_type: *const ::libc::c_char, + flags: ::libc::c_ulong, + buffer_size: ::libc::c_ulong, + ) -> *mut jack_port_t; + let jack_port_unregister_impl = + library .get:: ::libc::c_int>(b"jack_port_unregister") - .unwrap(); - let jack_port_unregister_impl = jack_port_unregister_impl.into_raw(); - let jack_port_unregister_impl = *jack_port_unregister_impl.deref() - as unsafe extern "C" fn( - client: *mut jack_client_t, - port: *mut jack_port_t, - ) -> ::libc::c_int; - let jack_port_get_buffer_impl = library + .map_err(|err| err.to_string())?; + let jack_port_unregister_impl = jack_port_unregister_impl.into_raw(); + let jack_port_unregister_impl = *jack_port_unregister_impl.deref() + as unsafe extern "C" fn( + client: *mut jack_client_t, + port: *mut jack_port_t, + ) -> ::libc::c_int; + let jack_port_get_buffer_impl = + library .get:: *mut ::libc::c_void>(b"jack_port_get_buffer") - .unwrap(); - let jack_port_get_buffer_impl = jack_port_get_buffer_impl.into_raw(); - let jack_port_get_buffer_impl = *jack_port_get_buffer_impl.deref() - as unsafe extern "C" fn( - port: *mut jack_port_t, - nframes: jack_nframes_t, - ) -> *mut ::libc::c_void; - let jack_port_uuid_impl = library - .get:: jack_uuid_t>(b"jack_port_uuid") - .unwrap(); - let jack_port_uuid_impl = jack_port_uuid_impl.into_raw(); - let jack_port_uuid_impl = *jack_port_uuid_impl.deref() - as unsafe extern "C" fn(port: *mut jack_port_t) -> jack_uuid_t; - let jack_port_name_impl = library - .get:: *const ::libc::c_char>( - b"jack_port_name", - ) - .unwrap(); - let jack_port_name_impl = jack_port_name_impl.into_raw(); - let jack_port_name_impl = *jack_port_name_impl.deref() - as unsafe extern "C" fn(port: *mut jack_port_t) -> *const ::libc::c_char; - let jack_port_short_name_impl = library - .get:: *const ::libc::c_char>( - b"jack_port_short_name", - ) - .unwrap(); - let jack_port_short_name_impl = jack_port_short_name_impl.into_raw(); - let jack_port_short_name_impl = *jack_port_short_name_impl.deref() - as unsafe extern "C" fn(port: *mut jack_port_t) -> *const ::libc::c_char; - let jack_port_flags_impl = library - .get:: ::libc::c_int>( - b"jack_port_flags", - ) - .unwrap(); - let jack_port_flags_impl = jack_port_flags_impl.into_raw(); - let jack_port_flags_impl = *jack_port_flags_impl.deref() - as unsafe extern "C" fn(port: *mut jack_port_t) -> ::libc::c_int; - let jack_port_type_impl = library - .get:: *const ::libc::c_char>( - b"jack_port_type", - ) - .unwrap(); - let jack_port_type_impl = jack_port_type_impl.into_raw(); - let jack_port_type_impl = *jack_port_type_impl.deref() - as unsafe extern "C" fn(port: *const jack_port_t) -> *const ::libc::c_char; - let jack_port_type_id_impl = library - .get:: jack_port_type_id_t>( - b"jack_port_type_id", - ) - .ok(); - let jack_port_type_id_impl = jack_port_type_id_impl.map(|sym| sym.into_raw()); - let jack_port_type_id_impl = jack_port_type_id_impl.map(|sym| { - *sym.deref() as unsafe extern "C" fn(port: *const jack_port_t) -> jack_port_type_id_t - }); - let jack_port_is_mine_impl = library - .get:: ::libc::c_int>(b"jack_port_is_mine") - .unwrap(); - let jack_port_is_mine_impl = jack_port_is_mine_impl.into_raw(); - let jack_port_is_mine_impl = *jack_port_is_mine_impl.deref() - as unsafe extern "C" fn( - client: *const jack_client_t, - port: *const jack_port_t, - ) -> ::libc::c_int; - let jack_port_connected_impl = library - .get:: ::libc::c_int>( - b"jack_port_connected", - ) - .unwrap(); - let jack_port_connected_impl = jack_port_connected_impl.into_raw(); - let jack_port_connected_impl = *jack_port_connected_impl.deref() - as unsafe extern "C" fn(port: *const jack_port_t) -> ::libc::c_int; - let jack_port_connected_to_impl = library - .get:: ::libc::c_int>(b"jack_port_connected_to") - .unwrap(); - let jack_port_connected_to_impl = jack_port_connected_to_impl.into_raw(); - let jack_port_connected_to_impl = *jack_port_connected_to_impl.deref() - as unsafe extern "C" fn( - port: *const jack_port_t, - port_name: *const ::libc::c_char, - ) -> ::libc::c_int; - let jack_port_get_connections_impl = library - .get:: *mut *const ::libc::c_char>( - b"jack_port_get_connections", - ) - .unwrap(); - let jack_port_get_connections_impl = jack_port_get_connections_impl.into_raw(); - let jack_port_get_connections_impl = *jack_port_get_connections_impl.deref() - as unsafe extern "C" fn(port: *const jack_port_t) -> *mut *const ::libc::c_char; - let jack_port_get_all_connections_impl = library - .get:: *mut *const ::libc::c_char>(b"jack_port_get_all_connections") - .unwrap(); - let jack_port_get_all_connections_impl = jack_port_get_all_connections_impl.into_raw(); - let jack_port_get_all_connections_impl = *jack_port_get_all_connections_impl.deref() - as unsafe extern "C" fn( - client: *const jack_client_t, - port: *const jack_port_t, - ) -> *mut *const ::libc::c_char; - let jack_port_tie_impl = library.get:: ::libc::c_int>(b"jack_port_tie").unwrap(); - let jack_port_tie_impl = jack_port_tie_impl.into_raw(); - let jack_port_tie_impl = *jack_port_tie_impl.deref() - as unsafe extern "C" fn(src: *mut jack_port_t, dst: *mut jack_port_t) -> ::libc::c_int; - let jack_port_untie_impl = library - .get:: ::libc::c_int>( - b"jack_port_untie", - ) - .unwrap(); - let jack_port_untie_impl = jack_port_untie_impl.into_raw(); - let jack_port_untie_impl = *jack_port_untie_impl.deref() - as unsafe extern "C" fn(port: *mut jack_port_t) -> ::libc::c_int; - let jack_port_set_name_impl = library - .get:: ::libc::c_int>(b"jack_port_set_name") - .unwrap(); - let jack_port_set_name_impl = jack_port_set_name_impl.into_raw(); - let jack_port_set_name_impl = *jack_port_set_name_impl.deref() + .map_err(|err| err.to_string())?; + let jack_port_get_buffer_impl = jack_port_get_buffer_impl.into_raw(); + let jack_port_get_buffer_impl = *jack_port_get_buffer_impl.deref() + as unsafe extern "C" fn( + port: *mut jack_port_t, + nframes: jack_nframes_t, + ) -> *mut ::libc::c_void; + let jack_port_uuid_impl = library + .get:: jack_uuid_t>(b"jack_port_uuid") + .map_err(|err| err.to_string())?; + let jack_port_uuid_impl = jack_port_uuid_impl.into_raw(); + let jack_port_uuid_impl = + *jack_port_uuid_impl.deref() as unsafe extern "C" fn(port: *mut jack_port_t) -> jack_uuid_t; + let jack_port_name_impl = library + .get:: *const ::libc::c_char>( + b"jack_port_name", + ) + .map_err(|err| err.to_string())?; + let jack_port_name_impl = jack_port_name_impl.into_raw(); + let jack_port_name_impl = *jack_port_name_impl.deref() + as unsafe extern "C" fn(port: *mut jack_port_t) -> *const ::libc::c_char; + let jack_port_short_name_impl = library + .get:: *const ::libc::c_char>( + b"jack_port_short_name", + ) + .map_err(|err| err.to_string())?; + let jack_port_short_name_impl = jack_port_short_name_impl.into_raw(); + let jack_port_short_name_impl = *jack_port_short_name_impl.deref() + as unsafe extern "C" fn(port: *mut jack_port_t) -> *const ::libc::c_char; + let jack_port_flags_impl = library + .get:: ::libc::c_int>(b"jack_port_flags") + .map_err(|err| err.to_string())?; + let jack_port_flags_impl = jack_port_flags_impl.into_raw(); + let jack_port_flags_impl = *jack_port_flags_impl.deref() + as unsafe extern "C" fn(port: *mut jack_port_t) -> ::libc::c_int; + let jack_port_type_impl = library + .get:: *const ::libc::c_char>( + b"jack_port_type", + ) + .map_err(|err| err.to_string())?; + let jack_port_type_impl = jack_port_type_impl.into_raw(); + let jack_port_type_impl = *jack_port_type_impl.deref() + as unsafe extern "C" fn(port: *const jack_port_t) -> *const ::libc::c_char; + let jack_port_type_id_impl = library + .get:: jack_port_type_id_t>( + b"jack_port_type_id", + ) + .ok(); + let jack_port_type_id_impl = jack_port_type_id_impl.map(|sym| sym.into_raw()); + let jack_port_type_id_impl = jack_port_type_id_impl.map(|sym| { + *sym.deref() as unsafe extern "C" fn(port: *const jack_port_t) -> jack_port_type_id_t + }); + let jack_port_is_mine_impl = library + .get:: ::libc::c_int>(b"jack_port_is_mine") + .map_err(|err| err.to_string())?; + let jack_port_is_mine_impl = jack_port_is_mine_impl.into_raw(); + let jack_port_is_mine_impl = *jack_port_is_mine_impl.deref() + as unsafe extern "C" fn( + client: *const jack_client_t, + port: *const jack_port_t, + ) -> ::libc::c_int; + let jack_port_connected_impl = library + .get:: ::libc::c_int>( + b"jack_port_connected", + ) + .map_err(|err| err.to_string())?; + let jack_port_connected_impl = jack_port_connected_impl.into_raw(); + let jack_port_connected_impl = *jack_port_connected_impl.deref() + as unsafe extern "C" fn(port: *const jack_port_t) -> ::libc::c_int; + let jack_port_connected_to_impl = library + .get:: ::libc::c_int>(b"jack_port_connected_to") + .map_err(|err| err.to_string())?; + let jack_port_connected_to_impl = jack_port_connected_to_impl.into_raw(); + let jack_port_connected_to_impl = *jack_port_connected_to_impl.deref() + as unsafe extern "C" fn( + port: *const jack_port_t, + port_name: *const ::libc::c_char, + ) -> ::libc::c_int; + let jack_port_get_connections_impl = library + .get:: *mut *const ::libc::c_char>( + b"jack_port_get_connections", + ) + .map_err(|err| err.to_string())?; + let jack_port_get_connections_impl = jack_port_get_connections_impl.into_raw(); + let jack_port_get_connections_impl = *jack_port_get_connections_impl.deref() + as unsafe extern "C" fn(port: *const jack_port_t) -> *mut *const ::libc::c_char; + let jack_port_get_all_connections_impl = library + .get:: *mut *const ::libc::c_char>(b"jack_port_get_all_connections") + .map_err(|err| err.to_string())?; + let jack_port_get_all_connections_impl = jack_port_get_all_connections_impl.into_raw(); + let jack_port_get_all_connections_impl = *jack_port_get_all_connections_impl.deref() + as unsafe extern "C" fn( + client: *const jack_client_t, + port: *const jack_port_t, + ) -> *mut *const ::libc::c_char; + let jack_port_tie_impl = library + .get:: ::libc::c_int>( + b"jack_port_tie", + ) + .map_err(|err| err.to_string())?; + let jack_port_tie_impl = jack_port_tie_impl.into_raw(); + let jack_port_tie_impl = *jack_port_tie_impl.deref() + as unsafe extern "C" fn(src: *mut jack_port_t, dst: *mut jack_port_t) -> ::libc::c_int; + let jack_port_untie_impl = library + .get:: ::libc::c_int>(b"jack_port_untie") + .map_err(|err| err.to_string())?; + let jack_port_untie_impl = jack_port_untie_impl.into_raw(); + let jack_port_untie_impl = *jack_port_untie_impl.deref() + as unsafe extern "C" fn(port: *mut jack_port_t) -> ::libc::c_int; + let jack_port_set_name_impl = library + .get:: ::libc::c_int>(b"jack_port_set_name") + .map_err(|err| err.to_string())?; + let jack_port_set_name_impl = jack_port_set_name_impl.into_raw(); + let jack_port_set_name_impl = *jack_port_set_name_impl.deref() + as unsafe extern "C" fn( + port: *mut jack_port_t, + port_name: *const ::libc::c_char, + ) -> ::libc::c_int; + let jack_port_rename_impl = library + .get:: ::libc::c_int>(b"jack_port_rename") + .ok(); + let jack_port_rename_impl = jack_port_rename_impl.map(|sym| { + *sym.into_raw().deref() as unsafe extern "C" fn( + client: *mut jack_client_t, port: *mut jack_port_t, port_name: *const ::libc::c_char, - ) -> ::libc::c_int; - let jack_port_set_alias_impl = library + ) -> ::libc::c_int + }); + let jack_port_set_alias_impl = + library .get:: ::libc::c_int>(b"jack_port_set_alias") - .unwrap(); - let jack_port_set_alias_impl = jack_port_set_alias_impl.into_raw(); - let jack_port_set_alias_impl = *jack_port_set_alias_impl.deref() - as unsafe extern "C" fn( - port: *mut jack_port_t, - alias: *const ::libc::c_char, - ) -> ::libc::c_int; - let jack_port_unset_alias_impl = library + .map_err(|err| err.to_string())?; + let jack_port_set_alias_impl = jack_port_set_alias_impl.into_raw(); + let jack_port_set_alias_impl = *jack_port_set_alias_impl.deref() + as unsafe extern "C" fn( + port: *mut jack_port_t, + alias: *const ::libc::c_char, + ) -> ::libc::c_int; + let jack_port_unset_alias_impl = + library .get:: ::libc::c_int>(b"jack_port_unset_alias") - .unwrap(); - let jack_port_unset_alias_impl = jack_port_unset_alias_impl.into_raw(); - let jack_port_unset_alias_impl = *jack_port_unset_alias_impl.deref() - as unsafe extern "C" fn( - port: *mut jack_port_t, - alias: *const ::libc::c_char, - ) -> ::libc::c_int; - let jack_port_get_aliases_impl = library - .get:: ::libc::c_int>(b"jack_port_get_aliases") - .unwrap(); - let jack_port_get_aliases_impl = jack_port_get_aliases_impl.into_raw(); - let jack_port_get_aliases_impl = *jack_port_get_aliases_impl.deref() - as unsafe extern "C" fn( - port: *const jack_port_t, - aliases: *mut *mut ::libc::c_char, - ) -> ::libc::c_int; - let jack_port_request_monitor_impl = library.get:: ::libc::c_int>(b"jack_port_request_monitor").unwrap(); - let jack_port_request_monitor_impl = jack_port_request_monitor_impl.into_raw(); - let jack_port_request_monitor_impl = *jack_port_request_monitor_impl.deref() - as unsafe extern "C" fn(port: *mut jack_port_t, onoff: ::libc::c_int) -> ::libc::c_int; - let jack_port_request_monitor_by_name_impl = library - .get:: ::libc::c_int>(b"jack_port_request_monitor_by_name") - .unwrap(); - let jack_port_request_monitor_by_name_impl = - jack_port_request_monitor_by_name_impl.into_raw(); - let jack_port_request_monitor_by_name_impl = *jack_port_request_monitor_by_name_impl.deref() - as unsafe extern "C" fn( - client: *mut jack_client_t, - port_name: *const ::libc::c_char, - onoff: ::libc::c_int, - ) -> ::libc::c_int; - let jack_port_ensure_monitor_impl = library.get:: ::libc::c_int>(b"jack_port_ensure_monitor").unwrap(); - let jack_port_ensure_monitor_impl = jack_port_ensure_monitor_impl.into_raw(); - let jack_port_ensure_monitor_impl = *jack_port_ensure_monitor_impl.deref() - as unsafe extern "C" fn(port: *mut jack_port_t, onoff: ::libc::c_int) -> ::libc::c_int; - let jack_port_monitoring_input_impl = library - .get:: ::libc::c_int>( - b"jack_port_monitoring_input", - ) - .unwrap(); - let jack_port_monitoring_input_impl = jack_port_monitoring_input_impl.into_raw(); - let jack_port_monitoring_input_impl = *jack_port_monitoring_input_impl.deref() - as unsafe extern "C" fn(port: *mut jack_port_t) -> ::libc::c_int; - let jack_connect_impl = library - .get:: ::libc::c_int>(b"jack_connect") - .unwrap(); - let jack_connect_impl = jack_connect_impl.into_raw(); - let jack_connect_impl = *jack_connect_impl.deref() - as unsafe extern "C" fn( - client: *mut jack_client_t, - source_port: *const ::libc::c_char, - destination_port: *const ::libc::c_char, - ) -> ::libc::c_int; - let jack_disconnect_impl = library - .get:: ::libc::c_int>(b"jack_disconnect") - .unwrap(); - let jack_disconnect_impl = jack_disconnect_impl.into_raw(); - let jack_disconnect_impl = *jack_disconnect_impl.deref() - as unsafe extern "C" fn( - client: *mut jack_client_t, - source_port: *const ::libc::c_char, - destination_port: *const ::libc::c_char, - ) -> ::libc::c_int; - let jack_port_disconnect_impl = library + .map_err(|err| err.to_string())?; + let jack_port_unset_alias_impl = jack_port_unset_alias_impl.into_raw(); + let jack_port_unset_alias_impl = *jack_port_unset_alias_impl.deref() + as unsafe extern "C" fn( + port: *mut jack_port_t, + alias: *const ::libc::c_char, + ) -> ::libc::c_int; + let jack_port_get_aliases_impl = library + .get:: ::libc::c_int>(b"jack_port_get_aliases") + .map_err(|err| err.to_string())?; + let jack_port_get_aliases_impl = jack_port_get_aliases_impl.into_raw(); + let jack_port_get_aliases_impl = *jack_port_get_aliases_impl.deref() + as unsafe extern "C" fn( + port: *const jack_port_t, + aliases: *mut *mut ::libc::c_char, + ) -> ::libc::c_int; + let jack_port_request_monitor_impl = library + .get:: ::libc::c_int>( + b"jack_port_request_monitor", + ) + .map_err(|err| err.to_string())?; + let jack_port_request_monitor_impl = jack_port_request_monitor_impl.into_raw(); + let jack_port_request_monitor_impl = *jack_port_request_monitor_impl.deref() + as unsafe extern "C" fn(port: *mut jack_port_t, onoff: ::libc::c_int) -> ::libc::c_int; + let jack_port_request_monitor_by_name_impl = library + .get:: ::libc::c_int>(b"jack_port_request_monitor_by_name") + .map_err(|err| err.to_string())?; + let jack_port_request_monitor_by_name_impl = jack_port_request_monitor_by_name_impl.into_raw(); + let jack_port_request_monitor_by_name_impl = *jack_port_request_monitor_by_name_impl.deref() + as unsafe extern "C" fn( + client: *mut jack_client_t, + port_name: *const ::libc::c_char, + onoff: ::libc::c_int, + ) -> ::libc::c_int; + let jack_port_ensure_monitor_impl = library + .get:: ::libc::c_int>( + b"jack_port_ensure_monitor", + ) + .map_err(|err| err.to_string())?; + let jack_port_ensure_monitor_impl = jack_port_ensure_monitor_impl.into_raw(); + let jack_port_ensure_monitor_impl = *jack_port_ensure_monitor_impl.deref() + as unsafe extern "C" fn(port: *mut jack_port_t, onoff: ::libc::c_int) -> ::libc::c_int; + let jack_port_monitoring_input_impl = library + .get:: ::libc::c_int>( + b"jack_port_monitoring_input", + ) + .map_err(|err| err.to_string())?; + let jack_port_monitoring_input_impl = jack_port_monitoring_input_impl.into_raw(); + let jack_port_monitoring_input_impl = *jack_port_monitoring_input_impl.deref() + as unsafe extern "C" fn(port: *mut jack_port_t) -> ::libc::c_int; + let jack_connect_impl = library + .get:: ::libc::c_int>(b"jack_connect") + .map_err(|err| err.to_string())?; + let jack_connect_impl = jack_connect_impl.into_raw(); + let jack_connect_impl = *jack_connect_impl.deref() + as unsafe extern "C" fn( + client: *mut jack_client_t, + source_port: *const ::libc::c_char, + destination_port: *const ::libc::c_char, + ) -> ::libc::c_int; + let jack_disconnect_impl = library + .get:: ::libc::c_int>(b"jack_disconnect") + .map_err(|err| err.to_string())?; + let jack_disconnect_impl = jack_disconnect_impl.into_raw(); + let jack_disconnect_impl = *jack_disconnect_impl.deref() + as unsafe extern "C" fn( + client: *mut jack_client_t, + source_port: *const ::libc::c_char, + destination_port: *const ::libc::c_char, + ) -> ::libc::c_int; + let jack_port_disconnect_impl = + library .get:: ::libc::c_int>(b"jack_port_disconnect") - .unwrap(); - let jack_port_disconnect_impl = jack_port_disconnect_impl.into_raw(); - let jack_port_disconnect_impl = *jack_port_disconnect_impl.deref() - as unsafe extern "C" fn( - client: *mut jack_client_t, - port: *mut jack_port_t, - ) -> ::libc::c_int; - let jack_port_name_size_impl = library - .get:: ::libc::c_int>(b"jack_port_name_size") - .unwrap(); - let jack_port_name_size_impl = jack_port_name_size_impl.into_raw(); - let jack_port_name_size_impl = - *jack_port_name_size_impl.deref() as unsafe extern "C" fn() -> ::libc::c_int; - let jack_port_type_size_impl = library - .get:: ::libc::c_int>(b"jack_port_type_size") - .unwrap(); - let jack_port_type_size_impl = jack_port_type_size_impl.into_raw(); - let jack_port_type_size_impl = - *jack_port_type_size_impl.deref() as unsafe extern "C" fn() -> ::libc::c_int; - let jack_port_type_get_buffer_size_impl = library - .get:: ::libc::size_t>(b"jack_port_type_get_buffer_size") - .unwrap(); - let jack_port_type_get_buffer_size_impl = jack_port_type_get_buffer_size_impl.into_raw(); - let jack_port_type_get_buffer_size_impl = *jack_port_type_get_buffer_size_impl.deref() - as unsafe extern "C" fn( - client: *mut jack_client_t, - port_type: *const ::libc::c_char, - ) -> ::libc::size_t; - let jack_port_set_latency_impl = library - .get:: ()>( - b"jack_port_set_latency", - ) - .unwrap(); - let jack_port_set_latency_impl = jack_port_set_latency_impl.into_raw(); - let jack_port_set_latency_impl = *jack_port_set_latency_impl.deref() - as unsafe extern "C" fn(port: *mut jack_port_t, arg1: jack_nframes_t) -> (); - let jack_port_get_latency_range_impl = library - .get:: ()>(b"jack_port_get_latency_range") - .unwrap(); - let jack_port_get_latency_range_impl = jack_port_get_latency_range_impl.into_raw(); - let jack_port_get_latency_range_impl = *jack_port_get_latency_range_impl.deref() - as unsafe extern "C" fn( - port: *mut jack_port_t, - mode: jack_latency_callback_mode_t, - range: *mut jack_latency_range_t, - ) -> (); - let jack_port_set_latency_range_impl = library - .get:: ()>(b"jack_port_set_latency_range") - .unwrap(); - let jack_port_set_latency_range_impl = jack_port_set_latency_range_impl.into_raw(); - let jack_port_set_latency_range_impl = *jack_port_set_latency_range_impl.deref() - as unsafe extern "C" fn( - port: *mut jack_port_t, - mode: jack_latency_callback_mode_t, - range: *mut jack_latency_range_t, - ) -> (); - let jack_recompute_total_latencies_impl = library - .get:: ::libc::c_int>( - b"jack_recompute_total_latencies", - ) - .unwrap(); - let jack_recompute_total_latencies_impl = jack_recompute_total_latencies_impl.into_raw(); - let jack_recompute_total_latencies_impl = *jack_recompute_total_latencies_impl.deref() - as unsafe extern "C" fn(client: *mut jack_client_t) -> ::libc::c_int; - let jack_port_get_latency_impl = library - .get:: jack_nframes_t>( - b"jack_port_get_latency", - ) - .unwrap(); - let jack_port_get_latency_impl = jack_port_get_latency_impl.into_raw(); - let jack_port_get_latency_impl = *jack_port_get_latency_impl.deref() - as unsafe extern "C" fn(port: *mut jack_port_t) -> jack_nframes_t; - let jack_port_get_total_latency_impl = library + .map_err(|err| err.to_string())?; + let jack_port_disconnect_impl = jack_port_disconnect_impl.into_raw(); + let jack_port_disconnect_impl = *jack_port_disconnect_impl.deref() + as unsafe extern "C" fn( + client: *mut jack_client_t, + port: *mut jack_port_t, + ) -> ::libc::c_int; + let jack_port_name_size_impl = library + .get:: ::libc::c_int>(b"jack_port_name_size") + .map_err(|err| err.to_string())?; + let jack_port_name_size_impl = jack_port_name_size_impl.into_raw(); + let jack_port_name_size_impl = + *jack_port_name_size_impl.deref() as unsafe extern "C" fn() -> ::libc::c_int; + let jack_port_type_size_impl = library + .get:: ::libc::c_int>(b"jack_port_type_size") + .map_err(|err| err.to_string())?; + let jack_port_type_size_impl = jack_port_type_size_impl.into_raw(); + let jack_port_type_size_impl = + *jack_port_type_size_impl.deref() as unsafe extern "C" fn() -> ::libc::c_int; + let jack_port_type_get_buffer_size_impl = library + .get:: ::libc::size_t>(b"jack_port_type_get_buffer_size") + .map_err(|err| err.to_string())?; + let jack_port_type_get_buffer_size_impl = jack_port_type_get_buffer_size_impl.into_raw(); + let jack_port_type_get_buffer_size_impl = *jack_port_type_get_buffer_size_impl.deref() + as unsafe extern "C" fn( + client: *mut jack_client_t, + port_type: *const ::libc::c_char, + ) -> ::libc::size_t; + let jack_port_set_latency_impl = library + .get:: ()>( + b"jack_port_set_latency", + ) + .map_err(|err| err.to_string())?; + let jack_port_set_latency_impl = jack_port_set_latency_impl.into_raw(); + let jack_port_set_latency_impl = *jack_port_set_latency_impl.deref() + as unsafe extern "C" fn(port: *mut jack_port_t, arg1: jack_nframes_t) -> (); + let jack_port_get_latency_range_impl = library + .get:: ()>(b"jack_port_get_latency_range") + .map_err(|err| err.to_string())?; + let jack_port_get_latency_range_impl = jack_port_get_latency_range_impl.into_raw(); + let jack_port_get_latency_range_impl = *jack_port_get_latency_range_impl.deref() + as unsafe extern "C" fn( + port: *mut jack_port_t, + mode: jack_latency_callback_mode_t, + range: *mut jack_latency_range_t, + ) -> (); + let jack_port_set_latency_range_impl = library + .get:: ()>(b"jack_port_set_latency_range") + .map_err(|err| err.to_string())?; + let jack_port_set_latency_range_impl = jack_port_set_latency_range_impl.into_raw(); + let jack_port_set_latency_range_impl = *jack_port_set_latency_range_impl.deref() + as unsafe extern "C" fn( + port: *mut jack_port_t, + mode: jack_latency_callback_mode_t, + range: *mut jack_latency_range_t, + ) -> (); + let jack_recompute_total_latencies_impl = library + .get:: ::libc::c_int>( + b"jack_recompute_total_latencies", + ) + .map_err(|err| err.to_string())?; + let jack_recompute_total_latencies_impl = jack_recompute_total_latencies_impl.into_raw(); + let jack_recompute_total_latencies_impl = *jack_recompute_total_latencies_impl.deref() + as unsafe extern "C" fn(client: *mut jack_client_t) -> ::libc::c_int; + let jack_port_get_latency_impl = library + .get:: jack_nframes_t>( + b"jack_port_get_latency", + ) + .map_err(|err| err.to_string())?; + let jack_port_get_latency_impl = jack_port_get_latency_impl.into_raw(); + let jack_port_get_latency_impl = *jack_port_get_latency_impl.deref() + as unsafe extern "C" fn(port: *mut jack_port_t) -> jack_nframes_t; + let jack_port_get_total_latency_impl = + library .get:: jack_nframes_t>(b"jack_port_get_total_latency") - .unwrap(); - let jack_port_get_total_latency_impl = jack_port_get_total_latency_impl.into_raw(); - let jack_port_get_total_latency_impl = *jack_port_get_total_latency_impl.deref() - as unsafe extern "C" fn( - client: *mut jack_client_t, - port: *mut jack_port_t, - ) -> jack_nframes_t; - let jack_recompute_total_latency_impl = + .map_err(|err| err.to_string())?; + let jack_port_get_total_latency_impl = jack_port_get_total_latency_impl.into_raw(); + let jack_port_get_total_latency_impl = *jack_port_get_total_latency_impl.deref() + as unsafe extern "C" fn( + client: *mut jack_client_t, + port: *mut jack_port_t, + ) -> jack_nframes_t; + let jack_recompute_total_latency_impl = library .get:: ::libc::c_int>(b"jack_recompute_total_latency") - .unwrap(); - let jack_recompute_total_latency_impl = jack_recompute_total_latency_impl.into_raw(); - let jack_recompute_total_latency_impl = *jack_recompute_total_latency_impl.deref() - as unsafe extern "C" fn( - arg1: *mut jack_client_t, - port: *mut jack_port_t, - ) -> ::libc::c_int; - let jack_get_ports_impl = library - .get:: *mut *const ::libc::c_char>(b"jack_get_ports") - .unwrap(); - let jack_get_ports_impl = jack_get_ports_impl.into_raw(); - let jack_get_ports_impl = *jack_get_ports_impl.deref() - as unsafe extern "C" fn( - client: *mut jack_client_t, - port_name_pattern: *const ::libc::c_char, - type_name_pattern: *const ::libc::c_char, - flags: ::libc::c_ulong, - ) -> *mut *const ::libc::c_char; - let jack_port_by_name_impl = library - .get:: *mut jack_port_t>(b"jack_port_by_name") - .unwrap(); - let jack_port_by_name_impl = jack_port_by_name_impl.into_raw(); - let jack_port_by_name_impl = *jack_port_by_name_impl.deref() - as unsafe extern "C" fn( - client: *mut jack_client_t, - port_name: *const ::libc::c_char, - ) -> *mut jack_port_t; - let jack_port_by_id_impl = library - .get:: *mut jack_port_t>(b"jack_port_by_id") - .unwrap(); - let jack_port_by_id_impl = jack_port_by_id_impl.into_raw(); - let jack_port_by_id_impl = *jack_port_by_id_impl.deref() - as unsafe extern "C" fn( - client: *mut jack_client_t, - port_id: jack_port_id_t, - ) -> *mut jack_port_t; - let jack_frames_since_cycle_start_impl = library - .get:: jack_nframes_t>( - b"jack_frames_since_cycle_start", - ) - .unwrap(); - let jack_frames_since_cycle_start_impl = jack_frames_since_cycle_start_impl.into_raw(); - let jack_frames_since_cycle_start_impl = *jack_frames_since_cycle_start_impl.deref() - as unsafe extern "C" fn(arg1: *const jack_client_t) -> jack_nframes_t; - let jack_frame_time_impl = library - .get:: jack_nframes_t>( - b"jack_frame_time", - ) - .unwrap(); - let jack_frame_time_impl = jack_frame_time_impl.into_raw(); - let jack_frame_time_impl = *jack_frame_time_impl.deref() - as unsafe extern "C" fn(arg1: *const jack_client_t) -> jack_nframes_t; - let jack_last_frame_time_impl = library - .get:: jack_nframes_t>( - b"jack_last_frame_time", - ) - .unwrap(); - let jack_last_frame_time_impl = jack_last_frame_time_impl.into_raw(); - let jack_last_frame_time_impl = *jack_last_frame_time_impl.deref() - as unsafe extern "C" fn(client: *const jack_client_t) -> jack_nframes_t; - let jack_frames_to_time_impl = + .map_err(|err| err.to_string())?; + let jack_recompute_total_latency_impl = jack_recompute_total_latency_impl.into_raw(); + let jack_recompute_total_latency_impl = *jack_recompute_total_latency_impl.deref() + as unsafe extern "C" fn(arg1: *mut jack_client_t, port: *mut jack_port_t) -> ::libc::c_int; + let jack_get_ports_impl = library + .get:: *mut *const ::libc::c_char>(b"jack_get_ports") + .map_err(|err| err.to_string())?; + let jack_get_ports_impl = jack_get_ports_impl.into_raw(); + let jack_get_ports_impl = *jack_get_ports_impl.deref() + as unsafe extern "C" fn( + client: *mut jack_client_t, + port_name_pattern: *const ::libc::c_char, + type_name_pattern: *const ::libc::c_char, + flags: ::libc::c_ulong, + ) -> *mut *const ::libc::c_char; + let jack_port_by_name_impl = library + .get:: *mut jack_port_t>(b"jack_port_by_name") + .map_err(|err| err.to_string())?; + let jack_port_by_name_impl = jack_port_by_name_impl.into_raw(); + let jack_port_by_name_impl = *jack_port_by_name_impl.deref() + as unsafe extern "C" fn( + client: *mut jack_client_t, + port_name: *const ::libc::c_char, + ) -> *mut jack_port_t; + let jack_port_by_id_impl = library + .get:: *mut jack_port_t>(b"jack_port_by_id") + .map_err(|err| err.to_string())?; + let jack_port_by_id_impl = jack_port_by_id_impl.into_raw(); + let jack_port_by_id_impl = *jack_port_by_id_impl.deref() + as unsafe extern "C" fn( + client: *mut jack_client_t, + port_id: jack_port_id_t, + ) -> *mut jack_port_t; + let jack_frames_since_cycle_start_impl = library + .get:: jack_nframes_t>( + b"jack_frames_since_cycle_start", + ) + .map_err(|err| err.to_string())?; + let jack_frames_since_cycle_start_impl = jack_frames_since_cycle_start_impl.into_raw(); + let jack_frames_since_cycle_start_impl = *jack_frames_since_cycle_start_impl.deref() + as unsafe extern "C" fn(arg1: *const jack_client_t) -> jack_nframes_t; + let jack_frame_time_impl = library + .get:: jack_nframes_t>( + b"jack_frame_time", + ) + .map_err(|err| err.to_string())?; + let jack_frame_time_impl = jack_frame_time_impl.into_raw(); + let jack_frame_time_impl = *jack_frame_time_impl.deref() + as unsafe extern "C" fn(arg1: *const jack_client_t) -> jack_nframes_t; + let jack_last_frame_time_impl = library + .get:: jack_nframes_t>( + b"jack_last_frame_time", + ) + .map_err(|err| err.to_string())?; + let jack_last_frame_time_impl = jack_last_frame_time_impl.into_raw(); + let jack_last_frame_time_impl = *jack_last_frame_time_impl.deref() + as unsafe extern "C" fn(client: *const jack_client_t) -> jack_nframes_t; + let jack_frames_to_time_impl = library .get:: jack_time_t>(b"jack_frames_to_time") - .unwrap(); - let jack_frames_to_time_impl = jack_frames_to_time_impl.into_raw(); - let jack_frames_to_time_impl = *jack_frames_to_time_impl.deref() - as unsafe extern "C" fn( - client: *const jack_client_t, - arg1: jack_nframes_t, - ) -> jack_time_t; - let jack_time_to_frames_impl = + .map_err(|err| err.to_string())?; + let jack_frames_to_time_impl = jack_frames_to_time_impl.into_raw(); + let jack_frames_to_time_impl = *jack_frames_to_time_impl.deref() + as unsafe extern "C" fn(client: *const jack_client_t, arg1: jack_nframes_t) -> jack_time_t; + let jack_time_to_frames_impl = library .get:: jack_nframes_t>(b"jack_time_to_frames") - .unwrap(); - let jack_time_to_frames_impl = jack_time_to_frames_impl.into_raw(); - let jack_time_to_frames_impl = *jack_time_to_frames_impl.deref() - as unsafe extern "C" fn( - client: *const jack_client_t, - arg1: jack_time_t, - ) -> jack_nframes_t; - let jack_get_time_impl = library - .get:: jack_time_t>(b"jack_get_time") - .unwrap(); - let jack_get_time_impl = jack_get_time_impl.into_raw(); - let jack_get_time_impl = - *jack_get_time_impl.deref() as unsafe extern "C" fn() -> jack_time_t; - let jack_set_error_function_impl = - library - .get:: (), - >, - ) -> ()>(b"jack_set_error_function") - .unwrap(); - let jack_set_error_function_impl = jack_set_error_function_impl.into_raw(); - let jack_set_error_function_impl = *jack_set_error_function_impl.deref() - as unsafe extern "C" fn( - func: ::std::option::Option ()>, - ) -> (); - let jack_set_info_function_impl = - library - .get:: (), - >, - ) -> ()>(b"jack_set_info_function") - .unwrap(); - let jack_set_info_function_impl = jack_set_info_function_impl.into_raw(); - let jack_set_info_function_impl = *jack_set_info_function_impl.deref() - as unsafe extern "C" fn( - func: ::std::option::Option ()>, - ) -> (); - let jack_free_impl = library - .get:: ()>(b"jack_free") - .unwrap(); - let jack_free_impl = jack_free_impl.into_raw(); - let jack_free_impl = - *jack_free_impl.deref() as unsafe extern "C" fn(ptr: *mut ::libc::c_void) -> (); - let jack_client_real_time_priority_impl = library - .get:: ::libc::c_int>( - b"jack_client_real_time_priority", - ) - .unwrap(); - let jack_client_real_time_priority_impl = jack_client_real_time_priority_impl.into_raw(); - let jack_client_real_time_priority_impl = *jack_client_real_time_priority_impl.deref() - as unsafe extern "C" fn(arg1: *mut jack_client_t) -> ::libc::c_int; - let jack_client_max_real_time_priority_impl = library - .get:: ::libc::c_int>( - b"jack_client_max_real_time_priority", - ) - .unwrap(); - let jack_client_max_real_time_priority_impl = - jack_client_max_real_time_priority_impl.into_raw(); - let jack_client_max_real_time_priority_impl = *jack_client_max_real_time_priority_impl - .deref() - as unsafe extern "C" fn(arg1: *mut jack_client_t) -> ::libc::c_int; - let jack_set_session_callback_impl = library - .get:: ::libc::c_int>(b"jack_set_session_callback") - .unwrap(); - let jack_set_session_callback_impl = jack_set_session_callback_impl.into_raw(); - let jack_set_session_callback_impl = *jack_set_session_callback_impl.deref() + .map_err(|err| err.to_string())?; + let jack_time_to_frames_impl = jack_time_to_frames_impl.into_raw(); + let jack_time_to_frames_impl = *jack_time_to_frames_impl.deref() + as unsafe extern "C" fn(client: *const jack_client_t, arg1: jack_time_t) -> jack_nframes_t; + let jack_get_time_impl = library + .get:: jack_time_t>(b"jack_get_time") + .map_err(|err| err.to_string())?; + let jack_get_time_impl = jack_get_time_impl.into_raw(); + let jack_get_time_impl = *jack_get_time_impl.deref() as unsafe extern "C" fn() -> jack_time_t; + let jack_set_error_function_impl = library + .get:: ()>, + ) -> ()>(b"jack_set_error_function") + .map_err(|err| err.to_string())?; + let jack_set_error_function_impl = jack_set_error_function_impl.into_raw(); + let jack_set_error_function_impl = *jack_set_error_function_impl.deref() + as unsafe extern "C" fn( + func: ::std::option::Option ()>, + ) -> (); + let jack_set_info_function_impl = library + .get:: ()>, + ) -> ()>(b"jack_set_info_function") + .map_err(|err| err.to_string())?; + let jack_set_info_function_impl = jack_set_info_function_impl.into_raw(); + let jack_set_info_function_impl = *jack_set_info_function_impl.deref() + as unsafe extern "C" fn( + func: ::std::option::Option ()>, + ) -> (); + let jack_free_impl = library + .get:: ()>(b"jack_free") + .map_err(|err| err.to_string())?; + let jack_free_impl = jack_free_impl.into_raw(); + let jack_free_impl = + *jack_free_impl.deref() as unsafe extern "C" fn(ptr: *mut ::libc::c_void) -> (); + let jack_client_real_time_priority_impl = library + .get:: ::libc::c_int>( + b"jack_client_real_time_priority", + ) + .map_err(|err| err.to_string())?; + let jack_client_real_time_priority_impl = jack_client_real_time_priority_impl.into_raw(); + let jack_client_real_time_priority_impl = *jack_client_real_time_priority_impl.deref() + as unsafe extern "C" fn(arg1: *mut jack_client_t) -> ::libc::c_int; + let jack_client_max_real_time_priority_impl = library + .get:: ::libc::c_int>( + b"jack_client_max_real_time_priority", + ) + .map_err(|err| err.to_string())?; + let jack_client_max_real_time_priority_impl = + jack_client_max_real_time_priority_impl.into_raw(); + let jack_client_max_real_time_priority_impl = *jack_client_max_real_time_priority_impl.deref() + as unsafe extern "C" fn(arg1: *mut jack_client_t) -> ::libc::c_int; + let jack_set_session_callback_impl = library + .get:: ::libc::c_int>(b"jack_set_session_callback") + .map_err(|err| err.to_string())?; + let jack_set_session_callback_impl = jack_set_session_callback_impl.into_raw(); + let jack_set_session_callback_impl = *jack_set_session_callback_impl.deref() + as unsafe extern "C" fn( + client: *mut jack_client_t, + session_callback: JackSessionCallback, + arg: *mut ::libc::c_void, + ) -> ::libc::c_int; + let jack_session_reply_impl = library + .get:: ::libc::c_int>(b"jack_session_reply") + .map_err(|err| err.to_string())?; + let jack_session_reply_impl = jack_session_reply_impl.into_raw(); + let jack_session_reply_impl = *jack_session_reply_impl.deref() + as unsafe extern "C" fn( + client: *mut jack_client_t, + event: *mut jack_session_event_t, + ) -> ::libc::c_int; + let jack_session_event_free_impl = library + .get:: ()>( + b"jack_session_event_free", + ) + .map_err(|err| err.to_string())?; + let jack_session_event_free_impl = jack_session_event_free_impl.into_raw(); + let jack_session_event_free_impl = *jack_session_event_free_impl.deref() + as unsafe extern "C" fn(event: *mut jack_session_event_t) -> (); + let jack_client_get_uuid_impl = library + .get:: *mut ::libc::c_char>( + b"jack_client_get_uuid", + ) + .map_err(|err| err.to_string())?; + let jack_client_get_uuid_impl = jack_client_get_uuid_impl.into_raw(); + let jack_client_get_uuid_impl = *jack_client_get_uuid_impl.deref() + as unsafe extern "C" fn(client: *mut jack_client_t) -> *mut ::libc::c_char; + let jack_session_notify_impl = library + .get:: *mut jack_session_command_t>(b"jack_session_notify") + .map_err(|err| err.to_string())?; + let jack_session_notify_impl = jack_session_notify_impl.into_raw(); + let jack_session_notify_impl = *jack_session_notify_impl.deref() + as unsafe extern "C" fn( + client: *mut jack_client_t, + target: *const ::libc::c_char, + _type: jack_session_event_type_t, + path: *const ::libc::c_char, + ) -> *mut jack_session_command_t; + let jack_session_commands_free_impl = library + .get:: ()>( + b"jack_session_commands_free", + ) + .map_err(|err| err.to_string())?; + let jack_session_commands_free_impl = jack_session_commands_free_impl.into_raw(); + let jack_session_commands_free_impl = *jack_session_commands_free_impl.deref() + as unsafe extern "C" fn(cmds: *mut jack_session_command_t) -> (); + let jack_reserve_client_name_impl = library + .get:: ::libc::c_int>(b"jack_reserve_client_name") + .map_err(|err| err.to_string())?; + let jack_reserve_client_name_impl = jack_reserve_client_name_impl.into_raw(); + let jack_reserve_client_name_impl = *jack_reserve_client_name_impl.deref() + as unsafe extern "C" fn( + client: *mut jack_client_t, + name: *const ::libc::c_char, + uuid: *const ::libc::c_char, + ) -> ::libc::c_int; + let jack_client_has_session_callback_impl = library + .get:: ::libc::c_int>(b"jack_client_has_session_callback") + .map_err(|err| err.to_string())?; + let jack_client_has_session_callback_impl = jack_client_has_session_callback_impl.into_raw(); + let jack_client_has_session_callback_impl = *jack_client_has_session_callback_impl.deref() + as unsafe extern "C" fn( + client: *mut jack_client_t, + client_name: *const ::libc::c_char, + ) -> ::libc::c_int; + let jackctl_setup_signals_impl = library + .get:: *mut jackctl_sigmask_t>( + b"jackctl_setup_signals", + ) + .ok(); + let jackctl_setup_signals_impl = jackctl_setup_signals_impl.map(|sym| sym.into_raw()); + let jackctl_setup_signals_impl = jackctl_setup_signals_impl.map(|sym| { + *sym.deref() as unsafe extern "C" fn(flags: ::libc::c_uint) -> *mut jackctl_sigmask_t + }); + let jackctl_wait_signals_impl = library + .get:: ()>(b"jackctl_wait_signals") + .ok(); + let jackctl_wait_signals_impl = jackctl_wait_signals_impl.map(|sym| sym.into_raw()); + let jackctl_wait_signals_impl = jackctl_wait_signals_impl + .map(|sym| *sym.deref() as unsafe extern "C" fn(signals: *mut jackctl_sigmask_t) -> ()); + let jackctl_server_create_impl = library + .get:: u8, + >, + on_device_release: ::std::option::Option< + unsafe extern "C" fn(device_name: *const ::libc::c_char) -> (), + >, + ) -> *mut jackctl_server_t>(b"jackctl_server_create") + .ok(); + let jackctl_server_create_impl = jackctl_server_create_impl.map(|sym| sym.into_raw()); + let jackctl_server_create_impl = jackctl_server_create_impl.map(|sym| { + *sym.deref() as unsafe extern "C" fn( - client: *mut jack_client_t, - session_callback: JackSessionCallback, - arg: *mut ::libc::c_void, - ) -> ::libc::c_int; - let jack_session_reply_impl = library - .get:: ::libc::c_int>(b"jack_session_reply") - .unwrap(); - let jack_session_reply_impl = jack_session_reply_impl.into_raw(); - let jack_session_reply_impl = *jack_session_reply_impl.deref() - as unsafe extern "C" fn( - client: *mut jack_client_t, - event: *mut jack_session_event_t, - ) -> ::libc::c_int; - let jack_session_event_free_impl = library - .get:: ()>( - b"jack_session_event_free", - ) - .unwrap(); - let jack_session_event_free_impl = jack_session_event_free_impl.into_raw(); - let jack_session_event_free_impl = *jack_session_event_free_impl.deref() - as unsafe extern "C" fn(event: *mut jack_session_event_t) -> (); - let jack_client_get_uuid_impl = library - .get:: *mut ::libc::c_char>( - b"jack_client_get_uuid", - ) - .unwrap(); - let jack_client_get_uuid_impl = jack_client_get_uuid_impl.into_raw(); - let jack_client_get_uuid_impl = *jack_client_get_uuid_impl.deref() - as unsafe extern "C" fn(client: *mut jack_client_t) -> *mut ::libc::c_char; - let jack_session_notify_impl = library - .get:: *mut jack_session_command_t>(b"jack_session_notify") - .unwrap(); - let jack_session_notify_impl = jack_session_notify_impl.into_raw(); - let jack_session_notify_impl = *jack_session_notify_impl.deref() - as unsafe extern "C" fn( - client: *mut jack_client_t, - target: *const ::libc::c_char, - _type: jack_session_event_type_t, - path: *const ::libc::c_char, - ) -> *mut jack_session_command_t; - let jack_session_commands_free_impl = library - .get:: ()>( - b"jack_session_commands_free", - ) - .unwrap(); - let jack_session_commands_free_impl = jack_session_commands_free_impl.into_raw(); - let jack_session_commands_free_impl = *jack_session_commands_free_impl.deref() - as unsafe extern "C" fn(cmds: *mut jack_session_command_t) -> (); - let jack_reserve_client_name_impl = library - .get:: ::libc::c_int>(b"jack_reserve_client_name") - .unwrap(); - let jack_reserve_client_name_impl = jack_reserve_client_name_impl.into_raw(); - let jack_reserve_client_name_impl = *jack_reserve_client_name_impl.deref() - as unsafe extern "C" fn( - client: *mut jack_client_t, - name: *const ::libc::c_char, - uuid: *const ::libc::c_char, - ) -> ::libc::c_int; - let jack_client_has_session_callback_impl = library - .get:: ::libc::c_int>(b"jack_client_has_session_callback") - .unwrap(); - let jack_client_has_session_callback_impl = - jack_client_has_session_callback_impl.into_raw(); - let jack_client_has_session_callback_impl = *jack_client_has_session_callback_impl.deref() - as unsafe extern "C" fn( - client: *mut jack_client_t, - client_name: *const ::libc::c_char, - ) -> ::libc::c_int; - let jackctl_setup_signals_impl = library - .get:: *mut jackctl_sigmask_t>( - b"jackctl_setup_signals", - ) - .ok(); - let jackctl_setup_signals_impl = jackctl_setup_signals_impl.map(|sym| sym.into_raw()); - let jackctl_setup_signals_impl = jackctl_setup_signals_impl.map(|sym| { - *sym.deref() as unsafe extern "C" fn(flags: ::libc::c_uint) -> *mut jackctl_sigmask_t - }); - let jackctl_wait_signals_impl = library - .get:: ()>( - b"jackctl_wait_signals", - ) - .ok(); - let jackctl_wait_signals_impl = jackctl_wait_signals_impl.map(|sym| sym.into_raw()); - let jackctl_wait_signals_impl = jackctl_wait_signals_impl - .map(|sym| *sym.deref() as unsafe extern "C" fn(signals: *mut jackctl_sigmask_t) -> ()); - let jackctl_server_create_impl = library - .get:: u8, >, on_device_release: ::std::option::Option< unsafe extern "C" fn(device_name: *const ::libc::c_char) -> (), >, - ) -> *mut jackctl_server_t>(b"jackctl_server_create") - .ok(); - let jackctl_server_create_impl = jackctl_server_create_impl.map(|sym| sym.into_raw()); - let jackctl_server_create_impl = jackctl_server_create_impl.map(|sym| { - *sym.deref() - as unsafe extern "C" fn( - on_device_acquire: ::std::option::Option< - unsafe extern "C" fn(device_name: *const ::libc::c_char) -> u8, - >, - on_device_release: ::std::option::Option< - unsafe extern "C" fn(device_name: *const ::libc::c_char) -> (), - >, - ) -> *mut jackctl_server_t - }); - let jackctl_server_destroy_impl = library - .get:: ()>( - b"jackctl_server_destroy", - ) - .ok(); - let jackctl_server_destroy_impl = jackctl_server_destroy_impl.map(|sym| sym.into_raw()); - let jackctl_server_destroy_impl = jackctl_server_destroy_impl - .map(|sym| *sym.deref() as unsafe extern "C" fn(server: *mut jackctl_server_t) -> ()); - let jackctl_server_open_impl = + ) -> *mut jackctl_server_t + }); + let jackctl_server_destroy_impl = library + .get:: ()>(b"jackctl_server_destroy") + .ok(); + let jackctl_server_destroy_impl = jackctl_server_destroy_impl.map(|sym| sym.into_raw()); + let jackctl_server_destroy_impl = jackctl_server_destroy_impl + .map(|sym| *sym.deref() as unsafe extern "C" fn(server: *mut jackctl_server_t) -> ()); + let jackctl_server_open_impl = library .get:: u8>(b"jackctl_server_open") .ok(); - let jackctl_server_open_impl = jackctl_server_open_impl.map(|sym| sym.into_raw()); - let jackctl_server_open_impl = jackctl_server_open_impl.map(|sym| { - *sym.deref() - as unsafe extern "C" fn( - server: *mut jackctl_server_t, - driver: *mut jackctl_driver_t, - ) -> u8 - }); - let jackctl_server_start_impl = library - .get:: u8>( - b"jackctl_server_start", - ) - .ok(); - let jackctl_server_start_impl = jackctl_server_start_impl.map(|sym| sym.into_raw()); - let jackctl_server_start_impl = jackctl_server_start_impl - .map(|sym| *sym.deref() as unsafe extern "C" fn(server: *mut jackctl_server_t) -> u8); - let jackctl_server_stop_impl = library - .get:: u8>( - b"jackctl_server_stop", - ) - .ok(); - let jackctl_server_stop_impl = jackctl_server_stop_impl.map(|sym| sym.into_raw()); - let jackctl_server_stop_impl = jackctl_server_stop_impl - .map(|sym| *sym.deref() as unsafe extern "C" fn(server: *mut jackctl_server_t) -> u8); - let jackctl_server_close_impl = library - .get:: u8>( - b"jackctl_server_close", - ) - .ok(); - let jackctl_server_close_impl = jackctl_server_close_impl.map(|sym| sym.into_raw()); - let jackctl_server_close_impl = jackctl_server_close_impl - .map(|sym| *sym.deref() as unsafe extern "C" fn(server: *mut jackctl_server_t) -> u8); - let jackctl_server_get_drivers_list_impl = library - .get:: *const JSList>( - b"jackctl_server_get_drivers_list", - ) - .ok(); - let jackctl_server_get_drivers_list_impl = - jackctl_server_get_drivers_list_impl.map(|sym| sym.into_raw()); - let jackctl_server_get_drivers_list_impl = - jackctl_server_get_drivers_list_impl.map(|sym| { - *sym.deref() as unsafe extern "C" fn(server: *mut jackctl_server_t) -> *const JSList - }); - let jackctl_server_get_parameters_impl = library - .get:: *const JSList>( - b"jackctl_server_get_parameters", - ) - .ok(); - let jackctl_server_get_parameters_impl = - jackctl_server_get_parameters_impl.map(|sym| sym.into_raw()); - let jackctl_server_get_parameters_impl = jackctl_server_get_parameters_impl.map(|sym| { + let jackctl_server_open_impl = jackctl_server_open_impl.map(|sym| sym.into_raw()); + let jackctl_server_open_impl = jackctl_server_open_impl.map(|sym| { + *sym.deref() + as unsafe extern "C" fn( + server: *mut jackctl_server_t, + driver: *mut jackctl_driver_t, + ) -> u8 + }); + let jackctl_server_start_impl = library + .get:: u8>(b"jackctl_server_start") + .ok(); + let jackctl_server_start_impl = jackctl_server_start_impl.map(|sym| sym.into_raw()); + let jackctl_server_start_impl = jackctl_server_start_impl + .map(|sym| *sym.deref() as unsafe extern "C" fn(server: *mut jackctl_server_t) -> u8); + let jackctl_server_stop_impl = library + .get:: u8>(b"jackctl_server_stop") + .ok(); + let jackctl_server_stop_impl = jackctl_server_stop_impl.map(|sym| sym.into_raw()); + let jackctl_server_stop_impl = jackctl_server_stop_impl + .map(|sym| *sym.deref() as unsafe extern "C" fn(server: *mut jackctl_server_t) -> u8); + let jackctl_server_close_impl = library + .get:: u8>(b"jackctl_server_close") + .ok(); + let jackctl_server_close_impl = jackctl_server_close_impl.map(|sym| sym.into_raw()); + let jackctl_server_close_impl = jackctl_server_close_impl + .map(|sym| *sym.deref() as unsafe extern "C" fn(server: *mut jackctl_server_t) -> u8); + let jackctl_server_get_drivers_list_impl = library + .get:: *const JSList>( + b"jackctl_server_get_drivers_list", + ) + .ok(); + let jackctl_server_get_drivers_list_impl = + jackctl_server_get_drivers_list_impl.map(|sym| sym.into_raw()); + let jackctl_server_get_drivers_list_impl = jackctl_server_get_drivers_list_impl.map(|sym| { + *sym.deref() as unsafe extern "C" fn(server: *mut jackctl_server_t) -> *const JSList + }); + let jackctl_server_get_parameters_impl = library + .get:: *const JSList>( + b"jackctl_server_get_parameters", + ) + .ok(); + let jackctl_server_get_parameters_impl = + jackctl_server_get_parameters_impl.map(|sym| sym.into_raw()); + let jackctl_server_get_parameters_impl = jackctl_server_get_parameters_impl.map(|sym| { + *sym.deref() as unsafe extern "C" fn(server: *mut jackctl_server_t) -> *const JSList + }); + let jackctl_server_get_internals_list_impl = library + .get:: *const JSList>( + b"jackctl_server_get_internals_list", + ) + .ok(); + let jackctl_server_get_internals_list_impl = + jackctl_server_get_internals_list_impl.map(|sym| sym.into_raw()); + let jackctl_server_get_internals_list_impl = + jackctl_server_get_internals_list_impl.map(|sym| { *sym.deref() as unsafe extern "C" fn(server: *mut jackctl_server_t) -> *const JSList }); - let jackctl_server_get_internals_list_impl = library - .get:: *const JSList>( - b"jackctl_server_get_internals_list", - ) - .ok(); - let jackctl_server_get_internals_list_impl = - jackctl_server_get_internals_list_impl.map(|sym| sym.into_raw()); - let jackctl_server_get_internals_list_impl = - jackctl_server_get_internals_list_impl.map(|sym| { - *sym.deref() as unsafe extern "C" fn(server: *mut jackctl_server_t) -> *const JSList - }); - let jackctl_server_load_internal_impl = library + let jackctl_server_load_internal_impl = + library .get:: u8>(b"jackctl_server_load_internal") .ok(); - let jackctl_server_load_internal_impl = - jackctl_server_load_internal_impl.map(|sym| sym.into_raw()); - let jackctl_server_load_internal_impl = jackctl_server_load_internal_impl.map(|sym| { - *sym.deref() - as unsafe extern "C" fn( - server: *mut jackctl_server_t, - internal: *mut jackctl_internal_t, - ) -> u8 - }); - let jackctl_server_unload_internal_impl = library + let jackctl_server_load_internal_impl = + jackctl_server_load_internal_impl.map(|sym| sym.into_raw()); + let jackctl_server_load_internal_impl = jackctl_server_load_internal_impl.map(|sym| { + *sym.deref() + as unsafe extern "C" fn( + server: *mut jackctl_server_t, + internal: *mut jackctl_internal_t, + ) -> u8 + }); + let jackctl_server_unload_internal_impl = + library .get:: u8>(b"jackctl_server_unload_internal") .ok(); - let jackctl_server_unload_internal_impl = - jackctl_server_unload_internal_impl.map(|sym| sym.into_raw()); - let jackctl_server_unload_internal_impl = jackctl_server_unload_internal_impl.map(|sym| { - *sym.deref() - as unsafe extern "C" fn( - server: *mut jackctl_server_t, - internal: *mut jackctl_internal_t, - ) -> u8 - }); - let jackctl_server_add_slave_impl = + let jackctl_server_unload_internal_impl = + jackctl_server_unload_internal_impl.map(|sym| sym.into_raw()); + let jackctl_server_unload_internal_impl = jackctl_server_unload_internal_impl.map(|sym| { + *sym.deref() + as unsafe extern "C" fn( + server: *mut jackctl_server_t, + internal: *mut jackctl_internal_t, + ) -> u8 + }); + let jackctl_server_add_slave_impl = library .get:: u8>(b"jackctl_server_add_slave") .ok(); - let jackctl_server_add_slave_impl = jackctl_server_add_slave_impl.map(|sym| sym.into_raw()); - let jackctl_server_add_slave_impl = jackctl_server_add_slave_impl.map(|sym| { - *sym.deref() - as unsafe extern "C" fn( - server: *mut jackctl_server_t, - driver: *mut jackctl_driver_t, - ) -> u8 - }); - let jackctl_server_remove_slave_impl = + let jackctl_server_add_slave_impl = jackctl_server_add_slave_impl.map(|sym| sym.into_raw()); + let jackctl_server_add_slave_impl = jackctl_server_add_slave_impl.map(|sym| { + *sym.deref() + as unsafe extern "C" fn( + server: *mut jackctl_server_t, + driver: *mut jackctl_driver_t, + ) -> u8 + }); + let jackctl_server_remove_slave_impl = library .get:: u8>(b"jackctl_server_remove_slave") .ok(); - let jackctl_server_remove_slave_impl = - jackctl_server_remove_slave_impl.map(|sym| sym.into_raw()); - let jackctl_server_remove_slave_impl = jackctl_server_remove_slave_impl.map(|sym| { - *sym.deref() - as unsafe extern "C" fn( - server: *mut jackctl_server_t, - driver: *mut jackctl_driver_t, - ) -> u8 - }); - let jackctl_server_switch_master_impl = + let jackctl_server_remove_slave_impl = + jackctl_server_remove_slave_impl.map(|sym| sym.into_raw()); + let jackctl_server_remove_slave_impl = jackctl_server_remove_slave_impl.map(|sym| { + *sym.deref() + as unsafe extern "C" fn( + server: *mut jackctl_server_t, + driver: *mut jackctl_driver_t, + ) -> u8 + }); + let jackctl_server_switch_master_impl = library .get:: u8>(b"jackctl_server_switch_master") .ok(); - let jackctl_server_switch_master_impl = - jackctl_server_switch_master_impl.map(|sym| sym.into_raw()); - let jackctl_server_switch_master_impl = jackctl_server_switch_master_impl.map(|sym| { - *sym.deref() - as unsafe extern "C" fn( - server: *mut jackctl_server_t, - driver: *mut jackctl_driver_t, - ) -> u8 - }); - let jackctl_driver_get_name_impl = library - .get:: *const ::libc::c_char>( - b"jackctl_driver_get_name", - ) - .ok(); - let jackctl_driver_get_name_impl = jackctl_driver_get_name_impl.map(|sym| sym.into_raw()); - let jackctl_driver_get_name_impl = jackctl_driver_get_name_impl.map(|sym| { - *sym.deref() - as unsafe extern "C" fn(driver: *mut jackctl_driver_t) -> *const ::libc::c_char - }); - let jackctl_driver_get_type_impl = library - .get:: jackctl_driver_type_t>( - b"jackctl_driver_get_type", - ) - .ok(); - let jackctl_driver_get_type_impl = jackctl_driver_get_type_impl.map(|sym| sym.into_raw()); - let jackctl_driver_get_type_impl = jackctl_driver_get_type_impl.map(|sym| { - *sym.deref() - as unsafe extern "C" fn(driver: *mut jackctl_driver_t) -> jackctl_driver_type_t - }); - let jackctl_driver_get_parameters_impl = library - .get:: *const JSList>( - b"jackctl_driver_get_parameters", - ) - .ok(); - let jackctl_driver_get_parameters_impl = - jackctl_driver_get_parameters_impl.map(|sym| sym.into_raw()); - let jackctl_driver_get_parameters_impl = jackctl_driver_get_parameters_impl.map(|sym| { - *sym.deref() as unsafe extern "C" fn(driver: *mut jackctl_driver_t) -> *const JSList - }); - let jackctl_driver_params_parse_impl = library - .get:: u8 + }); + let jackctl_driver_get_name_impl = library + .get:: *const ::libc::c_char>( + b"jackctl_driver_get_name", + ) + .ok(); + let jackctl_driver_get_name_impl = jackctl_driver_get_name_impl.map(|sym| sym.into_raw()); + let jackctl_driver_get_name_impl = jackctl_driver_get_name_impl.map(|sym| { + *sym.deref() as unsafe extern "C" fn(driver: *mut jackctl_driver_t) -> *const ::libc::c_char + }); + let jackctl_driver_get_type_impl = library + .get:: jackctl_driver_type_t>( + b"jackctl_driver_get_type", + ) + .ok(); + let jackctl_driver_get_type_impl = jackctl_driver_get_type_impl.map(|sym| sym.into_raw()); + let jackctl_driver_get_type_impl = jackctl_driver_get_type_impl.map(|sym| { + *sym.deref() as unsafe extern "C" fn(driver: *mut jackctl_driver_t) -> jackctl_driver_type_t + }); + let jackctl_driver_get_parameters_impl = library + .get:: *const JSList>( + b"jackctl_driver_get_parameters", + ) + .ok(); + let jackctl_driver_get_parameters_impl = + jackctl_driver_get_parameters_impl.map(|sym| sym.into_raw()); + let jackctl_driver_get_parameters_impl = jackctl_driver_get_parameters_impl.map(|sym| { + *sym.deref() as unsafe extern "C" fn(driver: *mut jackctl_driver_t) -> *const JSList + }); + let jackctl_driver_params_parse_impl = library + .get:: ::libc::c_int>(b"jackctl_driver_params_parse") + .ok(); + let jackctl_driver_params_parse_impl = + jackctl_driver_params_parse_impl.map(|sym| sym.into_raw()); + let jackctl_driver_params_parse_impl = jackctl_driver_params_parse_impl.map(|sym| { + *sym.deref() + as unsafe extern "C" fn( driver: *mut jackctl_driver_t, argc: ::libc::c_int, argv: *mut *mut ::libc::c_char, - ) -> ::libc::c_int>(b"jackctl_driver_params_parse") - .ok(); - let jackctl_driver_params_parse_impl = - jackctl_driver_params_parse_impl.map(|sym| sym.into_raw()); - let jackctl_driver_params_parse_impl = jackctl_driver_params_parse_impl.map(|sym| { + ) -> ::libc::c_int + }); + let jackctl_internal_get_name_impl = library + .get:: *const ::libc::c_char>( + b"jackctl_internal_get_name", + ) + .ok(); + let jackctl_internal_get_name_impl = jackctl_internal_get_name_impl.map(|sym| sym.into_raw()); + let jackctl_internal_get_name_impl = jackctl_internal_get_name_impl.map(|sym| { + *sym.deref() + as unsafe extern "C" fn(internal: *mut jackctl_internal_t) -> *const ::libc::c_char + }); + let jackctl_internal_get_parameters_impl = library + .get:: *const JSList>( + b"jackctl_internal_get_parameters", + ) + .ok(); + let jackctl_internal_get_parameters_impl = + jackctl_internal_get_parameters_impl.map(|sym| sym.into_raw()); + let jackctl_internal_get_parameters_impl = jackctl_internal_get_parameters_impl.map(|sym| { + *sym.deref() as unsafe extern "C" fn(internal: *mut jackctl_internal_t) -> *const JSList + }); + let jackctl_parameter_get_name_impl = library + .get:: *const ::libc::c_char>( + b"jackctl_parameter_get_name", + ) + .ok(); + let jackctl_parameter_get_name_impl = jackctl_parameter_get_name_impl.map(|sym| sym.into_raw()); + let jackctl_parameter_get_name_impl = jackctl_parameter_get_name_impl.map(|sym| { + *sym.deref() + as unsafe extern "C" fn(parameter: *mut jackctl_parameter_t) -> *const ::libc::c_char + }); + let jackctl_parameter_get_short_description_impl = library + .get:: *const ::libc::c_char>( + b"jackctl_parameter_get_short_description", + ) + .ok(); + let jackctl_parameter_get_short_description_impl = + jackctl_parameter_get_short_description_impl.map(|sym| sym.into_raw()); + let jackctl_parameter_get_short_description_impl = jackctl_parameter_get_short_description_impl + .map(|sym| { *sym.deref() as unsafe extern "C" fn( - driver: *mut jackctl_driver_t, - argc: ::libc::c_int, - argv: *mut *mut ::libc::c_char, - ) -> ::libc::c_int - }); - let jackctl_internal_get_name_impl = library.get:: *const ::libc::c_char>(b"jackctl_internal_get_name").ok(); - let jackctl_internal_get_name_impl = - jackctl_internal_get_name_impl.map(|sym| sym.into_raw()); - let jackctl_internal_get_name_impl = jackctl_internal_get_name_impl.map(|sym| { - *sym.deref() - as unsafe extern "C" fn(internal: *mut jackctl_internal_t) -> *const ::libc::c_char + parameter: *mut jackctl_parameter_t, + ) -> *const ::libc::c_char }); - let jackctl_internal_get_parameters_impl = library - .get:: *const JSList>( - b"jackctl_internal_get_parameters", - ) - .ok(); - let jackctl_internal_get_parameters_impl = - jackctl_internal_get_parameters_impl.map(|sym| sym.into_raw()); - let jackctl_internal_get_parameters_impl = - jackctl_internal_get_parameters_impl.map(|sym| { - *sym.deref() - as unsafe extern "C" fn(internal: *mut jackctl_internal_t) -> *const JSList - }); - let jackctl_parameter_get_name_impl = library.get:: *const ::libc::c_char>(b"jackctl_parameter_get_name").ok(); - let jackctl_parameter_get_name_impl = - jackctl_parameter_get_name_impl.map(|sym| sym.into_raw()); - let jackctl_parameter_get_name_impl = jackctl_parameter_get_name_impl.map(|sym| { + let jackctl_parameter_get_long_description_impl = library + .get:: *const ::libc::c_char>( + b"jackctl_parameter_get_long_description", + ) + .ok(); + let jackctl_parameter_get_long_description_impl = + jackctl_parameter_get_long_description_impl.map(|sym| sym.into_raw()); + let jackctl_parameter_get_long_description_impl = jackctl_parameter_get_long_description_impl + .map(|sym| { *sym.deref() as unsafe extern "C" fn( parameter: *mut jackctl_parameter_t, ) -> *const ::libc::c_char }); - let jackctl_parameter_get_short_description_impl = library.get:: *const ::libc::c_char>(b"jackctl_parameter_get_short_description").ok(); - let jackctl_parameter_get_short_description_impl = - jackctl_parameter_get_short_description_impl.map(|sym| sym.into_raw()); - let jackctl_parameter_get_short_description_impl = - jackctl_parameter_get_short_description_impl.map(|sym| { - *sym.deref() - as unsafe extern "C" fn( - parameter: *mut jackctl_parameter_t, - ) -> *const ::libc::c_char - }); - let jackctl_parameter_get_long_description_impl = library.get:: *const ::libc::c_char>(b"jackctl_parameter_get_long_description").ok(); - let jackctl_parameter_get_long_description_impl = - jackctl_parameter_get_long_description_impl.map(|sym| sym.into_raw()); - let jackctl_parameter_get_long_description_impl = - jackctl_parameter_get_long_description_impl.map(|sym| { - *sym.deref() - as unsafe extern "C" fn( - parameter: *mut jackctl_parameter_t, - ) -> *const ::libc::c_char - }); - let jackctl_parameter_get_type_impl = library.get:: jackctl_param_type_t>(b"jackctl_parameter_get_type").ok(); - let jackctl_parameter_get_type_impl = - jackctl_parameter_get_type_impl.map(|sym| sym.into_raw()); - let jackctl_parameter_get_type_impl = jackctl_parameter_get_type_impl.map(|sym| { - *sym.deref() - as unsafe extern "C" fn(parameter: *mut jackctl_parameter_t) -> jackctl_param_type_t - }); - let jackctl_parameter_get_id_impl = library - .get:: ::libc::c_char>( - b"jackctl_parameter_get_id", - ) - .ok(); - let jackctl_parameter_get_id_impl = jackctl_parameter_get_id_impl.map(|sym| sym.into_raw()); - let jackctl_parameter_get_id_impl = jackctl_parameter_get_id_impl.map(|sym| { - *sym.deref() - as unsafe extern "C" fn(parameter: *mut jackctl_parameter_t) -> ::libc::c_char - }); - let jackctl_parameter_is_set_impl = library - .get:: u8>( - b"jackctl_parameter_is_set", - ) - .ok(); - let jackctl_parameter_is_set_impl = jackctl_parameter_is_set_impl.map(|sym| sym.into_raw()); - let jackctl_parameter_is_set_impl = jackctl_parameter_is_set_impl.map(|sym| { - *sym.deref() as unsafe extern "C" fn(parameter: *mut jackctl_parameter_t) -> u8 - }); - let jackctl_parameter_reset_impl = library - .get:: u8>( - b"jackctl_parameter_reset", - ) - .ok(); - let jackctl_parameter_reset_impl = jackctl_parameter_reset_impl.map(|sym| sym.into_raw()); - let jackctl_parameter_reset_impl = jackctl_parameter_reset_impl.map(|sym| { - *sym.deref() as unsafe extern "C" fn(parameter: *mut jackctl_parameter_t) -> u8 - }); - let jackctl_parameter_get_value_impl = library + let jackctl_parameter_get_type_impl = library + .get:: jackctl_param_type_t>( + b"jackctl_parameter_get_type", + ) + .ok(); + let jackctl_parameter_get_type_impl = jackctl_parameter_get_type_impl.map(|sym| sym.into_raw()); + let jackctl_parameter_get_type_impl = jackctl_parameter_get_type_impl.map(|sym| { + *sym.deref() + as unsafe extern "C" fn(parameter: *mut jackctl_parameter_t) -> jackctl_param_type_t + }); + let jackctl_parameter_get_id_impl = library + .get:: ::libc::c_char>( + b"jackctl_parameter_get_id", + ) + .ok(); + let jackctl_parameter_get_id_impl = jackctl_parameter_get_id_impl.map(|sym| sym.into_raw()); + let jackctl_parameter_get_id_impl = jackctl_parameter_get_id_impl.map(|sym| { + *sym.deref() as unsafe extern "C" fn(parameter: *mut jackctl_parameter_t) -> ::libc::c_char + }); + let jackctl_parameter_is_set_impl = library + .get:: u8>( + b"jackctl_parameter_is_set", + ) + .ok(); + let jackctl_parameter_is_set_impl = jackctl_parameter_is_set_impl.map(|sym| sym.into_raw()); + let jackctl_parameter_is_set_impl = jackctl_parameter_is_set_impl + .map(|sym| *sym.deref() as unsafe extern "C" fn(parameter: *mut jackctl_parameter_t) -> u8); + let jackctl_parameter_reset_impl = library + .get:: u8>( + b"jackctl_parameter_reset", + ) + .ok(); + let jackctl_parameter_reset_impl = jackctl_parameter_reset_impl.map(|sym| sym.into_raw()); + let jackctl_parameter_reset_impl = jackctl_parameter_reset_impl + .map(|sym| *sym.deref() as unsafe extern "C" fn(parameter: *mut jackctl_parameter_t) -> u8); + let jackctl_parameter_get_value_impl = + library .get:: Union_jackctl_parameter_value>(b"jackctl_parameter_get_value") .ok(); - let jackctl_parameter_get_value_impl = - jackctl_parameter_get_value_impl.map(|sym| sym.into_raw()); - let jackctl_parameter_get_value_impl = jackctl_parameter_get_value_impl.map(|sym| { + let jackctl_parameter_get_value_impl = + jackctl_parameter_get_value_impl.map(|sym| sym.into_raw()); + let jackctl_parameter_get_value_impl = jackctl_parameter_get_value_impl.map(|sym| { + *sym.deref() + as unsafe extern "C" fn( + parameter: *mut jackctl_parameter_t, + ) -> Union_jackctl_parameter_value + }); + let jackctl_parameter_set_value_impl = library + .get:: u8>(b"jackctl_parameter_set_value") + .ok(); + let jackctl_parameter_set_value_impl = + jackctl_parameter_set_value_impl.map(|sym| sym.into_raw()); + let jackctl_parameter_set_value_impl = jackctl_parameter_set_value_impl.map(|sym| { + *sym.deref() + as unsafe extern "C" fn( + parameter: *mut jackctl_parameter_t, + value_ptr: *const Union_jackctl_parameter_value, + ) -> u8 + }); + let jackctl_parameter_get_default_value_impl = + library + .get:: Union_jackctl_parameter_value>(b"jackctl_parameter_get_default_value") + .ok(); + let jackctl_parameter_get_default_value_impl = + jackctl_parameter_get_default_value_impl.map(|sym| sym.into_raw()); + let jackctl_parameter_get_default_value_impl = + jackctl_parameter_get_default_value_impl.map(|sym| { *sym.deref() as unsafe extern "C" fn( parameter: *mut jackctl_parameter_t, ) -> Union_jackctl_parameter_value }); - let jackctl_parameter_set_value_impl = library - .get:: u8>(b"jackctl_parameter_set_value") - .ok(); - let jackctl_parameter_set_value_impl = - jackctl_parameter_set_value_impl.map(|sym| sym.into_raw()); - let jackctl_parameter_set_value_impl = jackctl_parameter_set_value_impl.map(|sym| { + let jackctl_parameter_has_range_constraint_impl = library + .get:: u8>( + b"jackctl_parameter_has_range_constraint", + ) + .ok(); + let jackctl_parameter_has_range_constraint_impl = + jackctl_parameter_has_range_constraint_impl.map(|sym| sym.into_raw()); + let jackctl_parameter_has_range_constraint_impl = jackctl_parameter_has_range_constraint_impl + .map(|sym| *sym.deref() as unsafe extern "C" fn(parameter: *mut jackctl_parameter_t) -> u8); + let jackctl_parameter_has_enum_constraint_impl = library + .get:: u8>( + b"jackctl_parameter_has_enum_constraint", + ) + .ok(); + let jackctl_parameter_has_enum_constraint_impl = + jackctl_parameter_has_enum_constraint_impl.map(|sym| sym.into_raw()); + let jackctl_parameter_has_enum_constraint_impl = jackctl_parameter_has_enum_constraint_impl + .map(|sym| *sym.deref() as unsafe extern "C" fn(parameter: *mut jackctl_parameter_t) -> u8); + let jackctl_parameter_get_enum_constraints_count_impl = library + .get:: u32>( + b"jackctl_parameter_get_enum_constraints_count", + ) + .ok(); + let jackctl_parameter_get_enum_constraints_count_impl = + jackctl_parameter_get_enum_constraints_count_impl.map(|sym| sym.into_raw()); + let jackctl_parameter_get_enum_constraints_count_impl = + jackctl_parameter_get_enum_constraints_count_impl.map(|sym| { + *sym.deref() as unsafe extern "C" fn(parameter: *mut jackctl_parameter_t) -> u32 + }); + let jackctl_parameter_get_enum_constraint_value_impl = library + .get:: Union_jackctl_parameter_value>(b"jackctl_parameter_get_enum_constraint_value") + .ok(); + let jackctl_parameter_get_enum_constraint_value_impl = + jackctl_parameter_get_enum_constraint_value_impl.map(|sym| sym.into_raw()); + let jackctl_parameter_get_enum_constraint_value_impl = + jackctl_parameter_get_enum_constraint_value_impl.map(|sym| { *sym.deref() as unsafe extern "C" fn( parameter: *mut jackctl_parameter_t, - value_ptr: *const Union_jackctl_parameter_value, - ) -> u8 + index: u32, + ) -> Union_jackctl_parameter_value }); - let jackctl_parameter_get_default_value_impl = library - .get:: Union_jackctl_parameter_value>(b"jackctl_parameter_get_default_value") - .ok(); - let jackctl_parameter_get_default_value_impl = - jackctl_parameter_get_default_value_impl.map(|sym| sym.into_raw()); - let jackctl_parameter_get_default_value_impl = jackctl_parameter_get_default_value_impl - .map(|sym| { - *sym.deref() - as unsafe extern "C" fn( - parameter: *mut jackctl_parameter_t, - ) -> Union_jackctl_parameter_value - }); - let jackctl_parameter_has_range_constraint_impl = library - .get:: u8>( - b"jackctl_parameter_has_range_constraint", - ) - .ok(); - let jackctl_parameter_has_range_constraint_impl = - jackctl_parameter_has_range_constraint_impl.map(|sym| sym.into_raw()); - let jackctl_parameter_has_range_constraint_impl = - jackctl_parameter_has_range_constraint_impl.map(|sym| { - *sym.deref() as unsafe extern "C" fn(parameter: *mut jackctl_parameter_t) -> u8 - }); - let jackctl_parameter_has_enum_constraint_impl = library - .get:: u8>( - b"jackctl_parameter_has_enum_constraint", - ) - .ok(); - let jackctl_parameter_has_enum_constraint_impl = - jackctl_parameter_has_enum_constraint_impl.map(|sym| sym.into_raw()); - let jackctl_parameter_has_enum_constraint_impl = jackctl_parameter_has_enum_constraint_impl - .map(|sym| { - *sym.deref() as unsafe extern "C" fn(parameter: *mut jackctl_parameter_t) -> u8 - }); - let jackctl_parameter_get_enum_constraints_count_impl = library - .get:: u32>( - b"jackctl_parameter_get_enum_constraints_count", - ) - .ok(); - let jackctl_parameter_get_enum_constraints_count_impl = - jackctl_parameter_get_enum_constraints_count_impl.map(|sym| sym.into_raw()); - let jackctl_parameter_get_enum_constraints_count_impl = - jackctl_parameter_get_enum_constraints_count_impl.map(|sym| { - *sym.deref() as unsafe extern "C" fn(parameter: *mut jackctl_parameter_t) -> u32 - }); - let jackctl_parameter_get_enum_constraint_value_impl = library - .get:: Union_jackctl_parameter_value>( - b"jackctl_parameter_get_enum_constraint_value" - ) - .ok(); - let jackctl_parameter_get_enum_constraint_value_impl = - jackctl_parameter_get_enum_constraint_value_impl.map(|sym| sym.into_raw()); - let jackctl_parameter_get_enum_constraint_value_impl = - jackctl_parameter_get_enum_constraint_value_impl.map(|sym| { - *sym.deref() - as unsafe extern "C" fn( - parameter: *mut jackctl_parameter_t, - index: u32, - ) -> Union_jackctl_parameter_value - }); - let jackctl_parameter_get_enum_constraint_description_impl = library - .get:: *const ::libc::c_char>( - b"jackctl_parameter_get_enum_constraint_description" - ) - .ok(); - let jackctl_parameter_get_enum_constraint_description_impl = - jackctl_parameter_get_enum_constraint_description_impl.map(|sym| sym.into_raw()); - let jackctl_parameter_get_enum_constraint_description_impl = - jackctl_parameter_get_enum_constraint_description_impl.map(|sym| { - *sym.deref() - as unsafe extern "C" fn( - parameter: *mut jackctl_parameter_t, - index: u32, - ) -> *const ::libc::c_char - }); - let jackctl_parameter_get_range_constraint_impl = library - .get:: ()>(b"jackctl_parameter_get_range_constraint") - .ok(); - let jackctl_parameter_get_range_constraint_impl = - jackctl_parameter_get_range_constraint_impl.map(|sym| sym.into_raw()); - let jackctl_parameter_get_range_constraint_impl = - jackctl_parameter_get_range_constraint_impl.map(|sym| { - *sym.deref() - as unsafe extern "C" fn( - parameter: *mut jackctl_parameter_t, - min_ptr: *mut Union_jackctl_parameter_value, - max_ptr: *mut Union_jackctl_parameter_value, - ) -> () - }); - let jackctl_parameter_constraint_is_strict_impl = library - .get:: u8>( - b"jackctl_parameter_constraint_is_strict", - ) - .ok(); - let jackctl_parameter_constraint_is_strict_impl = - jackctl_parameter_constraint_is_strict_impl.map(|sym| sym.into_raw()); - let jackctl_parameter_constraint_is_strict_impl = - jackctl_parameter_constraint_is_strict_impl.map(|sym| { - *sym.deref() as unsafe extern "C" fn(parameter: *mut jackctl_parameter_t) -> u8 - }); - let jackctl_parameter_constraint_is_fake_value_impl = library - .get:: u8>( - b"jackctl_parameter_constraint_is_fake_value", - ) - .ok(); - let jackctl_parameter_constraint_is_fake_value_impl = - jackctl_parameter_constraint_is_fake_value_impl.map(|sym| sym.into_raw()); - let jackctl_parameter_constraint_is_fake_value_impl = - jackctl_parameter_constraint_is_fake_value_impl.map(|sym| { - *sym.deref() as unsafe extern "C" fn(parameter: *mut jackctl_parameter_t) -> u8 - }); - let jack_set_property_impl = library - .get:: ::libc::c_int>(b"jack_set_property") - .unwrap(); - let jack_set_property_impl = jack_set_property_impl.into_raw(); - let jack_set_property_impl = *jack_set_property_impl.deref() - as unsafe extern "C" fn( - arg1: *mut jack_client_t, - subject: jack_uuid_t, - key: *const ::libc::c_char, - value: *const ::libc::c_char, - _type: *const ::libc::c_char, - ) -> ::libc::c_int; - let jack_get_property_impl = library - .get:: ::libc::c_int>(b"jack_get_property") - .unwrap(); - let jack_get_property_impl = jack_get_property_impl.into_raw(); - let jack_get_property_impl = *jack_get_property_impl.deref() - as unsafe extern "C" fn( - subject: jack_uuid_t, - key: *const ::libc::c_char, - value: *mut *mut ::libc::c_char, - _type: *mut *mut ::libc::c_char, - ) -> ::libc::c_int; - let jack_free_description_impl = library - .get:: ()>(b"jack_free_description") - .unwrap(); - let jack_free_description_impl = jack_free_description_impl.into_raw(); - let jack_free_description_impl = *jack_free_description_impl.deref() - as unsafe extern "C" fn( - desc: *mut jack_description_t, - free_description_itself: ::libc::c_int, - ) -> (); - let jack_get_properties_impl = library + let jackctl_parameter_get_enum_constraint_description_impl = library + .get:: *const ::libc::c_char>(b"jackctl_parameter_get_enum_constraint_description") + .ok(); + let jackctl_parameter_get_enum_constraint_description_impl = + jackctl_parameter_get_enum_constraint_description_impl.map(|sym| sym.into_raw()); + let jackctl_parameter_get_enum_constraint_description_impl = + jackctl_parameter_get_enum_constraint_description_impl.map(|sym| { + *sym.deref() + as unsafe extern "C" fn( + parameter: *mut jackctl_parameter_t, + index: u32, + ) -> *const ::libc::c_char + }); + let jackctl_parameter_get_range_constraint_impl = library + .get:: ()>(b"jackctl_parameter_get_range_constraint") + .ok(); + let jackctl_parameter_get_range_constraint_impl = + jackctl_parameter_get_range_constraint_impl.map(|sym| sym.into_raw()); + let jackctl_parameter_get_range_constraint_impl = jackctl_parameter_get_range_constraint_impl + .map(|sym| { + *sym.deref() + as unsafe extern "C" fn( + parameter: *mut jackctl_parameter_t, + min_ptr: *mut Union_jackctl_parameter_value, + max_ptr: *mut Union_jackctl_parameter_value, + ) -> () + }); + let jackctl_parameter_constraint_is_strict_impl = library + .get:: u8>( + b"jackctl_parameter_constraint_is_strict", + ) + .ok(); + let jackctl_parameter_constraint_is_strict_impl = + jackctl_parameter_constraint_is_strict_impl.map(|sym| sym.into_raw()); + let jackctl_parameter_constraint_is_strict_impl = jackctl_parameter_constraint_is_strict_impl + .map(|sym| *sym.deref() as unsafe extern "C" fn(parameter: *mut jackctl_parameter_t) -> u8); + let jackctl_parameter_constraint_is_fake_value_impl = library + .get:: u8>( + b"jackctl_parameter_constraint_is_fake_value", + ) + .ok(); + let jackctl_parameter_constraint_is_fake_value_impl = + jackctl_parameter_constraint_is_fake_value_impl.map(|sym| sym.into_raw()); + let jackctl_parameter_constraint_is_fake_value_impl = + jackctl_parameter_constraint_is_fake_value_impl.map(|sym| { + *sym.deref() as unsafe extern "C" fn(parameter: *mut jackctl_parameter_t) -> u8 + }); + let jack_set_property_impl = library + .get:: ::libc::c_int>(b"jack_set_property") + .map_err(|err| err.to_string())?; + let jack_set_property_impl = jack_set_property_impl.into_raw(); + let jack_set_property_impl = *jack_set_property_impl.deref() + as unsafe extern "C" fn( + arg1: *mut jack_client_t, + subject: jack_uuid_t, + key: *const ::libc::c_char, + value: *const ::libc::c_char, + _type: *const ::libc::c_char, + ) -> ::libc::c_int; + let jack_get_property_impl = library + .get:: ::libc::c_int>(b"jack_get_property") + .map_err(|err| err.to_string())?; + let jack_get_property_impl = jack_get_property_impl.into_raw(); + let jack_get_property_impl = *jack_get_property_impl.deref() + as unsafe extern "C" fn( + subject: jack_uuid_t, + key: *const ::libc::c_char, + value: *mut *mut ::libc::c_char, + _type: *mut *mut ::libc::c_char, + ) -> ::libc::c_int; + let jack_free_description_impl = library + .get:: ()>(b"jack_free_description") + .map_err(|err| err.to_string())?; + let jack_free_description_impl = jack_free_description_impl.into_raw(); + let jack_free_description_impl = *jack_free_description_impl.deref() + as unsafe extern "C" fn( + desc: *mut jack_description_t, + free_description_itself: ::libc::c_int, + ) -> (); + let jack_get_properties_impl = + library .get:: ::libc::c_int>(b"jack_get_properties") - .unwrap(); - let jack_get_properties_impl = jack_get_properties_impl.into_raw(); - let jack_get_properties_impl = *jack_get_properties_impl.deref() - as unsafe extern "C" fn( - subject: jack_uuid_t, - desc: *mut jack_description_t, - ) -> ::libc::c_int; - let jack_get_all_properties_impl = library - .get:: ::libc::c_int>( - b"jack_get_all_properties", - ) - .unwrap(); - let jack_get_all_properties_impl = jack_get_all_properties_impl.into_raw(); - let jack_get_all_properties_impl = *jack_get_all_properties_impl.deref() - as unsafe extern "C" fn(descs: *mut *mut jack_description_t) -> ::libc::c_int; - let jack_remove_property_impl = library - .get:: ::libc::c_int>(b"jack_remove_property") - .unwrap(); - let jack_remove_property_impl = jack_remove_property_impl.into_raw(); - let jack_remove_property_impl = *jack_remove_property_impl.deref() - as unsafe extern "C" fn( - client: *mut jack_client_t, - subject: jack_uuid_t, - key: *const ::libc::c_char, - ) -> ::libc::c_int; - let jack_remove_properties_impl = + .map_err(|err| err.to_string())?; + let jack_get_properties_impl = jack_get_properties_impl.into_raw(); + let jack_get_properties_impl = *jack_get_properties_impl.deref() + as unsafe extern "C" fn( + subject: jack_uuid_t, + desc: *mut jack_description_t, + ) -> ::libc::c_int; + let jack_get_all_properties_impl = library + .get:: ::libc::c_int>( + b"jack_get_all_properties", + ) + .map_err(|err| err.to_string())?; + let jack_get_all_properties_impl = jack_get_all_properties_impl.into_raw(); + let jack_get_all_properties_impl = *jack_get_all_properties_impl.deref() + as unsafe extern "C" fn(descs: *mut *mut jack_description_t) -> ::libc::c_int; + let jack_remove_property_impl = library + .get:: ::libc::c_int>(b"jack_remove_property") + .map_err(|err| err.to_string())?; + let jack_remove_property_impl = jack_remove_property_impl.into_raw(); + let jack_remove_property_impl = *jack_remove_property_impl.deref() + as unsafe extern "C" fn( + client: *mut jack_client_t, + subject: jack_uuid_t, + key: *const ::libc::c_char, + ) -> ::libc::c_int; + let jack_remove_properties_impl = library .get:: ::libc::c_int>(b"jack_remove_properties") - .unwrap(); - let jack_remove_properties_impl = jack_remove_properties_impl.into_raw(); - let jack_remove_properties_impl = *jack_remove_properties_impl.deref() - as unsafe extern "C" fn( - client: *mut jack_client_t, - subject: jack_uuid_t, - ) -> ::libc::c_int; - let jack_remove_all_properties_impl = library - .get:: ::libc::c_int>( - b"jack_remove_all_properties", - ) - .unwrap(); - let jack_remove_all_properties_impl = jack_remove_all_properties_impl.into_raw(); - let jack_remove_all_properties_impl = *jack_remove_all_properties_impl.deref() - as unsafe extern "C" fn(client: *mut jack_client_t) -> ::libc::c_int; - let jack_set_property_change_callback_impl = library - .get:: ::libc::c_int>(b"jack_set_property_change_callback") - .unwrap(); - let jack_set_property_change_callback_impl = - jack_set_property_change_callback_impl.into_raw(); - let jack_set_property_change_callback_impl = *jack_set_property_change_callback_impl.deref() + .map_err(|err| err.to_string())?; + let jack_remove_properties_impl = jack_remove_properties_impl.into_raw(); + let jack_remove_properties_impl = *jack_remove_properties_impl.deref() + as unsafe extern "C" fn(client: *mut jack_client_t, subject: jack_uuid_t) -> ::libc::c_int; + let jack_remove_all_properties_impl = library + .get:: ::libc::c_int>( + b"jack_remove_all_properties", + ) + .map_err(|err| err.to_string())?; + let jack_remove_all_properties_impl = jack_remove_all_properties_impl.into_raw(); + let jack_remove_all_properties_impl = *jack_remove_all_properties_impl.deref() + as unsafe extern "C" fn(client: *mut jack_client_t) -> ::libc::c_int; + let jack_set_property_change_callback_impl = library + .get:: ::libc::c_int>(b"jack_set_property_change_callback") + .map_err(|err| err.to_string())?; + let jack_set_property_change_callback_impl = jack_set_property_change_callback_impl.into_raw(); + let jack_set_property_change_callback_impl = *jack_set_property_change_callback_impl.deref() + as unsafe extern "C" fn( + client: *mut jack_client_t, + callback: JackPropertyChangeCallback, + arg: *mut ::libc::c_void, + ) -> ::libc::c_int; + let jack_get_internal_client_name_impl = library + .get:: *mut ::libc::c_char>(b"jack_get_internal_client_name") + .ok(); + let jack_get_internal_client_name_impl = + jack_get_internal_client_name_impl.map(|sym| sym.into_raw()); + let jack_get_internal_client_name_impl = jack_get_internal_client_name_impl.map(|sym| { + *sym.deref() as unsafe extern "C" fn( - client: *mut jack_client_t, - callback: JackPropertyChangeCallback, - arg: *mut ::libc::c_void, - ) -> ::libc::c_int; - let jack_get_internal_client_name_impl = library - .get:: *mut ::libc::c_char>(b"jack_get_internal_client_name") - .ok(); - let jack_get_internal_client_name_impl = - jack_get_internal_client_name_impl.map(|sym| sym.into_raw()); - let jack_get_internal_client_name_impl = jack_get_internal_client_name_impl.map(|sym| { - *sym.deref() - as unsafe extern "C" fn( - client: *mut jack_client_t, - intclient: jack_intclient_t, - ) -> *mut ::libc::c_char - }); - let jack_internal_client_handle_impl = library - .get:: *mut ::libc::c_char + }); + let jack_internal_client_handle_impl = library + .get:: jack_intclient_t>(b"jack_internal_client_handle") + .ok(); + let jack_internal_client_handle_impl = + jack_internal_client_handle_impl.map(|sym| sym.into_raw()); + let jack_internal_client_handle_impl = jack_internal_client_handle_impl.map(|sym| { + *sym.deref() + as unsafe extern "C" fn( client: *mut jack_client_t, client_name: *const ::libc::c_char, status: *mut jack_status_t, - ) -> jack_intclient_t>(b"jack_internal_client_handle") - .ok(); - let jack_internal_client_handle_impl = - jack_internal_client_handle_impl.map(|sym| sym.into_raw()); - let jack_internal_client_handle_impl = jack_internal_client_handle_impl.map(|sym| { - *sym.deref() - as unsafe extern "C" fn( - client: *mut jack_client_t, - client_name: *const ::libc::c_char, - status: *mut jack_status_t, - ) -> jack_intclient_t - }); - let jack_internal_client_load_impl = library - .get:: jack_intclient_t + }); + let jack_internal_client_load_impl = library + .get:: jack_intclient_t>(b"jack_internal_client_load") + .ok(); + let jack_internal_client_load_impl = jack_internal_client_load_impl.map(|sym| sym.into_raw()); + let jack_internal_client_load_impl = jack_internal_client_load_impl.map(|sym| { + *sym.deref() + as unsafe extern "C" fn( client: *mut jack_client_t, client_name: *const ::libc::c_char, options: jack_options_t, status: *mut jack_status_t, - load_name: *const ::libc::c_char, - load_init: *const ::libc::c_char, - ) -> jack_intclient_t>(b"jack_internal_client_load") - .ok(); - let jack_internal_client_load_impl = - jack_internal_client_load_impl.map(|sym| sym.into_raw()); - let jack_internal_client_load_impl = jack_internal_client_load_impl.map(|sym| { - *sym.deref() - as unsafe extern "C" fn( - client: *mut jack_client_t, - client_name: *const ::libc::c_char, - options: jack_options_t, - status: *mut jack_status_t, - load_name: *const ::libc::c_char, - load_init: *const ::libc::c_char, - ) -> jack_intclient_t - }); - let jack_internal_client_unload_impl = library - .get:: jack_intclient_t + }); + let jack_internal_client_unload_impl = library + .get:: jack_status_t>(b"jack_internal_client_unload") + .ok(); + let jack_internal_client_unload_impl = + jack_internal_client_unload_impl.map(|sym| sym.into_raw()); + let jack_internal_client_unload_impl = jack_internal_client_unload_impl.map(|sym| { + *sym.deref() + as unsafe extern "C" fn( client: *mut jack_client_t, intclient: jack_intclient_t, - ) -> jack_status_t>(b"jack_internal_client_unload") - .ok(); - let jack_internal_client_unload_impl = - jack_internal_client_unload_impl.map(|sym| sym.into_raw()); - let jack_internal_client_unload_impl = jack_internal_client_unload_impl.map(|sym| { - *sym.deref() - as unsafe extern "C" fn( - client: *mut jack_client_t, - intclient: jack_intclient_t, - ) -> jack_status_t - }); - let jack_get_max_delayed_usecs_impl = library - .get:: ::libc::c_float>( - b"jack_get_max_delayed_usecs", - ) - .unwrap(); - let jack_get_max_delayed_usecs_impl = jack_get_max_delayed_usecs_impl.into_raw(); - let jack_get_max_delayed_usecs_impl = *jack_get_max_delayed_usecs_impl.deref() - as unsafe extern "C" fn(client: *mut jack_client_t) -> ::libc::c_float; - let jack_get_xrun_delayed_usecs_impl = library - .get:: ::libc::c_float>( - b"jack_get_xrun_delayed_usecs", - ) - .unwrap(); - let jack_get_xrun_delayed_usecs_impl = jack_get_xrun_delayed_usecs_impl.into_raw(); - let jack_get_xrun_delayed_usecs_impl = *jack_get_xrun_delayed_usecs_impl.deref() - as unsafe extern "C" fn(client: *mut jack_client_t) -> ::libc::c_float; - let jack_reset_max_delayed_usecs_impl = library - .get:: ()>( - b"jack_reset_max_delayed_usecs", - ) - .unwrap(); - let jack_reset_max_delayed_usecs_impl = jack_reset_max_delayed_usecs_impl.into_raw(); - let jack_reset_max_delayed_usecs_impl = *jack_reset_max_delayed_usecs_impl.deref() - as unsafe extern "C" fn(client: *mut jack_client_t) -> (); - let jack_midi_get_event_count_impl = library - .get:: u32>( - b"jack_midi_get_event_count", - ) - .unwrap(); - let jack_midi_get_event_count_impl = jack_midi_get_event_count_impl.into_raw(); - let jack_midi_get_event_count_impl = *jack_midi_get_event_count_impl.deref() - as unsafe extern "C" fn(port_buffer: *mut ::libc::c_void) -> u32; - let jack_midi_event_get_impl = library - .get:: ::libc::c_int>(b"jack_midi_event_get") - .unwrap(); - let jack_midi_event_get_impl = jack_midi_event_get_impl.into_raw(); - let jack_midi_event_get_impl = *jack_midi_event_get_impl.deref() - as unsafe extern "C" fn( - event: *mut jack_midi_event_t, - port_buffer: *mut ::libc::c_void, - event_index: u32, - ) -> ::libc::c_int; - let jack_midi_clear_buffer_impl = library - .get:: ()>( - b"jack_midi_clear_buffer", - ) - .unwrap(); - let jack_midi_clear_buffer_impl = jack_midi_clear_buffer_impl.into_raw(); - let jack_midi_clear_buffer_impl = *jack_midi_clear_buffer_impl.deref() - as unsafe extern "C" fn(port_buffer: *mut ::libc::c_void) -> (); - let jack_midi_max_event_size_impl = library - .get:: ::libc::size_t>( - b"jack_midi_max_event_size", - ) - .unwrap(); - let jack_midi_max_event_size_impl = jack_midi_max_event_size_impl.into_raw(); - let jack_midi_max_event_size_impl = *jack_midi_max_event_size_impl.deref() - as unsafe extern "C" fn(port_buffer: *mut ::libc::c_void) -> ::libc::size_t; - let jack_midi_event_reserve_impl = library - .get:: *mut jack_midi_data_t>(b"jack_midi_event_reserve") - .unwrap(); - let jack_midi_event_reserve_impl = jack_midi_event_reserve_impl.into_raw(); - let jack_midi_event_reserve_impl = *jack_midi_event_reserve_impl.deref() - as unsafe extern "C" fn( - port_buffer: *mut ::libc::c_void, - time: jack_nframes_t, - data_size: ::libc::size_t, - ) -> *mut jack_midi_data_t; - let jack_midi_event_write_impl = library - .get:: ::libc::c_int>(b"jack_midi_event_write") - .unwrap(); - let jack_midi_event_write_impl = jack_midi_event_write_impl.into_raw(); - let jack_midi_event_write_impl = *jack_midi_event_write_impl.deref() - as unsafe extern "C" fn( - port_buffer: *mut ::libc::c_void, - time: jack_nframes_t, - data: *const jack_midi_data_t, - data_size: ::libc::size_t, - ) -> ::libc::c_int; - let jack_midi_get_lost_event_count_impl = library - .get:: u32>( - b"jack_midi_get_lost_event_count", - ) - .unwrap(); - let jack_midi_get_lost_event_count_impl = jack_midi_get_lost_event_count_impl.into_raw(); - let jack_midi_get_lost_event_count_impl = *jack_midi_get_lost_event_count_impl.deref() - as unsafe extern "C" fn(port_buffer: *mut ::libc::c_void) -> u32; - let jack_ringbuffer_create_impl = library - .get:: *mut jack_ringbuffer_t>( - b"jack_ringbuffer_create", - ) - .unwrap(); - let jack_ringbuffer_create_impl = jack_ringbuffer_create_impl.into_raw(); - let jack_ringbuffer_create_impl = *jack_ringbuffer_create_impl.deref() - as unsafe extern "C" fn(sz: ::libc::size_t) -> *mut jack_ringbuffer_t; - let jack_ringbuffer_free_impl = library - .get:: ()>(b"jack_ringbuffer_free") - .unwrap(); - let jack_ringbuffer_free_impl = jack_ringbuffer_free_impl.into_raw(); - let jack_ringbuffer_free_impl = *jack_ringbuffer_free_impl.deref() - as unsafe extern "C" fn(rb: *mut jack_ringbuffer_t) -> (); - let jack_ringbuffer_get_read_vector_impl = library + ) -> jack_status_t + }); + let jack_get_max_delayed_usecs_impl = library + .get:: ::libc::c_float>( + b"jack_get_max_delayed_usecs", + ) + .map_err(|err| err.to_string())?; + let jack_get_max_delayed_usecs_impl = jack_get_max_delayed_usecs_impl.into_raw(); + let jack_get_max_delayed_usecs_impl = *jack_get_max_delayed_usecs_impl.deref() + as unsafe extern "C" fn(client: *mut jack_client_t) -> ::libc::c_float; + let jack_get_xrun_delayed_usecs_impl = library + .get:: ::libc::c_float>( + b"jack_get_xrun_delayed_usecs", + ) + .map_err(|err| err.to_string())?; + let jack_get_xrun_delayed_usecs_impl = jack_get_xrun_delayed_usecs_impl.into_raw(); + let jack_get_xrun_delayed_usecs_impl = *jack_get_xrun_delayed_usecs_impl.deref() + as unsafe extern "C" fn(client: *mut jack_client_t) -> ::libc::c_float; + let jack_reset_max_delayed_usecs_impl = library + .get:: ()>( + b"jack_reset_max_delayed_usecs", + ) + .map_err(|err| err.to_string())?; + let jack_reset_max_delayed_usecs_impl = jack_reset_max_delayed_usecs_impl.into_raw(); + let jack_reset_max_delayed_usecs_impl = *jack_reset_max_delayed_usecs_impl.deref() + as unsafe extern "C" fn(client: *mut jack_client_t) -> (); + let jack_midi_get_event_count_impl = library + .get:: u32>( + b"jack_midi_get_event_count", + ) + .map_err(|err| err.to_string())?; + let jack_midi_get_event_count_impl = jack_midi_get_event_count_impl.into_raw(); + let jack_midi_get_event_count_impl = *jack_midi_get_event_count_impl.deref() + as unsafe extern "C" fn(port_buffer: *mut ::libc::c_void) -> u32; + let jack_midi_event_get_impl = library + .get:: ::libc::c_int>(b"jack_midi_event_get") + .map_err(|err| err.to_string())?; + let jack_midi_event_get_impl = jack_midi_event_get_impl.into_raw(); + let jack_midi_event_get_impl = *jack_midi_event_get_impl.deref() + as unsafe extern "C" fn( + event: *mut jack_midi_event_t, + port_buffer: *mut ::libc::c_void, + event_index: u32, + ) -> ::libc::c_int; + let jack_midi_clear_buffer_impl = library + .get:: ()>( + b"jack_midi_clear_buffer", + ) + .map_err(|err| err.to_string())?; + let jack_midi_clear_buffer_impl = jack_midi_clear_buffer_impl.into_raw(); + let jack_midi_clear_buffer_impl = *jack_midi_clear_buffer_impl.deref() + as unsafe extern "C" fn(port_buffer: *mut ::libc::c_void) -> (); + let jack_midi_max_event_size_impl = library + .get:: ::libc::size_t>( + b"jack_midi_max_event_size", + ) + .map_err(|err| err.to_string())?; + let jack_midi_max_event_size_impl = jack_midi_max_event_size_impl.into_raw(); + let jack_midi_max_event_size_impl = *jack_midi_max_event_size_impl.deref() + as unsafe extern "C" fn(port_buffer: *mut ::libc::c_void) -> ::libc::size_t; + let jack_midi_event_reserve_impl = library + .get:: *mut jack_midi_data_t>(b"jack_midi_event_reserve") + .map_err(|err| err.to_string())?; + let jack_midi_event_reserve_impl = jack_midi_event_reserve_impl.into_raw(); + let jack_midi_event_reserve_impl = *jack_midi_event_reserve_impl.deref() + as unsafe extern "C" fn( + port_buffer: *mut ::libc::c_void, + time: jack_nframes_t, + data_size: ::libc::size_t, + ) -> *mut jack_midi_data_t; + let jack_midi_event_write_impl = library + .get:: ::libc::c_int>(b"jack_midi_event_write") + .map_err(|err| err.to_string())?; + let jack_midi_event_write_impl = jack_midi_event_write_impl.into_raw(); + let jack_midi_event_write_impl = *jack_midi_event_write_impl.deref() + as unsafe extern "C" fn( + port_buffer: *mut ::libc::c_void, + time: jack_nframes_t, + data: *const jack_midi_data_t, + data_size: ::libc::size_t, + ) -> ::libc::c_int; + let jack_midi_get_lost_event_count_impl = library + .get:: u32>( + b"jack_midi_get_lost_event_count", + ) + .map_err(|err| err.to_string())?; + let jack_midi_get_lost_event_count_impl = jack_midi_get_lost_event_count_impl.into_raw(); + let jack_midi_get_lost_event_count_impl = *jack_midi_get_lost_event_count_impl.deref() + as unsafe extern "C" fn(port_buffer: *mut ::libc::c_void) -> u32; + let jack_ringbuffer_create_impl = library + .get:: *mut jack_ringbuffer_t>( + b"jack_ringbuffer_create", + ) + .map_err(|err| err.to_string())?; + let jack_ringbuffer_create_impl = jack_ringbuffer_create_impl.into_raw(); + let jack_ringbuffer_create_impl = *jack_ringbuffer_create_impl.deref() + as unsafe extern "C" fn(sz: ::libc::size_t) -> *mut jack_ringbuffer_t; + let jack_ringbuffer_free_impl = library + .get:: ()>(b"jack_ringbuffer_free") + .map_err(|err| err.to_string())?; + let jack_ringbuffer_free_impl = jack_ringbuffer_free_impl.into_raw(); + let jack_ringbuffer_free_impl = *jack_ringbuffer_free_impl.deref() + as unsafe extern "C" fn(rb: *mut jack_ringbuffer_t) -> (); + let jack_ringbuffer_get_read_vector_impl = + library .get:: ()>(b"jack_ringbuffer_get_read_vector") - .unwrap(); - let jack_ringbuffer_get_read_vector_impl = jack_ringbuffer_get_read_vector_impl.into_raw(); - let jack_ringbuffer_get_read_vector_impl = *jack_ringbuffer_get_read_vector_impl.deref() - as unsafe extern "C" fn( - rb: *const jack_ringbuffer_t, - vec: *mut jack_ringbuffer_data_t, - ) -> (); - let jack_ringbuffer_get_write_vector_impl = library + .map_err(|err| err.to_string())?; + let jack_ringbuffer_get_read_vector_impl = jack_ringbuffer_get_read_vector_impl.into_raw(); + let jack_ringbuffer_get_read_vector_impl = *jack_ringbuffer_get_read_vector_impl.deref() + as unsafe extern "C" fn( + rb: *const jack_ringbuffer_t, + vec: *mut jack_ringbuffer_data_t, + ) -> (); + let jack_ringbuffer_get_write_vector_impl = + library .get:: ()>(b"jack_ringbuffer_get_write_vector") - .unwrap(); - let jack_ringbuffer_get_write_vector_impl = - jack_ringbuffer_get_write_vector_impl.into_raw(); - let jack_ringbuffer_get_write_vector_impl = *jack_ringbuffer_get_write_vector_impl.deref() - as unsafe extern "C" fn( - rb: *const jack_ringbuffer_t, - vec: *mut jack_ringbuffer_data_t, - ) -> (); - let jack_ringbuffer_read_impl = library - .get:: ::libc::size_t>(b"jack_ringbuffer_read") - .unwrap(); - let jack_ringbuffer_read_impl = jack_ringbuffer_read_impl.into_raw(); - let jack_ringbuffer_read_impl = *jack_ringbuffer_read_impl.deref() - as unsafe extern "C" fn( - rb: *mut jack_ringbuffer_t, - dest: *mut ::libc::c_char, - cnt: ::libc::size_t, - ) -> ::libc::size_t; - let jack_ringbuffer_peek_impl = library - .get:: ::libc::size_t>(b"jack_ringbuffer_peek") - .unwrap(); - let jack_ringbuffer_peek_impl = jack_ringbuffer_peek_impl.into_raw(); - let jack_ringbuffer_peek_impl = *jack_ringbuffer_peek_impl.deref() - as unsafe extern "C" fn( - rb: *mut jack_ringbuffer_t, - dest: *mut ::libc::c_char, - cnt: ::libc::size_t, - ) -> ::libc::size_t; - let jack_ringbuffer_read_advance_impl = library - .get:: ()>( - b"jack_ringbuffer_read_advance", - ) - .unwrap(); - let jack_ringbuffer_read_advance_impl = jack_ringbuffer_read_advance_impl.into_raw(); - let jack_ringbuffer_read_advance_impl = *jack_ringbuffer_read_advance_impl.deref() - as unsafe extern "C" fn(rb: *mut jack_ringbuffer_t, cnt: ::libc::size_t) -> (); - let jack_ringbuffer_read_space_impl = library - .get:: ::libc::size_t>( - b"jack_ringbuffer_read_space", - ) - .unwrap(); - let jack_ringbuffer_read_space_impl = jack_ringbuffer_read_space_impl.into_raw(); - let jack_ringbuffer_read_space_impl = *jack_ringbuffer_read_space_impl.deref() - as unsafe extern "C" fn(rb: *const jack_ringbuffer_t) -> ::libc::size_t; - let jack_ringbuffer_mlock_impl = library - .get:: ::libc::c_int>( - b"jack_ringbuffer_mlock", - ) - .unwrap(); - let jack_ringbuffer_mlock_impl = jack_ringbuffer_mlock_impl.into_raw(); - let jack_ringbuffer_mlock_impl = *jack_ringbuffer_mlock_impl.deref() - as unsafe extern "C" fn(rb: *mut jack_ringbuffer_t) -> ::libc::c_int; - let jack_ringbuffer_reset_impl = library - .get:: ()>(b"jack_ringbuffer_reset") - .unwrap(); - let jack_ringbuffer_reset_impl = jack_ringbuffer_reset_impl.into_raw(); - let jack_ringbuffer_reset_impl = *jack_ringbuffer_reset_impl.deref() - as unsafe extern "C" fn(rb: *mut jack_ringbuffer_t) -> (); - let jack_ringbuffer_write_impl = library - .get:: ::libc::size_t>(b"jack_ringbuffer_write") - .unwrap(); - let jack_ringbuffer_write_impl = jack_ringbuffer_write_impl.into_raw(); - let jack_ringbuffer_write_impl = *jack_ringbuffer_write_impl.deref() - as unsafe extern "C" fn( - rb: *mut jack_ringbuffer_t, - src: *const ::libc::c_char, - cnt: ::libc::size_t, - ) -> ::libc::size_t; - let jack_ringbuffer_write_advance_impl = library - .get:: ()>( - b"jack_ringbuffer_write_advance", - ) - .unwrap(); - let jack_ringbuffer_write_advance_impl = jack_ringbuffer_write_advance_impl.into_raw(); - let jack_ringbuffer_write_advance_impl = *jack_ringbuffer_write_advance_impl.deref() - as unsafe extern "C" fn(rb: *mut jack_ringbuffer_t, cnt: ::libc::size_t) -> (); - let jack_ringbuffer_write_space_impl = library - .get:: ::libc::size_t>( - b"jack_ringbuffer_write_space", - ) - .unwrap(); - let jack_ringbuffer_write_space_impl = jack_ringbuffer_write_space_impl.into_raw(); - let jack_ringbuffer_write_space_impl = *jack_ringbuffer_write_space_impl.deref() - as unsafe extern "C" fn(rb: *const jack_ringbuffer_t) -> ::libc::size_t; - let jack_uuid_to_index_impl = library - .get:: u32>(b"jack_uuid_to_index") - .unwrap(); - let jack_uuid_to_index_impl = jack_uuid_to_index_impl.into_raw(); - let jack_uuid_to_index_impl = - *jack_uuid_to_index_impl.deref() as unsafe extern "C" fn(arg1: jack_uuid_t) -> u32; - let jack_uuid_compare_impl = library.get:: ::std::os::raw::c_int>(b"jack_uuid_compare").unwrap(); - let jack_uuid_compare_impl = jack_uuid_compare_impl.into_raw(); - let jack_uuid_compare_impl = *jack_uuid_compare_impl.deref() - as unsafe extern "C" fn(arg1: jack_uuid_t, arg2: jack_uuid_t) -> ::std::os::raw::c_int; - let jack_uuid_copy_impl = library - .get:: ()>( - b"jack_uuid_copy", - ) - .unwrap(); - let jack_uuid_copy_impl = jack_uuid_copy_impl.into_raw(); - let jack_uuid_copy_impl = *jack_uuid_copy_impl.deref() - as unsafe extern "C" fn(dst: *mut jack_uuid_t, src: jack_uuid_t) -> (); - let jack_uuid_clear_impl = library - .get:: ()>(b"jack_uuid_clear") - .unwrap(); - let jack_uuid_clear_impl = jack_uuid_clear_impl.into_raw(); - let jack_uuid_clear_impl = - *jack_uuid_clear_impl.deref() as unsafe extern "C" fn(arg1: *mut jack_uuid_t) -> (); - let jack_uuid_parse_impl = library - .get:: ::std::os::raw::c_int>(b"jack_uuid_parse") - .unwrap(); - let jack_uuid_parse_impl = jack_uuid_parse_impl.into_raw(); - let jack_uuid_parse_impl = *jack_uuid_parse_impl.deref() - as unsafe extern "C" fn( - buf: *const ::std::os::raw::c_char, - arg1: *mut jack_uuid_t, - ) -> ::std::os::raw::c_int; - let jack_uuid_unparse_impl = library - .get:: ()>( - b"jack_uuid_unparse", - ) - .unwrap(); - let jack_uuid_unparse_impl = jack_uuid_unparse_impl.into_raw(); - let jack_uuid_unparse_impl = *jack_uuid_unparse_impl.deref() - as unsafe extern "C" fn(arg1: jack_uuid_t, buf: *mut ::std::os::raw::c_char) -> (); - let jack_uuid_empty_impl = library - .get:: ::std::os::raw::c_int>( - b"jack_uuid_empty", - ) - .unwrap(); - let jack_uuid_empty_impl = jack_uuid_empty_impl.into_raw(); - let jack_uuid_empty_impl = *jack_uuid_empty_impl.deref() - as unsafe extern "C" fn(arg1: jack_uuid_t) -> ::std::os::raw::c_int; - JackFunctions { - jack_release_timebase_impl, - jack_get_cycle_times_impl, - jack_set_sync_callback_impl, - jack_set_sync_timeout_impl, - jack_set_timebase_callback_impl, - jack_transport_locate_impl, - jack_transport_query_impl, - jack_get_current_transport_frame_impl, - jack_transport_reposition_impl, - jack_transport_start_impl, - jack_transport_stop_impl, - jack_get_transport_info_impl, - jack_set_transport_info_impl, - jack_client_open_impl, - jack_client_new_impl, - jack_client_close_impl, - jack_client_name_size_impl, - jack_get_client_name_impl, - jack_get_uuid_for_client_name_impl, - jack_get_client_name_by_uuid_impl, - jack_internal_client_new_impl, - jack_internal_client_close_impl, - jack_activate_impl, - jack_deactivate_impl, - jack_get_client_pid_impl, - jack_is_realtime_impl, - jack_thread_wait_impl, - jack_cycle_wait_impl, - jack_cycle_signal_impl, - jack_set_process_thread_impl, - jack_set_thread_init_callback_impl, - jack_on_shutdown_impl, - jack_on_info_shutdown_impl, - jack_set_process_callback_impl, - jack_set_freewheel_callback_impl, - jack_set_buffer_size_callback_impl, - jack_get_sample_rate_impl, - jack_set_sample_rate_callback_impl, - jack_set_client_registration_callback_impl, - jack_set_port_registration_callback_impl, - jack_set_port_connect_callback_impl, - jack_set_port_rename_callback_impl, - jack_set_graph_order_callback_impl, - jack_set_xrun_callback_impl, - jack_set_latency_callback_impl, - jack_set_freewheel_impl, - jack_set_buffer_size_impl, - jack_get_buffer_size_impl, - jack_engine_takeover_timebase_impl, - jack_cpu_load_impl, - jack_port_register_impl, - jack_port_unregister_impl, - jack_port_get_buffer_impl, - jack_port_uuid_impl, - jack_port_name_impl, - jack_port_short_name_impl, - jack_port_flags_impl, - jack_port_type_impl, - jack_port_type_id_impl, - jack_port_is_mine_impl, - jack_port_connected_impl, - jack_port_connected_to_impl, - jack_port_get_connections_impl, - jack_port_get_all_connections_impl, - jack_port_tie_impl, - jack_port_untie_impl, - jack_port_set_name_impl, - jack_port_set_alias_impl, - jack_port_unset_alias_impl, - jack_port_get_aliases_impl, - jack_port_request_monitor_impl, - jack_port_request_monitor_by_name_impl, - jack_port_ensure_monitor_impl, - jack_port_monitoring_input_impl, - jack_connect_impl, - jack_disconnect_impl, - jack_port_disconnect_impl, - jack_port_name_size_impl, - jack_port_type_size_impl, - jack_port_type_get_buffer_size_impl, - jack_port_set_latency_impl, - jack_port_get_latency_range_impl, - jack_port_set_latency_range_impl, - jack_recompute_total_latencies_impl, - jack_port_get_latency_impl, - jack_port_get_total_latency_impl, - jack_recompute_total_latency_impl, - jack_get_ports_impl, - jack_port_by_name_impl, - jack_port_by_id_impl, - jack_frames_since_cycle_start_impl, - jack_frame_time_impl, - jack_last_frame_time_impl, - jack_frames_to_time_impl, - jack_time_to_frames_impl, - jack_get_time_impl, - jack_set_error_function_impl, - jack_set_info_function_impl, - jack_free_impl, - jack_client_real_time_priority_impl, - jack_client_max_real_time_priority_impl, - jack_set_session_callback_impl, - jack_session_reply_impl, - jack_session_event_free_impl, - jack_client_get_uuid_impl, - jack_session_notify_impl, - jack_session_commands_free_impl, - jack_reserve_client_name_impl, - jack_client_has_session_callback_impl, - jackctl_setup_signals_impl, - jackctl_wait_signals_impl, - jackctl_server_create_impl, - jackctl_server_destroy_impl, - jackctl_server_open_impl, - jackctl_server_start_impl, - jackctl_server_stop_impl, - jackctl_server_close_impl, - jackctl_server_get_drivers_list_impl, - jackctl_server_get_parameters_impl, - jackctl_server_get_internals_list_impl, - jackctl_server_load_internal_impl, - jackctl_server_unload_internal_impl, - jackctl_server_add_slave_impl, - jackctl_server_remove_slave_impl, - jackctl_server_switch_master_impl, - jackctl_driver_get_name_impl, - jackctl_driver_get_type_impl, - jackctl_driver_get_parameters_impl, - jackctl_driver_params_parse_impl, - jackctl_internal_get_name_impl, - jackctl_internal_get_parameters_impl, - jackctl_parameter_get_name_impl, - jackctl_parameter_get_short_description_impl, - jackctl_parameter_get_long_description_impl, - jackctl_parameter_get_type_impl, - jackctl_parameter_get_id_impl, - jackctl_parameter_is_set_impl, - jackctl_parameter_reset_impl, - jackctl_parameter_get_value_impl, - jackctl_parameter_set_value_impl, - jackctl_parameter_get_default_value_impl, - jackctl_parameter_has_range_constraint_impl, - jackctl_parameter_has_enum_constraint_impl, - jackctl_parameter_get_enum_constraints_count_impl, - jackctl_parameter_get_enum_constraint_value_impl, - jackctl_parameter_get_enum_constraint_description_impl, - jackctl_parameter_get_range_constraint_impl, - jackctl_parameter_constraint_is_strict_impl, - jackctl_parameter_constraint_is_fake_value_impl, - jack_set_property_impl, - jack_get_property_impl, - jack_free_description_impl, - jack_get_properties_impl, - jack_get_all_properties_impl, - jack_remove_property_impl, - jack_remove_properties_impl, - jack_remove_all_properties_impl, - jack_set_property_change_callback_impl, - jack_get_internal_client_name_impl, - jack_internal_client_handle_impl, - jack_internal_client_load_impl, - jack_internal_client_unload_impl, - jack_get_max_delayed_usecs_impl, - jack_get_xrun_delayed_usecs_impl, - jack_reset_max_delayed_usecs_impl, - jack_midi_get_event_count_impl, - jack_midi_event_get_impl, - jack_midi_clear_buffer_impl, - jack_midi_max_event_size_impl, - jack_midi_event_reserve_impl, - jack_midi_event_write_impl, - jack_midi_get_lost_event_count_impl, - jack_ringbuffer_create_impl, - jack_ringbuffer_free_impl, - jack_ringbuffer_get_read_vector_impl, - jack_ringbuffer_get_write_vector_impl, - jack_ringbuffer_read_impl, - jack_ringbuffer_peek_impl, - jack_ringbuffer_read_advance_impl, - jack_ringbuffer_read_space_impl, - jack_ringbuffer_mlock_impl, - jack_ringbuffer_reset_impl, - jack_ringbuffer_write_impl, - jack_ringbuffer_write_advance_impl, - jack_ringbuffer_write_space_impl, - jack_uuid_to_index_impl, - jack_uuid_compare_impl, - jack_uuid_copy_impl, - jack_uuid_clear_impl, - jack_uuid_parse_impl, - jack_uuid_unparse_impl, - jack_uuid_empty_impl, - } - }; + .map_err(|err| err.to_string())?; + let jack_ringbuffer_get_write_vector_impl = jack_ringbuffer_get_write_vector_impl.into_raw(); + let jack_ringbuffer_get_write_vector_impl = *jack_ringbuffer_get_write_vector_impl.deref() + as unsafe extern "C" fn( + rb: *const jack_ringbuffer_t, + vec: *mut jack_ringbuffer_data_t, + ) -> (); + let jack_ringbuffer_read_impl = library + .get:: ::libc::size_t>(b"jack_ringbuffer_read") + .map_err(|err| err.to_string())?; + let jack_ringbuffer_read_impl = jack_ringbuffer_read_impl.into_raw(); + let jack_ringbuffer_read_impl = *jack_ringbuffer_read_impl.deref() + as unsafe extern "C" fn( + rb: *mut jack_ringbuffer_t, + dest: *mut ::libc::c_char, + cnt: ::libc::size_t, + ) -> ::libc::size_t; + let jack_ringbuffer_peek_impl = library + .get:: ::libc::size_t>(b"jack_ringbuffer_peek") + .map_err(|err| err.to_string())?; + let jack_ringbuffer_peek_impl = jack_ringbuffer_peek_impl.into_raw(); + let jack_ringbuffer_peek_impl = *jack_ringbuffer_peek_impl.deref() + as unsafe extern "C" fn( + rb: *mut jack_ringbuffer_t, + dest: *mut ::libc::c_char, + cnt: ::libc::size_t, + ) -> ::libc::size_t; + let jack_ringbuffer_read_advance_impl = library + .get:: ()>( + b"jack_ringbuffer_read_advance", + ) + .map_err(|err| err.to_string())?; + let jack_ringbuffer_read_advance_impl = jack_ringbuffer_read_advance_impl.into_raw(); + let jack_ringbuffer_read_advance_impl = *jack_ringbuffer_read_advance_impl.deref() + as unsafe extern "C" fn(rb: *mut jack_ringbuffer_t, cnt: ::libc::size_t) -> (); + let jack_ringbuffer_read_space_impl = library + .get:: ::libc::size_t>( + b"jack_ringbuffer_read_space", + ) + .map_err(|err| err.to_string())?; + let jack_ringbuffer_read_space_impl = jack_ringbuffer_read_space_impl.into_raw(); + let jack_ringbuffer_read_space_impl = *jack_ringbuffer_read_space_impl.deref() + as unsafe extern "C" fn(rb: *const jack_ringbuffer_t) -> ::libc::size_t; + let jack_ringbuffer_mlock_impl = library + .get:: ::libc::c_int>( + b"jack_ringbuffer_mlock", + ) + .map_err(|err| err.to_string())?; + let jack_ringbuffer_mlock_impl = jack_ringbuffer_mlock_impl.into_raw(); + let jack_ringbuffer_mlock_impl = *jack_ringbuffer_mlock_impl.deref() + as unsafe extern "C" fn(rb: *mut jack_ringbuffer_t) -> ::libc::c_int; + let jack_ringbuffer_reset_impl = library + .get:: ()>(b"jack_ringbuffer_reset") + .map_err(|err| err.to_string())?; + let jack_ringbuffer_reset_impl = jack_ringbuffer_reset_impl.into_raw(); + let jack_ringbuffer_reset_impl = *jack_ringbuffer_reset_impl.deref() + as unsafe extern "C" fn(rb: *mut jack_ringbuffer_t) -> (); + let jack_ringbuffer_write_impl = library + .get:: ::libc::size_t>(b"jack_ringbuffer_write") + .map_err(|err| err.to_string())?; + let jack_ringbuffer_write_impl = jack_ringbuffer_write_impl.into_raw(); + let jack_ringbuffer_write_impl = *jack_ringbuffer_write_impl.deref() + as unsafe extern "C" fn( + rb: *mut jack_ringbuffer_t, + src: *const ::libc::c_char, + cnt: ::libc::size_t, + ) -> ::libc::size_t; + let jack_ringbuffer_write_advance_impl = library + .get:: ()>( + b"jack_ringbuffer_write_advance", + ) + .map_err(|err| err.to_string())?; + let jack_ringbuffer_write_advance_impl = jack_ringbuffer_write_advance_impl.into_raw(); + let jack_ringbuffer_write_advance_impl = *jack_ringbuffer_write_advance_impl.deref() + as unsafe extern "C" fn(rb: *mut jack_ringbuffer_t, cnt: ::libc::size_t) -> (); + let jack_ringbuffer_write_space_impl = library + .get:: ::libc::size_t>( + b"jack_ringbuffer_write_space", + ) + .map_err(|err| err.to_string())?; + let jack_ringbuffer_write_space_impl = jack_ringbuffer_write_space_impl.into_raw(); + let jack_ringbuffer_write_space_impl = *jack_ringbuffer_write_space_impl.deref() + as unsafe extern "C" fn(rb: *const jack_ringbuffer_t) -> ::libc::size_t; + let jack_uuid_to_index_impl = library + .get:: u32>(b"jack_uuid_to_index") + .map_err(|err| err.to_string())?; + let jack_uuid_to_index_impl = jack_uuid_to_index_impl.into_raw(); + let jack_uuid_to_index_impl = + *jack_uuid_to_index_impl.deref() as unsafe extern "C" fn(arg1: jack_uuid_t) -> u32; + let jack_uuid_compare_impl = library + .get:: ::std::os::raw::c_int>( + b"jack_uuid_compare", + ) + .map_err(|err| err.to_string())?; + let jack_uuid_compare_impl = jack_uuid_compare_impl.into_raw(); + let jack_uuid_compare_impl = *jack_uuid_compare_impl.deref() + as unsafe extern "C" fn(arg1: jack_uuid_t, arg2: jack_uuid_t) -> ::std::os::raw::c_int; + let jack_uuid_copy_impl = library + .get:: ()>( + b"jack_uuid_copy", + ) + .map_err(|err| err.to_string())?; + let jack_uuid_copy_impl = jack_uuid_copy_impl.into_raw(); + let jack_uuid_copy_impl = *jack_uuid_copy_impl.deref() + as unsafe extern "C" fn(dst: *mut jack_uuid_t, src: jack_uuid_t) -> (); + let jack_uuid_clear_impl = library + .get:: ()>(b"jack_uuid_clear") + .map_err(|err| err.to_string())?; + let jack_uuid_clear_impl = jack_uuid_clear_impl.into_raw(); + let jack_uuid_clear_impl = + *jack_uuid_clear_impl.deref() as unsafe extern "C" fn(arg1: *mut jack_uuid_t) -> (); + let jack_uuid_parse_impl = library + .get:: ::std::os::raw::c_int>(b"jack_uuid_parse") + .map_err(|err| err.to_string())?; + let jack_uuid_parse_impl = jack_uuid_parse_impl.into_raw(); + let jack_uuid_parse_impl = *jack_uuid_parse_impl.deref() + as unsafe extern "C" fn( + buf: *const ::std::os::raw::c_char, + arg1: *mut jack_uuid_t, + ) -> ::std::os::raw::c_int; + let jack_uuid_unparse_impl = library + .get:: ()>( + b"jack_uuid_unparse", + ) + .map_err(|err| err.to_string())?; + let jack_uuid_unparse_impl = jack_uuid_unparse_impl.into_raw(); + let jack_uuid_unparse_impl = *jack_uuid_unparse_impl.deref() + as unsafe extern "C" fn(arg1: jack_uuid_t, buf: *mut ::std::os::raw::c_char) -> (); + let jack_uuid_empty_impl = library + .get:: ::std::os::raw::c_int>(b"jack_uuid_empty") + .map_err(|err| err.to_string())?; + let jack_uuid_empty_impl = jack_uuid_empty_impl.into_raw(); + let jack_uuid_empty_impl = *jack_uuid_empty_impl.deref() + as unsafe extern "C" fn(arg1: jack_uuid_t) -> ::std::os::raw::c_int; + Ok(JackFunctions { + jack_release_timebase_impl, + jack_get_cycle_times_impl, + jack_set_sync_callback_impl, + jack_set_sync_timeout_impl, + jack_set_timebase_callback_impl, + jack_transport_locate_impl, + jack_transport_query_impl, + jack_get_current_transport_frame_impl, + jack_transport_reposition_impl, + jack_transport_start_impl, + jack_transport_stop_impl, + jack_get_transport_info_impl, + jack_set_transport_info_impl, + jack_client_open_impl, + jack_client_new_impl, + jack_client_close_impl, + jack_client_name_size_impl, + jack_get_client_name_impl, + jack_get_uuid_for_client_name_impl, + jack_get_client_name_by_uuid_impl, + jack_internal_client_new_impl, + jack_internal_client_close_impl, + jack_activate_impl, + jack_deactivate_impl, + jack_get_client_pid_impl, + jack_is_realtime_impl, + jack_thread_wait_impl, + jack_cycle_wait_impl, + jack_cycle_signal_impl, + jack_set_process_thread_impl, + jack_set_thread_init_callback_impl, + jack_on_shutdown_impl, + jack_on_info_shutdown_impl, + jack_set_process_callback_impl, + jack_set_freewheel_callback_impl, + jack_set_buffer_size_callback_impl, + jack_get_sample_rate_impl, + jack_set_sample_rate_callback_impl, + jack_set_client_registration_callback_impl, + jack_set_port_registration_callback_impl, + jack_set_port_connect_callback_impl, + jack_set_port_rename_callback_impl, + jack_set_graph_order_callback_impl, + jack_set_xrun_callback_impl, + jack_set_latency_callback_impl, + jack_set_freewheel_impl, + jack_set_buffer_size_impl, + jack_get_buffer_size_impl, + jack_engine_takeover_timebase_impl, + jack_cpu_load_impl, + jack_port_register_impl, + jack_port_unregister_impl, + jack_port_get_buffer_impl, + jack_port_uuid_impl, + jack_port_name_impl, + jack_port_short_name_impl, + jack_port_flags_impl, + jack_port_type_impl, + jack_port_type_id_impl, + jack_port_is_mine_impl, + jack_port_connected_impl, + jack_port_connected_to_impl, + jack_port_get_connections_impl, + jack_port_get_all_connections_impl, + jack_port_tie_impl, + jack_port_untie_impl, + jack_port_set_name_impl, + jack_port_rename_impl, + jack_port_set_alias_impl, + jack_port_unset_alias_impl, + jack_port_get_aliases_impl, + jack_port_request_monitor_impl, + jack_port_request_monitor_by_name_impl, + jack_port_ensure_monitor_impl, + jack_port_monitoring_input_impl, + jack_connect_impl, + jack_disconnect_impl, + jack_port_disconnect_impl, + jack_port_name_size_impl, + jack_port_type_size_impl, + jack_port_type_get_buffer_size_impl, + jack_port_set_latency_impl, + jack_port_get_latency_range_impl, + jack_port_set_latency_range_impl, + jack_recompute_total_latencies_impl, + jack_port_get_latency_impl, + jack_port_get_total_latency_impl, + jack_recompute_total_latency_impl, + jack_get_ports_impl, + jack_port_by_name_impl, + jack_port_by_id_impl, + jack_frames_since_cycle_start_impl, + jack_frame_time_impl, + jack_last_frame_time_impl, + jack_frames_to_time_impl, + jack_time_to_frames_impl, + jack_get_time_impl, + jack_set_error_function_impl, + jack_set_info_function_impl, + jack_free_impl, + jack_client_real_time_priority_impl, + jack_client_max_real_time_priority_impl, + jack_set_session_callback_impl, + jack_session_reply_impl, + jack_session_event_free_impl, + jack_client_get_uuid_impl, + jack_session_notify_impl, + jack_session_commands_free_impl, + jack_reserve_client_name_impl, + jack_client_has_session_callback_impl, + jackctl_setup_signals_impl, + jackctl_wait_signals_impl, + jackctl_server_create_impl, + jackctl_server_destroy_impl, + jackctl_server_open_impl, + jackctl_server_start_impl, + jackctl_server_stop_impl, + jackctl_server_close_impl, + jackctl_server_get_drivers_list_impl, + jackctl_server_get_parameters_impl, + jackctl_server_get_internals_list_impl, + jackctl_server_load_internal_impl, + jackctl_server_unload_internal_impl, + jackctl_server_add_slave_impl, + jackctl_server_remove_slave_impl, + jackctl_server_switch_master_impl, + jackctl_driver_get_name_impl, + jackctl_driver_get_type_impl, + jackctl_driver_get_parameters_impl, + jackctl_driver_params_parse_impl, + jackctl_internal_get_name_impl, + jackctl_internal_get_parameters_impl, + jackctl_parameter_get_name_impl, + jackctl_parameter_get_short_description_impl, + jackctl_parameter_get_long_description_impl, + jackctl_parameter_get_type_impl, + jackctl_parameter_get_id_impl, + jackctl_parameter_is_set_impl, + jackctl_parameter_reset_impl, + jackctl_parameter_get_value_impl, + jackctl_parameter_set_value_impl, + jackctl_parameter_get_default_value_impl, + jackctl_parameter_has_range_constraint_impl, + jackctl_parameter_has_enum_constraint_impl, + jackctl_parameter_get_enum_constraints_count_impl, + jackctl_parameter_get_enum_constraint_value_impl, + jackctl_parameter_get_enum_constraint_description_impl, + jackctl_parameter_get_range_constraint_impl, + jackctl_parameter_constraint_is_strict_impl, + jackctl_parameter_constraint_is_fake_value_impl, + jack_set_property_impl, + jack_get_property_impl, + jack_free_description_impl, + jack_get_properties_impl, + jack_get_all_properties_impl, + jack_remove_property_impl, + jack_remove_properties_impl, + jack_remove_all_properties_impl, + jack_set_property_change_callback_impl, + jack_get_internal_client_name_impl, + jack_internal_client_handle_impl, + jack_internal_client_load_impl, + jack_internal_client_unload_impl, + jack_get_max_delayed_usecs_impl, + jack_get_xrun_delayed_usecs_impl, + jack_reset_max_delayed_usecs_impl, + jack_midi_get_event_count_impl, + jack_midi_event_get_impl, + jack_midi_clear_buffer_impl, + jack_midi_max_event_size_impl, + jack_midi_event_reserve_impl, + jack_midi_event_write_impl, + jack_midi_get_lost_event_count_impl, + jack_ringbuffer_create_impl, + jack_ringbuffer_free_impl, + jack_ringbuffer_get_read_vector_impl, + jack_ringbuffer_get_write_vector_impl, + jack_ringbuffer_read_impl, + jack_ringbuffer_peek_impl, + jack_ringbuffer_read_advance_impl, + jack_ringbuffer_read_space_impl, + jack_ringbuffer_mlock_impl, + jack_ringbuffer_reset_impl, + jack_ringbuffer_write_impl, + jack_ringbuffer_write_advance_impl, + jack_ringbuffer_write_space_impl, + jack_uuid_to_index_impl, + jack_uuid_compare_impl, + jack_uuid_copy_impl, + jack_uuid_clear_impl, + jack_uuid_parse_impl, + jack_uuid_unparse_impl, + jack_uuid_empty_impl, + }) +} + +/// Returns the loaded JACK functions. +/// +/// # Panics +/// Panics if the JACK library or one of its required functions could not be loaded. Call +/// [`ensure_loaded`] first to handle this as an error. +fn functions() -> &'static JackFunctions { + match &*FUNCTIONS { + Ok(functions) => functions, + Err(err) => panic!("failed to load JACK: {}", err), + } +} + +/// Load the JACK library and all of its required functions. +/// +/// Every other function in this crate panics if loading failed, so call this first and handle the +/// error. +pub fn ensure_loaded() -> Result<(), &'static str> { + FUNCTIONS.as_ref().map(|_| ()).map_err(String::as_str) } pub unsafe fn jack_release_timebase(client: *mut jack_client_t) -> ::libc::c_int { - let f = FUNCTIONS.jack_release_timebase_impl; + let f = functions().jack_release_timebase_impl; f(client) } pub unsafe fn jack_get_cycle_times( @@ -2828,7 +2854,7 @@ pub unsafe fn jack_get_cycle_times( next_usecs: *mut jack_time_t, period_usecs: *mut ::libc::c_float, ) -> Option<::libc::c_int> { - let f = FUNCTIONS.jack_get_cycle_times_impl?; + let f = functions().jack_get_cycle_times_impl?; Some(f( client, current_frames, @@ -2842,14 +2868,14 @@ pub unsafe fn jack_set_sync_callback( sync_callback: JackSyncCallback, sync_arg: *mut ::libc::c_void, ) -> ::libc::c_int { - let f = FUNCTIONS.jack_set_sync_callback_impl; + let f = functions().jack_set_sync_callback_impl; f(client, sync_callback, sync_arg) } pub unsafe fn jack_set_sync_timeout( client: *mut jack_client_t, timeout: jack_time_t, ) -> ::libc::c_int { - let f = FUNCTIONS.jack_set_sync_timeout_impl; + let f = functions().jack_set_sync_timeout_impl; f(client, timeout) } pub unsafe fn jack_set_timebase_callback( @@ -2858,54 +2884,54 @@ pub unsafe fn jack_set_timebase_callback( timebase_callback: TimebaseCallback, arg: *mut ::libc::c_void, ) -> ::libc::c_int { - let f = FUNCTIONS.jack_set_timebase_callback_impl; + let f = functions().jack_set_timebase_callback_impl; f(client, conditional, timebase_callback, arg) } pub unsafe fn jack_transport_locate( client: *mut jack_client_t, frame: jack_nframes_t, ) -> ::libc::c_int { - let f = FUNCTIONS.jack_transport_locate_impl; + let f = functions().jack_transport_locate_impl; f(client, frame) } pub unsafe fn jack_transport_query( client: *const jack_client_t, pos: *mut jack_position_t, ) -> jack_transport_state_t { - let f = FUNCTIONS.jack_transport_query_impl; + let f = functions().jack_transport_query_impl; f(client, pos) } pub unsafe fn jack_get_current_transport_frame(client: *const jack_client_t) -> jack_nframes_t { - let f = FUNCTIONS.jack_get_current_transport_frame_impl; + let f = functions().jack_get_current_transport_frame_impl; f(client) } pub unsafe fn jack_transport_reposition( client: *mut jack_client_t, pos: *const jack_position_t, ) -> ::libc::c_int { - let f = FUNCTIONS.jack_transport_reposition_impl; + let f = functions().jack_transport_reposition_impl; f(client, pos) } pub unsafe fn jack_transport_start(client: *mut jack_client_t) -> () { - let f = FUNCTIONS.jack_transport_start_impl; + let f = functions().jack_transport_start_impl; f(client) } pub unsafe fn jack_transport_stop(client: *mut jack_client_t) -> () { - let f = FUNCTIONS.jack_transport_stop_impl; + let f = functions().jack_transport_stop_impl; f(client) } pub unsafe fn jack_get_transport_info( client: *mut jack_client_t, tinfo: *mut jack_transport_info_t, ) -> () { - let f = FUNCTIONS.jack_get_transport_info_impl; + let f = functions().jack_get_transport_info_impl; f(client, tinfo) } pub unsafe fn jack_set_transport_info( client: *mut jack_client_t, tinfo: *mut jack_transport_info_t, ) -> () { - let f = FUNCTIONS.jack_set_transport_info_impl; + let f = functions().jack_set_transport_info_impl; f(client, tinfo) } pub unsafe fn jack_client_open( @@ -2913,37 +2939,37 @@ pub unsafe fn jack_client_open( options: jack_options_t, status: *mut jack_status_t, ) -> *mut jack_client_t { - let f = FUNCTIONS.jack_client_open_impl; + let f = functions().jack_client_open_impl; f(client_name, options, status) } pub unsafe fn jack_client_new(client_name: *const ::libc::c_char) -> *mut jack_client_t { - let f = FUNCTIONS.jack_client_new_impl; + let f = functions().jack_client_new_impl; f(client_name) } pub unsafe fn jack_client_close(client: *mut jack_client_t) -> ::libc::c_int { - let f = FUNCTIONS.jack_client_close_impl; + let f = functions().jack_client_close_impl; f(client) } pub unsafe fn jack_client_name_size() -> ::libc::c_int { - let f = FUNCTIONS.jack_client_name_size_impl; + let f = functions().jack_client_name_size_impl; f() } pub unsafe fn jack_get_client_name(client: *mut jack_client_t) -> *mut ::libc::c_char { - let f = FUNCTIONS.jack_get_client_name_impl; + let f = functions().jack_get_client_name_impl; f(client) } pub unsafe fn jack_get_uuid_for_client_name( client: *mut jack_client_t, client_name: *const ::libc::c_char, ) -> *mut ::libc::c_char { - let f = FUNCTIONS.jack_get_uuid_for_client_name_impl; + let f = functions().jack_get_uuid_for_client_name_impl; f(client, client_name) } pub unsafe fn jack_get_client_name_by_uuid( client: *mut jack_client_t, client_uuid: *const ::libc::c_char, ) -> *mut ::libc::c_char { - let f = FUNCTIONS.jack_get_client_name_by_uuid_impl; + let f = functions().jack_get_client_name_by_uuid_impl; f(client, client_uuid) } pub unsafe fn jack_internal_client_new( @@ -2951,42 +2977,42 @@ pub unsafe fn jack_internal_client_new( load_name: *const ::libc::c_char, load_init: *const ::libc::c_char, ) -> Option<::libc::c_int> { - let f = FUNCTIONS.jack_internal_client_new_impl?; + let f = functions().jack_internal_client_new_impl?; Some(f(client_name, load_name, load_init)) } pub unsafe fn jack_internal_client_close(client_name: *const ::libc::c_char) -> Option<()> { - let f = FUNCTIONS.jack_internal_client_close_impl?; + let f = functions().jack_internal_client_close_impl?; Some(f(client_name)) } pub unsafe fn jack_activate(client: *mut jack_client_t) -> ::libc::c_int { - let f = FUNCTIONS.jack_activate_impl; + let f = functions().jack_activate_impl; f(client) } pub unsafe fn jack_deactivate(client: *mut jack_client_t) -> ::libc::c_int { - let f = FUNCTIONS.jack_deactivate_impl; + let f = functions().jack_deactivate_impl; f(client) } pub unsafe fn jack_get_client_pid(name: *const ::libc::c_char) -> Option<::libc::c_int> { - let f = FUNCTIONS.jack_get_client_pid_impl?; + let f = functions().jack_get_client_pid_impl?; Some(f(name)) } pub unsafe fn jack_is_realtime(client: *mut jack_client_t) -> ::libc::c_int { - let f = FUNCTIONS.jack_is_realtime_impl; + let f = functions().jack_is_realtime_impl; f(client) } pub unsafe fn jack_thread_wait( client: *mut jack_client_t, status: ::libc::c_int, ) -> jack_nframes_t { - let f = FUNCTIONS.jack_thread_wait_impl; + let f = functions().jack_thread_wait_impl; f(client, status) } pub unsafe fn jack_cycle_wait(client: *mut jack_client_t) -> jack_nframes_t { - let f = FUNCTIONS.jack_cycle_wait_impl; + let f = functions().jack_cycle_wait_impl; f(client) } pub unsafe fn jack_cycle_signal(client: *mut jack_client_t, status: ::libc::c_int) -> () { - let f = FUNCTIONS.jack_cycle_signal_impl; + let f = functions().jack_cycle_signal_impl; f(client, status) } pub unsafe fn jack_set_process_thread( @@ -2994,7 +3020,7 @@ pub unsafe fn jack_set_process_thread( thread_callback: JackThreadCallback, arg: *mut ::libc::c_void, ) -> ::libc::c_int { - let f = FUNCTIONS.jack_set_process_thread_impl; + let f = functions().jack_set_process_thread_impl; f(client, thread_callback, arg) } pub unsafe fn jack_set_thread_init_callback( @@ -3002,7 +3028,7 @@ pub unsafe fn jack_set_thread_init_callback( thread_init_callback: JackThreadInitCallback, arg: *mut ::libc::c_void, ) -> ::libc::c_int { - let f = FUNCTIONS.jack_set_thread_init_callback_impl; + let f = functions().jack_set_thread_init_callback_impl; f(client, thread_init_callback, arg) } pub unsafe fn jack_on_shutdown( @@ -3010,7 +3036,7 @@ pub unsafe fn jack_on_shutdown( callback: JackShutdownCallback, arg: *mut ::libc::c_void, ) -> () { - let f = FUNCTIONS.jack_on_shutdown_impl; + let f = functions().jack_on_shutdown_impl; f(client, callback, arg) } pub unsafe fn jack_on_info_shutdown( @@ -3018,7 +3044,7 @@ pub unsafe fn jack_on_info_shutdown( callback: JackInfoShutdownCallback, arg: *mut ::libc::c_void, ) -> () { - let f = FUNCTIONS.jack_on_info_shutdown_impl; + let f = functions().jack_on_info_shutdown_impl; f(client, callback, arg) } pub unsafe fn jack_set_process_callback( @@ -3026,7 +3052,7 @@ pub unsafe fn jack_set_process_callback( process_callback: JackProcessCallback, arg: *mut ::libc::c_void, ) -> ::libc::c_int { - let f = FUNCTIONS.jack_set_process_callback_impl; + let f = functions().jack_set_process_callback_impl; f(client, process_callback, arg) } pub unsafe fn jack_set_freewheel_callback( @@ -3034,7 +3060,7 @@ pub unsafe fn jack_set_freewheel_callback( freewheel_callback: JackFreewheelCallback, arg: *mut ::libc::c_void, ) -> ::libc::c_int { - let f = FUNCTIONS.jack_set_freewheel_callback_impl; + let f = functions().jack_set_freewheel_callback_impl; f(client, freewheel_callback, arg) } pub unsafe fn jack_set_buffer_size_callback( @@ -3042,11 +3068,11 @@ pub unsafe fn jack_set_buffer_size_callback( bufsize_callback: JackBufferSizeCallback, arg: *mut ::libc::c_void, ) -> ::libc::c_int { - let f = FUNCTIONS.jack_set_buffer_size_callback_impl; + let f = functions().jack_set_buffer_size_callback_impl; f(client, bufsize_callback, arg) } pub unsafe fn jack_get_sample_rate(client: *mut jack_client_t) -> ::libc::c_int { - let f = FUNCTIONS.jack_get_sample_rate_impl; + let f = functions().jack_get_sample_rate_impl; f(client) } pub unsafe fn jack_set_sample_rate_callback( @@ -3054,7 +3080,7 @@ pub unsafe fn jack_set_sample_rate_callback( srate_callback: JackSampleRateCallback, arg: *mut ::libc::c_void, ) -> ::libc::c_int { - let f = FUNCTIONS.jack_set_sample_rate_callback_impl; + let f = functions().jack_set_sample_rate_callback_impl; f(client, srate_callback, arg) } pub unsafe fn jack_set_client_registration_callback( @@ -3062,7 +3088,7 @@ pub unsafe fn jack_set_client_registration_callback( registration_callback: JackClientRegistrationCallback, arg: *mut ::libc::c_void, ) -> ::libc::c_int { - let f = FUNCTIONS.jack_set_client_registration_callback_impl; + let f = functions().jack_set_client_registration_callback_impl; f(client, registration_callback, arg) } pub unsafe fn jack_set_port_registration_callback( @@ -3070,7 +3096,7 @@ pub unsafe fn jack_set_port_registration_callback( registration_callback: JackPortRegistrationCallback, arg: *mut ::libc::c_void, ) -> ::libc::c_int { - let f = FUNCTIONS.jack_set_port_registration_callback_impl; + let f = functions().jack_set_port_registration_callback_impl; f(client, registration_callback, arg) } pub unsafe fn jack_set_port_connect_callback( @@ -3078,7 +3104,7 @@ pub unsafe fn jack_set_port_connect_callback( connect_callback: JackPortConnectCallback, arg: *mut ::libc::c_void, ) -> ::libc::c_int { - let f = FUNCTIONS.jack_set_port_connect_callback_impl; + let f = functions().jack_set_port_connect_callback_impl; f(client, connect_callback, arg) } pub unsafe fn jack_set_port_rename_callback( @@ -3086,7 +3112,7 @@ pub unsafe fn jack_set_port_rename_callback( rename_callback: JackPortRenameCallback, arg: *mut ::libc::c_void, ) -> ::libc::c_int { - let f = FUNCTIONS.jack_set_port_rename_callback_impl; + let f = functions().jack_set_port_rename_callback_impl; f(client, rename_callback, arg) } pub unsafe fn jack_set_graph_order_callback( @@ -3094,7 +3120,7 @@ pub unsafe fn jack_set_graph_order_callback( graph_callback: JackGraphOrderCallback, arg: *mut ::libc::c_void, ) -> ::libc::c_int { - let f = FUNCTIONS.jack_set_graph_order_callback_impl; + let f = functions().jack_set_graph_order_callback_impl; f(client, graph_callback, arg) } pub unsafe fn jack_set_xrun_callback( @@ -3102,7 +3128,7 @@ pub unsafe fn jack_set_xrun_callback( xrun_callback: JackXRunCallback, arg: *mut ::libc::c_void, ) -> ::libc::c_int { - let f = FUNCTIONS.jack_set_xrun_callback_impl; + let f = functions().jack_set_xrun_callback_impl; f(client, xrun_callback, arg) } pub unsafe fn jack_set_latency_callback( @@ -3110,33 +3136,33 @@ pub unsafe fn jack_set_latency_callback( latency_callback: JackLatencyCallback, arg: *mut ::libc::c_void, ) -> ::libc::c_int { - let f = FUNCTIONS.jack_set_latency_callback_impl; + let f = functions().jack_set_latency_callback_impl; f(client, latency_callback, arg) } pub unsafe fn jack_set_freewheel( client: *mut jack_client_t, onoff: ::libc::c_int, ) -> ::libc::c_int { - let f = FUNCTIONS.jack_set_freewheel_impl; + let f = functions().jack_set_freewheel_impl; f(client, onoff) } pub unsafe fn jack_set_buffer_size( client: *mut jack_client_t, nframes: jack_nframes_t, ) -> ::libc::c_int { - let f = FUNCTIONS.jack_set_buffer_size_impl; + let f = functions().jack_set_buffer_size_impl; f(client, nframes) } pub unsafe fn jack_get_buffer_size(client: *mut jack_client_t) -> jack_nframes_t { - let f = FUNCTIONS.jack_get_buffer_size_impl; + let f = functions().jack_get_buffer_size_impl; f(client) } pub unsafe fn jack_engine_takeover_timebase(client: *mut jack_client_t) -> ::libc::c_int { - let f = FUNCTIONS.jack_engine_takeover_timebase_impl; + let f = functions().jack_engine_takeover_timebase_impl; f(client) } pub unsafe fn jack_cpu_load(client: *mut jack_client_t) -> ::libc::c_float { - let f = FUNCTIONS.jack_cpu_load_impl; + let f = functions().jack_cpu_load_impl; f(client) } pub unsafe fn jack_port_register( @@ -3146,117 +3172,127 @@ pub unsafe fn jack_port_register( flags: ::libc::c_ulong, buffer_size: ::libc::c_ulong, ) -> *mut jack_port_t { - let f = FUNCTIONS.jack_port_register_impl; + let f = functions().jack_port_register_impl; f(client, port_name, port_type, flags, buffer_size) } pub unsafe fn jack_port_unregister( client: *mut jack_client_t, port: *mut jack_port_t, ) -> ::libc::c_int { - let f = FUNCTIONS.jack_port_unregister_impl; + let f = functions().jack_port_unregister_impl; f(client, port) } pub unsafe fn jack_port_get_buffer( port: *mut jack_port_t, nframes: jack_nframes_t, ) -> *mut ::libc::c_void { - let f = FUNCTIONS.jack_port_get_buffer_impl; + let f = functions().jack_port_get_buffer_impl; f(port, nframes) } pub unsafe fn jack_port_uuid(port: *mut jack_port_t) -> jack_uuid_t { - let f = FUNCTIONS.jack_port_uuid_impl; + let f = functions().jack_port_uuid_impl; f(port) } pub unsafe fn jack_port_name(port: *mut jack_port_t) -> *const ::libc::c_char { - let f = FUNCTIONS.jack_port_name_impl; + let f = functions().jack_port_name_impl; f(port) } pub unsafe fn jack_port_short_name(port: *mut jack_port_t) -> *const ::libc::c_char { - let f = FUNCTIONS.jack_port_short_name_impl; + let f = functions().jack_port_short_name_impl; f(port) } pub unsafe fn jack_port_flags(port: *mut jack_port_t) -> ::libc::c_int { - let f = FUNCTIONS.jack_port_flags_impl; + let f = functions().jack_port_flags_impl; f(port) } pub unsafe fn jack_port_type(port: *const jack_port_t) -> *const ::libc::c_char { - let f = FUNCTIONS.jack_port_type_impl; + let f = functions().jack_port_type_impl; f(port) } pub unsafe fn jack_port_type_id(port: *const jack_port_t) -> Option { - let f = FUNCTIONS.jack_port_type_id_impl?; + let f = functions().jack_port_type_id_impl?; Some(f(port)) } pub unsafe fn jack_port_is_mine( client: *const jack_client_t, port: *const jack_port_t, ) -> ::libc::c_int { - let f = FUNCTIONS.jack_port_is_mine_impl; + let f = functions().jack_port_is_mine_impl; f(client, port) } pub unsafe fn jack_port_connected(port: *const jack_port_t) -> ::libc::c_int { - let f = FUNCTIONS.jack_port_connected_impl; + let f = functions().jack_port_connected_impl; f(port) } pub unsafe fn jack_port_connected_to( port: *const jack_port_t, port_name: *const ::libc::c_char, ) -> ::libc::c_int { - let f = FUNCTIONS.jack_port_connected_to_impl; + let f = functions().jack_port_connected_to_impl; f(port, port_name) } pub unsafe fn jack_port_get_connections(port: *const jack_port_t) -> *mut *const ::libc::c_char { - let f = FUNCTIONS.jack_port_get_connections_impl; + let f = functions().jack_port_get_connections_impl; f(port) } pub unsafe fn jack_port_get_all_connections( client: *const jack_client_t, port: *const jack_port_t, ) -> *mut *const ::libc::c_char { - let f = FUNCTIONS.jack_port_get_all_connections_impl; + let f = functions().jack_port_get_all_connections_impl; f(client, port) } pub unsafe fn jack_port_tie(src: *mut jack_port_t, dst: *mut jack_port_t) -> ::libc::c_int { - let f = FUNCTIONS.jack_port_tie_impl; + let f = functions().jack_port_tie_impl; f(src, dst) } pub unsafe fn jack_port_untie(port: *mut jack_port_t) -> ::libc::c_int { - let f = FUNCTIONS.jack_port_untie_impl; + let f = functions().jack_port_untie_impl; f(port) } pub unsafe fn jack_port_set_name( port: *mut jack_port_t, port_name: *const ::libc::c_char, ) -> ::libc::c_int { - let f = FUNCTIONS.jack_port_set_name_impl; + let f = functions().jack_port_set_name_impl; f(port, port_name) } +/// Rename `port`. Unlike `jack_port_set_name`, this notifies port rename callbacks. Returns `None` +/// if the JACK library does not provide it. +pub unsafe fn jack_port_rename( + client: *mut jack_client_t, + port: *mut jack_port_t, + port_name: *const ::libc::c_char, +) -> Option<::libc::c_int> { + let f = functions().jack_port_rename_impl?; + Some(f(client, port, port_name)) +} pub unsafe fn jack_port_set_alias( port: *mut jack_port_t, alias: *const ::libc::c_char, ) -> ::libc::c_int { - let f = FUNCTIONS.jack_port_set_alias_impl; + let f = functions().jack_port_set_alias_impl; f(port, alias) } pub unsafe fn jack_port_unset_alias( port: *mut jack_port_t, alias: *const ::libc::c_char, ) -> ::libc::c_int { - let f = FUNCTIONS.jack_port_unset_alias_impl; + let f = functions().jack_port_unset_alias_impl; f(port, alias) } pub unsafe fn jack_port_get_aliases( port: *const jack_port_t, aliases: *mut *mut ::libc::c_char, ) -> ::libc::c_int { - let f = FUNCTIONS.jack_port_get_aliases_impl; + let f = functions().jack_port_get_aliases_impl; f(port, aliases) } pub unsafe fn jack_port_request_monitor( port: *mut jack_port_t, onoff: ::libc::c_int, ) -> ::libc::c_int { - let f = FUNCTIONS.jack_port_request_monitor_impl; + let f = functions().jack_port_request_monitor_impl; f(port, onoff) } pub unsafe fn jack_port_request_monitor_by_name( @@ -3264,18 +3300,18 @@ pub unsafe fn jack_port_request_monitor_by_name( port_name: *const ::libc::c_char, onoff: ::libc::c_int, ) -> ::libc::c_int { - let f = FUNCTIONS.jack_port_request_monitor_by_name_impl; + let f = functions().jack_port_request_monitor_by_name_impl; f(client, port_name, onoff) } pub unsafe fn jack_port_ensure_monitor( port: *mut jack_port_t, onoff: ::libc::c_int, ) -> ::libc::c_int { - let f = FUNCTIONS.jack_port_ensure_monitor_impl; + let f = functions().jack_port_ensure_monitor_impl; f(port, onoff) } pub unsafe fn jack_port_monitoring_input(port: *mut jack_port_t) -> ::libc::c_int { - let f = FUNCTIONS.jack_port_monitoring_input_impl; + let f = functions().jack_port_monitoring_input_impl; f(port) } pub unsafe fn jack_connect( @@ -3283,7 +3319,7 @@ pub unsafe fn jack_connect( source_port: *const ::libc::c_char, destination_port: *const ::libc::c_char, ) -> ::libc::c_int { - let f = FUNCTIONS.jack_connect_impl; + let f = functions().jack_connect_impl; f(client, source_port, destination_port) } pub unsafe fn jack_disconnect( @@ -3291,33 +3327,33 @@ pub unsafe fn jack_disconnect( source_port: *const ::libc::c_char, destination_port: *const ::libc::c_char, ) -> ::libc::c_int { - let f = FUNCTIONS.jack_disconnect_impl; + let f = functions().jack_disconnect_impl; f(client, source_port, destination_port) } pub unsafe fn jack_port_disconnect( client: *mut jack_client_t, port: *mut jack_port_t, ) -> ::libc::c_int { - let f = FUNCTIONS.jack_port_disconnect_impl; + let f = functions().jack_port_disconnect_impl; f(client, port) } pub unsafe fn jack_port_name_size() -> ::libc::c_int { - let f = FUNCTIONS.jack_port_name_size_impl; + let f = functions().jack_port_name_size_impl; f() } pub unsafe fn jack_port_type_size() -> ::libc::c_int { - let f = FUNCTIONS.jack_port_type_size_impl; + let f = functions().jack_port_type_size_impl; f() } pub unsafe fn jack_port_type_get_buffer_size( client: *mut jack_client_t, port_type: *const ::libc::c_char, ) -> ::libc::size_t { - let f = FUNCTIONS.jack_port_type_get_buffer_size_impl; + let f = functions().jack_port_type_get_buffer_size_impl; f(client, port_type) } pub unsafe fn jack_port_set_latency(port: *mut jack_port_t, arg1: jack_nframes_t) -> () { - let f = FUNCTIONS.jack_port_set_latency_impl; + let f = functions().jack_port_set_latency_impl; f(port, arg1) } pub unsafe fn jack_port_get_latency_range( @@ -3325,7 +3361,7 @@ pub unsafe fn jack_port_get_latency_range( mode: jack_latency_callback_mode_t, range: *mut jack_latency_range_t, ) -> () { - let f = FUNCTIONS.jack_port_get_latency_range_impl; + let f = functions().jack_port_get_latency_range_impl; f(port, mode, range) } pub unsafe fn jack_port_set_latency_range( @@ -3333,29 +3369,29 @@ pub unsafe fn jack_port_set_latency_range( mode: jack_latency_callback_mode_t, range: *mut jack_latency_range_t, ) -> () { - let f = FUNCTIONS.jack_port_set_latency_range_impl; + let f = functions().jack_port_set_latency_range_impl; f(port, mode, range) } pub unsafe fn jack_recompute_total_latencies(client: *mut jack_client_t) -> ::libc::c_int { - let f = FUNCTIONS.jack_recompute_total_latencies_impl; + let f = functions().jack_recompute_total_latencies_impl; f(client) } pub unsafe fn jack_port_get_latency(port: *mut jack_port_t) -> jack_nframes_t { - let f = FUNCTIONS.jack_port_get_latency_impl; + let f = functions().jack_port_get_latency_impl; f(port) } pub unsafe fn jack_port_get_total_latency( client: *mut jack_client_t, port: *mut jack_port_t, ) -> jack_nframes_t { - let f = FUNCTIONS.jack_port_get_total_latency_impl; + let f = functions().jack_port_get_total_latency_impl; f(client, port) } pub unsafe fn jack_recompute_total_latency( arg1: *mut jack_client_t, port: *mut jack_port_t, ) -> ::libc::c_int { - let f = FUNCTIONS.jack_recompute_total_latency_impl; + let f = functions().jack_recompute_total_latency_impl; f(arg1, port) } pub unsafe fn jack_get_ports( @@ -3364,75 +3400,75 @@ pub unsafe fn jack_get_ports( type_name_pattern: *const ::libc::c_char, flags: ::libc::c_ulong, ) -> *mut *const ::libc::c_char { - let f = FUNCTIONS.jack_get_ports_impl; + let f = functions().jack_get_ports_impl; f(client, port_name_pattern, type_name_pattern, flags) } pub unsafe fn jack_port_by_name( client: *mut jack_client_t, port_name: *const ::libc::c_char, ) -> *mut jack_port_t { - let f = FUNCTIONS.jack_port_by_name_impl; + let f = functions().jack_port_by_name_impl; f(client, port_name) } pub unsafe fn jack_port_by_id( client: *mut jack_client_t, port_id: jack_port_id_t, ) -> *mut jack_port_t { - let f = FUNCTIONS.jack_port_by_id_impl; + let f = functions().jack_port_by_id_impl; f(client, port_id) } pub unsafe fn jack_frames_since_cycle_start(arg1: *const jack_client_t) -> jack_nframes_t { - let f = FUNCTIONS.jack_frames_since_cycle_start_impl; + let f = functions().jack_frames_since_cycle_start_impl; f(arg1) } pub unsafe fn jack_frame_time(arg1: *const jack_client_t) -> jack_nframes_t { - let f = FUNCTIONS.jack_frame_time_impl; + let f = functions().jack_frame_time_impl; f(arg1) } pub unsafe fn jack_last_frame_time(client: *const jack_client_t) -> jack_nframes_t { - let f = FUNCTIONS.jack_last_frame_time_impl; + let f = functions().jack_last_frame_time_impl; f(client) } pub unsafe fn jack_frames_to_time( client: *const jack_client_t, arg1: jack_nframes_t, ) -> jack_time_t { - let f = FUNCTIONS.jack_frames_to_time_impl; + let f = functions().jack_frames_to_time_impl; f(client, arg1) } pub unsafe fn jack_time_to_frames( client: *const jack_client_t, arg1: jack_time_t, ) -> jack_nframes_t { - let f = FUNCTIONS.jack_time_to_frames_impl; + let f = functions().jack_time_to_frames_impl; f(client, arg1) } pub unsafe fn jack_get_time() -> jack_time_t { - let f = FUNCTIONS.jack_get_time_impl; + let f = functions().jack_get_time_impl; f() } pub unsafe fn jack_set_error_function( func: ::std::option::Option ()>, ) -> () { - let f = FUNCTIONS.jack_set_error_function_impl; + let f = functions().jack_set_error_function_impl; f(func) } pub unsafe fn jack_set_info_function( func: ::std::option::Option ()>, ) -> () { - let f = FUNCTIONS.jack_set_info_function_impl; + let f = functions().jack_set_info_function_impl; f(func) } pub unsafe fn jack_free(ptr: *mut ::libc::c_void) -> () { - let f = FUNCTIONS.jack_free_impl; + let f = functions().jack_free_impl; f(ptr) } pub unsafe fn jack_client_real_time_priority(arg1: *mut jack_client_t) -> ::libc::c_int { - let f = FUNCTIONS.jack_client_real_time_priority_impl; + let f = functions().jack_client_real_time_priority_impl; f(arg1) } pub unsafe fn jack_client_max_real_time_priority(arg1: *mut jack_client_t) -> ::libc::c_int { - let f = FUNCTIONS.jack_client_max_real_time_priority_impl; + let f = functions().jack_client_max_real_time_priority_impl; f(arg1) } pub unsafe fn jack_set_session_callback( @@ -3440,22 +3476,22 @@ pub unsafe fn jack_set_session_callback( session_callback: JackSessionCallback, arg: *mut ::libc::c_void, ) -> ::libc::c_int { - let f = FUNCTIONS.jack_set_session_callback_impl; + let f = functions().jack_set_session_callback_impl; f(client, session_callback, arg) } pub unsafe fn jack_session_reply( client: *mut jack_client_t, event: *mut jack_session_event_t, ) -> ::libc::c_int { - let f = FUNCTIONS.jack_session_reply_impl; + let f = functions().jack_session_reply_impl; f(client, event) } pub unsafe fn jack_session_event_free(event: *mut jack_session_event_t) -> () { - let f = FUNCTIONS.jack_session_event_free_impl; + let f = functions().jack_session_event_free_impl; f(event) } pub unsafe fn jack_client_get_uuid(client: *mut jack_client_t) -> *mut ::libc::c_char { - let f = FUNCTIONS.jack_client_get_uuid_impl; + let f = functions().jack_client_get_uuid_impl; f(client) } pub unsafe fn jack_session_notify( @@ -3464,11 +3500,11 @@ pub unsafe fn jack_session_notify( _type: jack_session_event_type_t, path: *const ::libc::c_char, ) -> *mut jack_session_command_t { - let f = FUNCTIONS.jack_session_notify_impl; + let f = functions().jack_session_notify_impl; f(client, target, _type, path) } pub unsafe fn jack_session_commands_free(cmds: *mut jack_session_command_t) -> () { - let f = FUNCTIONS.jack_session_commands_free_impl; + let f = functions().jack_session_commands_free_impl; f(cmds) } pub unsafe fn jack_reserve_client_name( @@ -3476,22 +3512,22 @@ pub unsafe fn jack_reserve_client_name( name: *const ::libc::c_char, uuid: *const ::libc::c_char, ) -> ::libc::c_int { - let f = FUNCTIONS.jack_reserve_client_name_impl; + let f = functions().jack_reserve_client_name_impl; f(client, name, uuid) } pub unsafe fn jack_client_has_session_callback( client: *mut jack_client_t, client_name: *const ::libc::c_char, ) -> ::libc::c_int { - let f = FUNCTIONS.jack_client_has_session_callback_impl; + let f = functions().jack_client_has_session_callback_impl; f(client, client_name) } pub unsafe fn jackctl_setup_signals(flags: ::libc::c_uint) -> Option<*mut jackctl_sigmask_t> { - let f = FUNCTIONS.jackctl_setup_signals_impl?; + let f = functions().jackctl_setup_signals_impl?; Some(f(flags)) } pub unsafe fn jackctl_wait_signals(signals: *mut jackctl_sigmask_t) -> Option<()> { - let f = FUNCTIONS.jackctl_wait_signals_impl?; + let f = functions().jackctl_wait_signals_impl?; Some(f(signals)) } pub unsafe fn jackctl_server_create( @@ -3502,101 +3538,101 @@ pub unsafe fn jackctl_server_create( unsafe extern "C" fn(device_name: *const ::libc::c_char) -> (), >, ) -> Option<*mut jackctl_server_t> { - let f = FUNCTIONS.jackctl_server_create_impl?; + let f = functions().jackctl_server_create_impl?; Some(f(on_device_acquire, on_device_release)) } pub unsafe fn jackctl_server_destroy(server: *mut jackctl_server_t) -> Option<()> { - let f = FUNCTIONS.jackctl_server_destroy_impl?; + let f = functions().jackctl_server_destroy_impl?; Some(f(server)) } pub unsafe fn jackctl_server_open( server: *mut jackctl_server_t, driver: *mut jackctl_driver_t, ) -> Option { - let f = FUNCTIONS.jackctl_server_open_impl?; + let f = functions().jackctl_server_open_impl?; Some(f(server, driver)) } pub unsafe fn jackctl_server_start(server: *mut jackctl_server_t) -> Option { - let f = FUNCTIONS.jackctl_server_start_impl?; + let f = functions().jackctl_server_start_impl?; Some(f(server)) } pub unsafe fn jackctl_server_stop(server: *mut jackctl_server_t) -> Option { - let f = FUNCTIONS.jackctl_server_stop_impl?; + let f = functions().jackctl_server_stop_impl?; Some(f(server)) } pub unsafe fn jackctl_server_close(server: *mut jackctl_server_t) -> Option { - let f = FUNCTIONS.jackctl_server_close_impl?; + let f = functions().jackctl_server_close_impl?; Some(f(server)) } pub unsafe fn jackctl_server_get_drivers_list( server: *mut jackctl_server_t, ) -> Option<*const JSList> { - let f = FUNCTIONS.jackctl_server_get_drivers_list_impl?; + let f = functions().jackctl_server_get_drivers_list_impl?; Some(f(server)) } pub unsafe fn jackctl_server_get_parameters( server: *mut jackctl_server_t, ) -> Option<*const JSList> { - let f = FUNCTIONS.jackctl_server_get_parameters_impl?; + let f = functions().jackctl_server_get_parameters_impl?; Some(f(server)) } pub unsafe fn jackctl_server_get_internals_list( server: *mut jackctl_server_t, ) -> Option<*const JSList> { - let f = FUNCTIONS.jackctl_server_get_internals_list_impl?; + let f = functions().jackctl_server_get_internals_list_impl?; Some(f(server)) } pub unsafe fn jackctl_server_load_internal( server: *mut jackctl_server_t, internal: *mut jackctl_internal_t, ) -> Option { - let f = FUNCTIONS.jackctl_server_load_internal_impl?; + let f = functions().jackctl_server_load_internal_impl?; Some(f(server, internal)) } pub unsafe fn jackctl_server_unload_internal( server: *mut jackctl_server_t, internal: *mut jackctl_internal_t, ) -> Option { - let f = FUNCTIONS.jackctl_server_unload_internal_impl?; + let f = functions().jackctl_server_unload_internal_impl?; Some(f(server, internal)) } pub unsafe fn jackctl_server_add_slave( server: *mut jackctl_server_t, driver: *mut jackctl_driver_t, ) -> Option { - let f = FUNCTIONS.jackctl_server_add_slave_impl?; + let f = functions().jackctl_server_add_slave_impl?; Some(f(server, driver)) } pub unsafe fn jackctl_server_remove_slave( server: *mut jackctl_server_t, driver: *mut jackctl_driver_t, ) -> Option { - let f = FUNCTIONS.jackctl_server_remove_slave_impl?; + let f = functions().jackctl_server_remove_slave_impl?; Some(f(server, driver)) } pub unsafe fn jackctl_server_switch_master( server: *mut jackctl_server_t, driver: *mut jackctl_driver_t, ) -> Option { - let f = FUNCTIONS.jackctl_server_switch_master_impl?; + let f = functions().jackctl_server_switch_master_impl?; Some(f(server, driver)) } pub unsafe fn jackctl_driver_get_name( driver: *mut jackctl_driver_t, ) -> Option<*const ::libc::c_char> { - let f = FUNCTIONS.jackctl_driver_get_name_impl?; + let f = functions().jackctl_driver_get_name_impl?; Some(f(driver)) } pub unsafe fn jackctl_driver_get_type( driver: *mut jackctl_driver_t, ) -> Option { - let f = FUNCTIONS.jackctl_driver_get_type_impl?; + let f = functions().jackctl_driver_get_type_impl?; Some(f(driver)) } pub unsafe fn jackctl_driver_get_parameters( driver: *mut jackctl_driver_t, ) -> Option<*const JSList> { - let f = FUNCTIONS.jackctl_driver_get_parameters_impl?; + let f = functions().jackctl_driver_get_parameters_impl?; Some(f(driver)) } pub unsafe fn jackctl_driver_params_parse( @@ -3604,108 +3640,108 @@ pub unsafe fn jackctl_driver_params_parse( argc: ::libc::c_int, argv: *mut *mut ::libc::c_char, ) -> Option<::libc::c_int> { - let f = FUNCTIONS.jackctl_driver_params_parse_impl?; + let f = functions().jackctl_driver_params_parse_impl?; Some(f(driver, argc, argv)) } pub unsafe fn jackctl_internal_get_name( internal: *mut jackctl_internal_t, ) -> Option<*const ::libc::c_char> { - let f = FUNCTIONS.jackctl_internal_get_name_impl?; + let f = functions().jackctl_internal_get_name_impl?; Some(f(internal)) } pub unsafe fn jackctl_internal_get_parameters( internal: *mut jackctl_internal_t, ) -> Option<*const JSList> { - let f = FUNCTIONS.jackctl_internal_get_parameters_impl?; + let f = functions().jackctl_internal_get_parameters_impl?; Some(f(internal)) } pub unsafe fn jackctl_parameter_get_name( parameter: *mut jackctl_parameter_t, ) -> Option<*const ::libc::c_char> { - let f = FUNCTIONS.jackctl_parameter_get_name_impl?; + let f = functions().jackctl_parameter_get_name_impl?; Some(f(parameter)) } pub unsafe fn jackctl_parameter_get_short_description( parameter: *mut jackctl_parameter_t, ) -> Option<*const ::libc::c_char> { - let f = FUNCTIONS.jackctl_parameter_get_short_description_impl?; + let f = functions().jackctl_parameter_get_short_description_impl?; Some(f(parameter)) } pub unsafe fn jackctl_parameter_get_long_description( parameter: *mut jackctl_parameter_t, ) -> Option<*const ::libc::c_char> { - let f = FUNCTIONS.jackctl_parameter_get_long_description_impl?; + let f = functions().jackctl_parameter_get_long_description_impl?; Some(f(parameter)) } pub unsafe fn jackctl_parameter_get_type( parameter: *mut jackctl_parameter_t, ) -> Option { - let f = FUNCTIONS.jackctl_parameter_get_type_impl?; + let f = functions().jackctl_parameter_get_type_impl?; Some(f(parameter)) } pub unsafe fn jackctl_parameter_get_id( parameter: *mut jackctl_parameter_t, ) -> Option<::libc::c_char> { - let f = FUNCTIONS.jackctl_parameter_get_id_impl?; + let f = functions().jackctl_parameter_get_id_impl?; Some(f(parameter)) } pub unsafe fn jackctl_parameter_is_set(parameter: *mut jackctl_parameter_t) -> Option { - let f = FUNCTIONS.jackctl_parameter_is_set_impl?; + let f = functions().jackctl_parameter_is_set_impl?; Some(f(parameter)) } pub unsafe fn jackctl_parameter_reset(parameter: *mut jackctl_parameter_t) -> Option { - let f = FUNCTIONS.jackctl_parameter_reset_impl?; + let f = functions().jackctl_parameter_reset_impl?; Some(f(parameter)) } pub unsafe fn jackctl_parameter_get_value( parameter: *mut jackctl_parameter_t, ) -> Option { - let f = FUNCTIONS.jackctl_parameter_get_value_impl?; + let f = functions().jackctl_parameter_get_value_impl?; Some(f(parameter)) } pub unsafe fn jackctl_parameter_set_value( parameter: *mut jackctl_parameter_t, value_ptr: *const Union_jackctl_parameter_value, ) -> Option { - let f = FUNCTIONS.jackctl_parameter_set_value_impl?; + let f = functions().jackctl_parameter_set_value_impl?; Some(f(parameter, value_ptr)) } pub unsafe fn jackctl_parameter_get_default_value( parameter: *mut jackctl_parameter_t, ) -> Option { - let f = FUNCTIONS.jackctl_parameter_get_default_value_impl?; + let f = functions().jackctl_parameter_get_default_value_impl?; Some(f(parameter)) } pub unsafe fn jackctl_parameter_has_range_constraint( parameter: *mut jackctl_parameter_t, ) -> Option { - let f = FUNCTIONS.jackctl_parameter_has_range_constraint_impl?; + let f = functions().jackctl_parameter_has_range_constraint_impl?; Some(f(parameter)) } pub unsafe fn jackctl_parameter_has_enum_constraint( parameter: *mut jackctl_parameter_t, ) -> Option { - let f = FUNCTIONS.jackctl_parameter_has_enum_constraint_impl?; + let f = functions().jackctl_parameter_has_enum_constraint_impl?; Some(f(parameter)) } pub unsafe fn jackctl_parameter_get_enum_constraints_count( parameter: *mut jackctl_parameter_t, ) -> Option { - let f = FUNCTIONS.jackctl_parameter_get_enum_constraints_count_impl?; + let f = functions().jackctl_parameter_get_enum_constraints_count_impl?; Some(f(parameter)) } pub unsafe fn jackctl_parameter_get_enum_constraint_value( parameter: *mut jackctl_parameter_t, index: u32, ) -> Option { - let f = FUNCTIONS.jackctl_parameter_get_enum_constraint_value_impl?; + let f = functions().jackctl_parameter_get_enum_constraint_value_impl?; Some(f(parameter, index)) } pub unsafe fn jackctl_parameter_get_enum_constraint_description( parameter: *mut jackctl_parameter_t, index: u32, ) -> Option<*const ::libc::c_char> { - let f = FUNCTIONS.jackctl_parameter_get_enum_constraint_description_impl?; + let f = functions().jackctl_parameter_get_enum_constraint_description_impl?; Some(f(parameter, index)) } pub unsafe fn jackctl_parameter_get_range_constraint( @@ -3713,19 +3749,19 @@ pub unsafe fn jackctl_parameter_get_range_constraint( min_ptr: *mut Union_jackctl_parameter_value, max_ptr: *mut Union_jackctl_parameter_value, ) -> Option<()> { - let f = FUNCTIONS.jackctl_parameter_get_range_constraint_impl?; + let f = functions().jackctl_parameter_get_range_constraint_impl?; Some(f(parameter, min_ptr, max_ptr)) } pub unsafe fn jackctl_parameter_constraint_is_strict( parameter: *mut jackctl_parameter_t, ) -> Option { - let f = FUNCTIONS.jackctl_parameter_constraint_is_strict_impl?; + let f = functions().jackctl_parameter_constraint_is_strict_impl?; Some(f(parameter)) } pub unsafe fn jackctl_parameter_constraint_is_fake_value( parameter: *mut jackctl_parameter_t, ) -> Option { - let f = FUNCTIONS.jackctl_parameter_constraint_is_fake_value_impl?; + let f = functions().jackctl_parameter_constraint_is_fake_value_impl?; Some(f(parameter)) } pub unsafe fn jack_set_property( @@ -3735,7 +3771,7 @@ pub unsafe fn jack_set_property( value: *const ::libc::c_char, _type: *const ::libc::c_char, ) -> ::libc::c_int { - let f = FUNCTIONS.jack_set_property_impl; + let f = functions().jack_set_property_impl; f(arg1, subject, key, value, _type) } pub unsafe fn jack_get_property( @@ -3744,25 +3780,25 @@ pub unsafe fn jack_get_property( value: *mut *mut ::libc::c_char, _type: *mut *mut ::libc::c_char, ) -> ::libc::c_int { - let f = FUNCTIONS.jack_get_property_impl; + let f = functions().jack_get_property_impl; f(subject, key, value, _type) } pub unsafe fn jack_free_description( desc: *mut jack_description_t, free_description_itself: ::libc::c_int, ) -> () { - let f = FUNCTIONS.jack_free_description_impl; + let f = functions().jack_free_description_impl; f(desc, free_description_itself) } pub unsafe fn jack_get_properties( subject: jack_uuid_t, desc: *mut jack_description_t, ) -> ::libc::c_int { - let f = FUNCTIONS.jack_get_properties_impl; + let f = functions().jack_get_properties_impl; f(subject, desc) } pub unsafe fn jack_get_all_properties(descs: *mut *mut jack_description_t) -> ::libc::c_int { - let f = FUNCTIONS.jack_get_all_properties_impl; + let f = functions().jack_get_all_properties_impl; f(descs) } pub unsafe fn jack_remove_property( @@ -3770,18 +3806,18 @@ pub unsafe fn jack_remove_property( subject: jack_uuid_t, key: *const ::libc::c_char, ) -> ::libc::c_int { - let f = FUNCTIONS.jack_remove_property_impl; + let f = functions().jack_remove_property_impl; f(client, subject, key) } pub unsafe fn jack_remove_properties( client: *mut jack_client_t, subject: jack_uuid_t, ) -> ::libc::c_int { - let f = FUNCTIONS.jack_remove_properties_impl; + let f = functions().jack_remove_properties_impl; f(client, subject) } pub unsafe fn jack_remove_all_properties(client: *mut jack_client_t) -> ::libc::c_int { - let f = FUNCTIONS.jack_remove_all_properties_impl; + let f = functions().jack_remove_all_properties_impl; f(client) } pub unsafe fn jack_set_property_change_callback( @@ -3789,14 +3825,14 @@ pub unsafe fn jack_set_property_change_callback( callback: JackPropertyChangeCallback, arg: *mut ::libc::c_void, ) -> ::libc::c_int { - let f = FUNCTIONS.jack_set_property_change_callback_impl; + let f = functions().jack_set_property_change_callback_impl; f(client, callback, arg) } pub unsafe fn jack_get_internal_client_name( client: *mut jack_client_t, intclient: jack_intclient_t, ) -> Option<*mut ::libc::c_char> { - let f = FUNCTIONS.jack_get_internal_client_name_impl?; + let f = functions().jack_get_internal_client_name_impl?; Some(f(client, intclient)) } pub unsafe fn jack_internal_client_handle( @@ -3804,9 +3840,11 @@ pub unsafe fn jack_internal_client_handle( client_name: *const ::libc::c_char, status: *mut jack_status_t, ) -> Option { - let f = FUNCTIONS.jack_internal_client_handle_impl?; + let f = functions().jack_internal_client_handle_impl?; Some(f(client, client_name, status)) } +/// `jack_internal_client_load` is variadic in C. This wrapper always passes both `load_name` and +/// `load_init`, so `options` should contain `JackLoadName | JackLoadInit`. pub unsafe fn jack_internal_client_load( client: *mut jack_client_t, client_name: *const ::libc::c_char, @@ -3815,7 +3853,7 @@ pub unsafe fn jack_internal_client_load( load_name: *const ::libc::c_char, load_init: *const ::libc::c_char, ) -> Option { - let f = FUNCTIONS.jack_internal_client_load_impl?; + let f = functions().jack_internal_client_load_impl?; Some(f( client, client_name, @@ -3829,23 +3867,23 @@ pub unsafe fn jack_internal_client_unload( client: *mut jack_client_t, intclient: jack_intclient_t, ) -> Option { - let f = FUNCTIONS.jack_internal_client_unload_impl?; + let f = functions().jack_internal_client_unload_impl?; Some(f(client, intclient)) } pub unsafe fn jack_get_max_delayed_usecs(client: *mut jack_client_t) -> ::libc::c_float { - let f = FUNCTIONS.jack_get_max_delayed_usecs_impl; + let f = functions().jack_get_max_delayed_usecs_impl; f(client) } pub unsafe fn jack_get_xrun_delayed_usecs(client: *mut jack_client_t) -> ::libc::c_float { - let f = FUNCTIONS.jack_get_xrun_delayed_usecs_impl; + let f = functions().jack_get_xrun_delayed_usecs_impl; f(client) } pub unsafe fn jack_reset_max_delayed_usecs(client: *mut jack_client_t) -> () { - let f = FUNCTIONS.jack_reset_max_delayed_usecs_impl; + let f = functions().jack_reset_max_delayed_usecs_impl; f(client) } pub unsafe fn jack_midi_get_event_count(port_buffer: *mut ::libc::c_void) -> u32 { - let f = FUNCTIONS.jack_midi_get_event_count_impl; + let f = functions().jack_midi_get_event_count_impl; f(port_buffer) } pub unsafe fn jack_midi_event_get( @@ -3853,15 +3891,15 @@ pub unsafe fn jack_midi_event_get( port_buffer: *mut ::libc::c_void, event_index: u32, ) -> ::libc::c_int { - let f = FUNCTIONS.jack_midi_event_get_impl; + let f = functions().jack_midi_event_get_impl; f(event, port_buffer, event_index) } pub unsafe fn jack_midi_clear_buffer(port_buffer: *mut ::libc::c_void) -> () { - let f = FUNCTIONS.jack_midi_clear_buffer_impl; + let f = functions().jack_midi_clear_buffer_impl; f(port_buffer) } pub unsafe fn jack_midi_max_event_size(port_buffer: *mut ::libc::c_void) -> ::libc::size_t { - let f = FUNCTIONS.jack_midi_max_event_size_impl; + let f = functions().jack_midi_max_event_size_impl; f(port_buffer) } pub unsafe fn jack_midi_event_reserve( @@ -3869,7 +3907,7 @@ pub unsafe fn jack_midi_event_reserve( time: jack_nframes_t, data_size: ::libc::size_t, ) -> *mut jack_midi_data_t { - let f = FUNCTIONS.jack_midi_event_reserve_impl; + let f = functions().jack_midi_event_reserve_impl; f(port_buffer, time, data_size) } pub unsafe fn jack_midi_event_write( @@ -3878,33 +3916,33 @@ pub unsafe fn jack_midi_event_write( data: *const jack_midi_data_t, data_size: ::libc::size_t, ) -> ::libc::c_int { - let f = FUNCTIONS.jack_midi_event_write_impl; + let f = functions().jack_midi_event_write_impl; f(port_buffer, time, data, data_size) } pub unsafe fn jack_midi_get_lost_event_count(port_buffer: *mut ::libc::c_void) -> u32 { - let f = FUNCTIONS.jack_midi_get_lost_event_count_impl; + let f = functions().jack_midi_get_lost_event_count_impl; f(port_buffer) } pub unsafe fn jack_ringbuffer_create(sz: ::libc::size_t) -> *mut jack_ringbuffer_t { - let f = FUNCTIONS.jack_ringbuffer_create_impl; + let f = functions().jack_ringbuffer_create_impl; f(sz) } pub unsafe fn jack_ringbuffer_free(rb: *mut jack_ringbuffer_t) -> () { - let f = FUNCTIONS.jack_ringbuffer_free_impl; + let f = functions().jack_ringbuffer_free_impl; f(rb) } pub unsafe fn jack_ringbuffer_get_read_vector( rb: *const jack_ringbuffer_t, vec: *mut jack_ringbuffer_data_t, ) -> () { - let f = FUNCTIONS.jack_ringbuffer_get_read_vector_impl; + let f = functions().jack_ringbuffer_get_read_vector_impl; f(rb, vec) } pub unsafe fn jack_ringbuffer_get_write_vector( rb: *const jack_ringbuffer_t, vec: *mut jack_ringbuffer_data_t, ) -> () { - let f = FUNCTIONS.jack_ringbuffer_get_write_vector_impl; + let f = functions().jack_ringbuffer_get_write_vector_impl; f(rb, vec) } pub unsafe fn jack_ringbuffer_read( @@ -3912,7 +3950,7 @@ pub unsafe fn jack_ringbuffer_read( dest: *mut ::libc::c_char, cnt: ::libc::size_t, ) -> ::libc::size_t { - let f = FUNCTIONS.jack_ringbuffer_read_impl; + let f = functions().jack_ringbuffer_read_impl; f(rb, dest, cnt) } pub unsafe fn jack_ringbuffer_peek( @@ -3920,23 +3958,23 @@ pub unsafe fn jack_ringbuffer_peek( dest: *mut ::libc::c_char, cnt: ::libc::size_t, ) -> ::libc::size_t { - let f = FUNCTIONS.jack_ringbuffer_peek_impl; + let f = functions().jack_ringbuffer_peek_impl; f(rb, dest, cnt) } pub unsafe fn jack_ringbuffer_read_advance(rb: *mut jack_ringbuffer_t, cnt: ::libc::size_t) -> () { - let f = FUNCTIONS.jack_ringbuffer_read_advance_impl; + let f = functions().jack_ringbuffer_read_advance_impl; f(rb, cnt) } pub unsafe fn jack_ringbuffer_read_space(rb: *const jack_ringbuffer_t) -> ::libc::size_t { - let f = FUNCTIONS.jack_ringbuffer_read_space_impl; + let f = functions().jack_ringbuffer_read_space_impl; f(rb) } pub unsafe fn jack_ringbuffer_mlock(rb: *mut jack_ringbuffer_t) -> ::libc::c_int { - let f = FUNCTIONS.jack_ringbuffer_mlock_impl; + let f = functions().jack_ringbuffer_mlock_impl; f(rb) } pub unsafe fn jack_ringbuffer_reset(rb: *mut jack_ringbuffer_t) -> () { - let f = FUNCTIONS.jack_ringbuffer_reset_impl; + let f = functions().jack_ringbuffer_reset_impl; f(rb) } pub unsafe fn jack_ringbuffer_write( @@ -3944,45 +3982,59 @@ pub unsafe fn jack_ringbuffer_write( src: *const ::libc::c_char, cnt: ::libc::size_t, ) -> ::libc::size_t { - let f = FUNCTIONS.jack_ringbuffer_write_impl; + let f = functions().jack_ringbuffer_write_impl; f(rb, src, cnt) } pub unsafe fn jack_ringbuffer_write_advance(rb: *mut jack_ringbuffer_t, cnt: ::libc::size_t) -> () { - let f = FUNCTIONS.jack_ringbuffer_write_advance_impl; + let f = functions().jack_ringbuffer_write_advance_impl; f(rb, cnt) } pub unsafe fn jack_ringbuffer_write_space(rb: *const jack_ringbuffer_t) -> ::libc::size_t { - let f = FUNCTIONS.jack_ringbuffer_write_space_impl; + let f = functions().jack_ringbuffer_write_space_impl; f(rb) } pub unsafe fn jack_uuid_to_index(arg1: jack_uuid_t) -> u32 { - let f = FUNCTIONS.jack_uuid_to_index_impl; + let f = functions().jack_uuid_to_index_impl; f(arg1) } pub unsafe fn jack_uuid_compare(arg1: jack_uuid_t, arg2: jack_uuid_t) -> ::std::os::raw::c_int { - let f = FUNCTIONS.jack_uuid_compare_impl; + let f = functions().jack_uuid_compare_impl; f(arg1, arg2) } pub unsafe fn jack_uuid_copy(dst: *mut jack_uuid_t, src: jack_uuid_t) -> () { - let f = FUNCTIONS.jack_uuid_copy_impl; + let f = functions().jack_uuid_copy_impl; f(dst, src) } pub unsafe fn jack_uuid_clear(arg1: *mut jack_uuid_t) -> () { - let f = FUNCTIONS.jack_uuid_clear_impl; + let f = functions().jack_uuid_clear_impl; f(arg1) } pub unsafe fn jack_uuid_parse( buf: *const ::std::os::raw::c_char, arg1: *mut jack_uuid_t, ) -> ::std::os::raw::c_int { - let f = FUNCTIONS.jack_uuid_parse_impl; + let f = functions().jack_uuid_parse_impl; f(buf, arg1) } pub unsafe fn jack_uuid_unparse(arg1: jack_uuid_t, buf: *mut ::std::os::raw::c_char) -> () { - let f = FUNCTIONS.jack_uuid_unparse_impl; + let f = functions().jack_uuid_unparse_impl; f(arg1, buf) } pub unsafe fn jack_uuid_empty(arg1: jack_uuid_t) -> ::std::os::raw::c_int { - let f = FUNCTIONS.jack_uuid_empty_impl; + let f = functions().jack_uuid_empty_impl; f(arg1) } + +#[cfg(test)] +mod tests { + #[test] + #[cfg(target_os = "linux")] + fn loading_from_a_library_without_jack_returns_an_error() { + let library = unsafe { libloading::Library::new("libc.so.6") }.unwrap(); + let err = match unsafe { super::load_functions(&library) } { + Ok(_) => panic!("libc should not provide JACK functions"), + Err(err) => err, + }; + assert!(err.contains("jack_"), "{}", err); + } +} diff --git a/jack-sys/src/lib.rs b/jack-sys/src/lib.rs index ff51fe672..c41f9fbdf 100644 --- a/jack-sys/src/lib.rs +++ b/jack-sys/src/lib.rs @@ -26,10 +26,18 @@ lazy_static! { /// the library. /// /// # Example -/// ```rust -/// let symbol = library.get:: ::libc::c_int>(b"jack_release_timebase").unwrap(); -/// let raw_symbol = symbol.into_raw(); -/// let func = *raw_symbol.deref() as unsafe extern "C" fn(client: *mut jack_client_t) -> ::libc::c_int; +/// ```no_run +/// use jack_sys::jack_client_t; +/// +/// let library = jack_sys::library().unwrap(); +/// let func = unsafe { +/// library +/// .get:: ::libc::c_int>( +/// b"jack_release_timebase", +/// ) +/// .unwrap() +/// }; +/// # let _ = func; /// ``` pub fn library() -> Result<&'static libloading::Library, impl std::error::Error> { LIB_RESULT.as_ref() diff --git a/src/client/async_client.rs b/src/client/async_client.rs index 7b3692962..5003cfe35 100644 --- a/src/client/async_client.rs +++ b/src/client/async_client.rs @@ -1,8 +1,6 @@ use jack_sys as j; use std::fmt; use std::fmt::Debug; -use std::mem; -use std::sync::atomic::AtomicBool; use super::callbacks::clear_callbacks; use super::callbacks::{CallbackContext, NotificationHandler, ProcessHandler}; @@ -54,26 +52,32 @@ where /// `notification_handler` and `process_handler` are consumed, but they are returned when /// `Client::deactivate` is called. pub fn new(client: Client, notification_handler: N, process_handler: P) -> Result { - let _m = CREATE_OR_DESTROY_CLIENT_MUTEX.lock().ok(); - unsafe { - let mut callback_context = Box::new(CallbackContext { - client, - notification: notification_handler, - process: process_handler, - is_valid_for_callback: AtomicBool::new(true), - has_panic: AtomicBool::new(false), - callback_lock: std::sync::Mutex::new(()), - }); - CallbackContext::register_callbacks(&mut callback_context)?; - let res = j::jack_activate(callback_context.client.raw()); - match res { - 0 => Ok(AsyncClient { - callback: Some(callback_context), - }), - _ => { - mem::forget(callback_context); - Err(Error::ClientActivationError) - } + let mut callback_context = Box::new(CallbackContext::new( + client, + notification_handler, + process_handler, + )); + let res = { + let _m = CREATE_OR_DESTROY_CLIENT_MUTEX.lock().ok(); + unsafe { Self::activate(&mut callback_context) } + }; + // On failure, `callback_context` is dropped here, after the mutex is released since + // `Client::drop` takes it too. Its `client` field is dropped first, which closes the + // client, so JACK can no longer call into the context once it is freed. + res.map(|()| AsyncClient { + callback: Some(callback_context), + }) + } + + /// Register the callbacks of `callback_context` and activate its client. On failure, the + /// callbacks are cleared again. + unsafe fn activate(callback_context: &mut Box>) -> Result<(), Error> { + CallbackContext::register_callbacks(callback_context)?; + match j::jack_activate(callback_context.client.raw()) { + 0 => Ok(()), + _ => { + clear_callbacks(callback_context.client.raw())?; + Err(Error::ClientActivationError) } } } @@ -97,8 +101,7 @@ impl AsyncClient { /// therefore unsafe to continue using. pub fn deactivate(self) -> Result<(Client, N, P), Error> { let mut c = self; - c.maybe_deactivate() - .map(|c| (c.client, c.notification, c.process)) + c.maybe_deactivate().map(|c| c.into_parts()) } // Helper function for deactivating. Any function that calls this should diff --git a/src/client/callbacks.rs b/src/client/callbacks.rs index eb85df6a6..d622cf165 100644 --- a/src/client/callbacks.rs +++ b/src/client/callbacks.rs @@ -1,8 +1,10 @@ use jack_sys as j; use std::{ + cell::UnsafeCell, ffi, panic::catch_unwind, sync::atomic::{AtomicBool, Ordering}, + sync::{Mutex, MutexGuard}, }; use crate::{Client, ClientStatus, Control, Error, Frames, PortId, ProcessScope}; @@ -14,17 +16,21 @@ pub trait NotificationHandler: Send { /// handled. /// /// It does not need to be suitable for real-time execution. + /// + /// Unlike the other methods, this takes `&self`: it runs on JACK's process thread, possibly at + /// the same time as other notifications on the notification thread. Use interior mutability + /// (for example an atomic) for any state it updates. fn thread_init(&self, _: &Client) {} /// Called when the JACK server shuts down the client thread. The function must be written as if /// it were an asynchronous POSIX signal handler --- use only async-safe functions, and remember - /// that it is executed from another thread. A typical funcion might set a flag or write to a + /// that it is executed from another thread. A typical function might set a flag or write to a /// pipe so that the rest of the application knows that the JACK client thread has shut down. /// - /// # Safety /// See for details about - /// what is legal in an async-signal-safe callback. - unsafe fn shutdown(&mut self, _status: ClientStatus, _reason: &str) {} + /// what is legal in an async-signal-safe callback. This is a requirement on the + /// implementation, which is why the method itself is safe to call. + fn shutdown(&mut self, _status: ClientStatus, _reason: &str) {} /// Called whenever "freewheel" mode is entered or leaving. fn freewheel(&mut self, _: &Client, _is_freewheel_enabled: bool) {} @@ -127,11 +133,12 @@ where N: 'static + Send + Sync + NotificationHandler, P: 'static + Send + ProcessHandler, { + let _defer_cancel = crate::jack_utils::DeferThreadCancellation::new(); let res = catch_unwind(|| { let Some(ctx) = CallbackContext::::from_raw(data) else { return; }; - ctx.notification.thread_init(&ctx.client); + ctx.notification().thread_init(&ctx.client); }); if let Err(err) = res { if let Some(ctx) = CallbackContext::::from_raw(data) { @@ -150,15 +157,19 @@ unsafe extern "C" fn shutdown( N: 'static + Send + Sync + NotificationHandler, P: 'static + Send + ProcessHandler, { + let _defer_cancel = crate::jack_utils::DeferThreadCancellation::new(); let res = catch_unwind(|| { let Some(ctx) = CallbackContext::::from_raw(data) else { return; }; - let cstr = ffi::CStr::from_ptr(reason); - let reason_str = cstr.to_str().unwrap_or("Failed to interpret error."); - ctx.notification.shutdown( + let reason = if reason.is_null() { + std::borrow::Cow::Borrowed("") + } else { + ffi::CStr::from_ptr(reason).to_string_lossy() + }; + ctx.notification().shutdown( ClientStatus::from_bits(code).unwrap_or_else(ClientStatus::empty), - reason_str, + &reason, ); }); if let Err(err) = res { @@ -175,6 +186,7 @@ where N: 'static + Send + Sync + NotificationHandler, P: 'static + Send + ProcessHandler, { + let _defer_cancel = crate::jack_utils::DeferThreadCancellation::new(); let Some(ctx_ref) = (unsafe { (data as *const CallbackContext).as_ref() }) else { return Control::Quit.to_ffi(); }; @@ -186,7 +198,7 @@ where return Control::Quit; }; let scope = ProcessScope::from_raw(n_frames, ctx.client.raw()); - let c = ctx.process.process(&ctx.client, &scope); + let c = ctx.process().process(&ctx.client, &scope); if c == Control::Quit { ctx.mark_invalid(false); } @@ -214,18 +226,16 @@ where N: 'static + Send + Sync + NotificationHandler, P: 'static + Send + ProcessHandler, { + let _defer_cancel = crate::jack_utils::DeferThreadCancellation::new(); let res = catch_unwind(|| { let Some(ctx) = CallbackContext::::from_raw(data) else { return false; }; - let is_ready = ctx.process.sync( + let is_ready = ctx.process().sync( &ctx.client, crate::Transport::state_from_ffi(state), &*(pos as *mut crate::TransportPosition), ); - if !is_ready { - ctx.mark_invalid(false); - } is_ready }); match res { @@ -247,12 +257,13 @@ where N: 'static + Send + Sync + NotificationHandler, P: 'static + Send + ProcessHandler, { + let _defer_cancel = crate::jack_utils::DeferThreadCancellation::new(); let res = catch_unwind(|| { let Some(ctx) = CallbackContext::::from_raw(data) else { return; }; let is_starting = !matches!(starting, 0); - ctx.notification.freewheel(&ctx.client, is_starting); + ctx.notification().freewheel(&ctx.client, is_starting); }); if let Err(err) = res { if let Some(ctx) = CallbackContext::::from_raw(data) { @@ -268,6 +279,7 @@ where N: 'static + Send + Sync + NotificationHandler, P: 'static + Send + ProcessHandler, { + let _defer_cancel = crate::jack_utils::DeferThreadCancellation::new(); let Some(ctx_ref) = (unsafe { (data as *const CallbackContext).as_ref() }) else { return Control::Quit.to_ffi(); }; @@ -278,7 +290,7 @@ where let Some(ctx) = CallbackContext::::from_raw(data) else { return Control::Quit; }; - let c = ctx.process.buffer_size(&ctx.client, n_frames); + let c = ctx.process().buffer_size(&ctx.client, n_frames); if c == Control::Quit { ctx.mark_invalid(false); } @@ -302,11 +314,12 @@ where N: 'static + Send + Sync + NotificationHandler, P: 'static + Send + ProcessHandler, { + let _defer_cancel = crate::jack_utils::DeferThreadCancellation::new(); let res = catch_unwind(|| { let Some(ctx) = CallbackContext::::from_raw(data) else { return Control::Quit; }; - let c = ctx.notification.sample_rate(&ctx.client, n_frames); + let c = ctx.notification().sample_rate(&ctx.client, n_frames); if c == Control::Quit { ctx.mark_invalid(false); } @@ -333,14 +346,15 @@ unsafe extern "C" fn client_registration( N: 'static + Send + Sync + NotificationHandler, P: 'static + Send + ProcessHandler, { + let _defer_cancel = crate::jack_utils::DeferThreadCancellation::new(); let res = catch_unwind(|| { let Some(ctx) = CallbackContext::::from_raw(data) else { return; }; - let name = ffi::CStr::from_ptr(name).to_str().unwrap(); + let name = ffi::CStr::from_ptr(name).to_string_lossy(); let register = !matches!(register, 0); - ctx.notification - .client_registration(&ctx.client, name, register); + ctx.notification() + .client_registration(&ctx.client, &name, register); }); if let Err(err) = res { if let Some(ctx) = CallbackContext::::from_raw(data) { @@ -359,12 +373,13 @@ unsafe extern "C" fn port_registration( N: 'static + Send + Sync + NotificationHandler, P: 'static + Send + ProcessHandler, { + let _defer_cancel = crate::jack_utils::DeferThreadCancellation::new(); let res = catch_unwind(|| { let Some(ctx) = CallbackContext::::from_raw(data) else { return; }; let register = !matches!(register, 0); - ctx.notification + ctx.notification() .port_registration(&ctx.client, port_id, register); }); if let Err(err) = res { @@ -376,7 +391,6 @@ unsafe extern "C" fn port_registration( } } -#[allow(dead_code)] // TODO: remove once it can be registered unsafe extern "C" fn port_rename( port_id: PortId, old_name: *const libc::c_char, @@ -387,15 +401,16 @@ where N: 'static + Send + Sync + NotificationHandler, P: 'static + Send + ProcessHandler, { + let _defer_cancel = crate::jack_utils::DeferThreadCancellation::new(); let res = catch_unwind(|| { let Some(ctx) = CallbackContext::::from_raw(data) else { return Control::Quit; }; - let old_name = ffi::CStr::from_ptr(old_name).to_str().unwrap(); - let new_name = ffi::CStr::from_ptr(new_name).to_str().unwrap(); + let old_name = ffi::CStr::from_ptr(old_name).to_string_lossy(); + let new_name = ffi::CStr::from_ptr(new_name).to_string_lossy(); let c = ctx - .notification - .port_rename(&ctx.client, port_id, old_name, new_name); + .notification() + .port_rename(&ctx.client, port_id, &old_name, &new_name); if c == Control::Quit { ctx.mark_invalid(false); } @@ -423,12 +438,13 @@ unsafe extern "C" fn port_connect( N: 'static + Send + Sync + NotificationHandler, P: 'static + Send + ProcessHandler, { + let _defer_cancel = crate::jack_utils::DeferThreadCancellation::new(); let res = catch_unwind(|| { let Some(ctx) = CallbackContext::::from_raw(data) else { return; }; let are_connected = !matches!(connect, 0); - ctx.notification + ctx.notification() .ports_connected(&ctx.client, port_id_a, port_id_b, are_connected); }); if let Err(err) = res { @@ -445,11 +461,12 @@ where N: 'static + Send + Sync + NotificationHandler, P: 'static + Send + ProcessHandler, { + let _defer_cancel = crate::jack_utils::DeferThreadCancellation::new(); let res = catch_unwind(|| { let Some(ctx) = CallbackContext::::from_raw(data) else { return Control::Quit; }; - let c = ctx.notification.graph_reorder(&ctx.client); + let c = ctx.notification().graph_reorder(&ctx.client); if c == Control::Quit { ctx.mark_invalid(false); } @@ -473,11 +490,12 @@ where N: 'static + Send + Sync + NotificationHandler, P: 'static + Send + ProcessHandler, { + let _defer_cancel = crate::jack_utils::DeferThreadCancellation::new(); let res = catch_unwind(|| { let Some(ctx) = CallbackContext::::from_raw(data) else { return Control::Quit; }; - let c = ctx.notification.xrun(&ctx.client); + let c = ctx.notification().xrun(&ctx.client); if c == Control::Quit { ctx.mark_invalid(false); } @@ -500,29 +518,48 @@ where /// /// This is mostly for use within the jack crate itself. /// -/// Returns `Err(Error::CallbackDeregistrationError)` on failure. -/// -/// # Unsafe -/// -/// * Uses ffi calls, be careful. +/// Every callback that `CallbackContext::register_callbacks` sets must be cleared here. Otherwise +/// JACK keeps a pointer to the `CallbackContext` after it has been freed and may call into it, for +/// example when the server shuts down while the deactivated `Client` is still open. /// -/// # TODO +/// # Safety /// -/// * Implement correctly. Freezes on my system. Maybe this makes sense now? it doesn't disturb my program +/// * `client` must be a valid, deactivated client. pub unsafe fn clear_callbacks(client: *mut j::jack_client_t) -> Result<(), Error> { - j::jack_set_thread_init_callback(client, None, std::ptr::null_mut()); - j::jack_set_process_callback(client, None, std::ptr::null_mut()); + let null = std::ptr::null_mut(); + j::jack_set_thread_init_callback(client, None, null); + j::jack_on_info_shutdown(client, None, null); + j::jack_set_process_callback(client, None, null); + j::jack_set_sync_callback(client, None, null); + j::jack_set_freewheel_callback(client, None, null); + j::jack_set_buffer_size_callback(client, None, null); + j::jack_set_sample_rate_callback(client, None, null); + j::jack_set_client_registration_callback(client, None, null); + j::jack_set_port_registration_callback(client, None, null); + j::jack_set_port_connect_callback(client, None, null); + j::jack_set_graph_order_callback(client, None, null); + j::jack_set_xrun_callback(client, None, null); Ok(()) } /// The information used by JACK to process data. +/// +/// JACK calls into this context from several threads at once: the process thread (`process`, +/// `sync` and `thread_init`) and the notification thread (all other callbacks). Callbacks therefore +/// only ever get a shared `&CallbackContext`. The handlers are reached through interior mutability: +/// +/// * `notification` is behind a `Mutex`. Notifications are not real-time, and `thread_init` runs +/// on the process thread while the notification thread may be using the handler. +/// * `process` is behind an `UnsafeCell`. JACK calls `process` and `sync` on the process thread, +/// and calls `buffer_size` only while the process cycle is stopped, so the accesses never +/// overlap. pub struct CallbackContext { /// The underlying JACK client. pub client: Client, /// The handler for notifications. - pub notification: N, + notification: Mutex, /// The handler for processing. - pub process: P, + process: UnsafeCell

, /// True if the callback is valid for callbacks. /// /// This becomes false after quit an event that causes processing to quit. @@ -535,15 +572,38 @@ pub struct CallbackContext { pub callback_lock: std::sync::Mutex<()>, } +impl CallbackContext { + /// Create a new context that is valid for callbacks. + pub fn new(client: Client, notification: N, process: P) -> Self { + CallbackContext { + client, + notification: Mutex::new(notification), + process: UnsafeCell::new(process), + is_valid_for_callback: AtomicBool::new(true), + has_panic: AtomicBool::new(false), + callback_lock: std::sync::Mutex::new(()), + } + } + + /// Consume the context and return its parts. + pub fn into_parts(self) -> (Client, N, P) { + let notification = self + .notification + .into_inner() + .unwrap_or_else(|err| err.into_inner()); + (self.client, notification, self.process.into_inner()) + } +} + impl CallbackContext where N: 'static + Send + Sync + NotificationHandler, P: 'static + Send + ProcessHandler, { - pub unsafe fn from_raw<'a>(ptr: *mut libc::c_void) -> Option<&'a mut CallbackContext> { + pub unsafe fn from_raw<'a>(ptr: *mut libc::c_void) -> Option<&'a CallbackContext> { debug_assert!(!ptr.is_null()); - let obj_ptr = ptr as *mut CallbackContext; - let obj_ref = &mut *obj_ptr; + let obj_ptr = ptr as *const CallbackContext; + let obj_ref = &*obj_ptr; if obj_ref.is_valid_for_callback.load(Ordering::Relaxed) { Some(obj_ref) } else { @@ -551,6 +611,26 @@ where } } + /// Lock the notification handler. + /// + /// A poisoned lock is still handed out. A panic in a handler already marks the context as + /// invalid, so no further callbacks will reach it. + fn notification(&self) -> MutexGuard<'_, N> { + self.notification + .lock() + .unwrap_or_else(|err| err.into_inner()) + } + + /// Get the process handler. + /// + /// # Safety + /// Must only be called from JACK's process thread, or from the buffer size callback while the + /// process cycle is stopped. The returned reference must not outlive the callback. + #[allow(clippy::mut_from_ref)] + unsafe fn process(&self) -> &mut P { + &mut *self.process.get() + } + /// Mark the callback context as invalid. /// /// This usually happens after a panic or when a callback returns `Control::Quit`. @@ -559,9 +639,11 @@ where /// as `buffer_size` and continues invoking `process`, so we rely on `is_valid_for_callback` to /// prevent invoking user callbacks after quitting or panicking. #[cold] - pub fn mark_invalid(&mut self, did_panic: bool) { + pub fn mark_invalid(&self, did_panic: bool) { self.is_valid_for_callback.store(false, Ordering::Relaxed); - self.has_panic.store(did_panic, Ordering::Relaxed); + if did_panic { + self.has_panic.store(true, Ordering::Relaxed); + } } fn raw(b: &mut Box) -> *mut libc::c_void { @@ -586,10 +668,12 @@ where /// registering new callbacks /// with the same client, or dropping the client. /// + /// If any registration fails, the callbacks are cleared again and + /// `Err(Error::CallbackRegistrationError)` is returned. JACK refuses registrations while the + /// client is active, for example. + /// /// # TODO /// - /// * Handled failed registrations - /// * Fix `jack_set_port_rename_callback` /// /// # Unsafe /// @@ -598,26 +682,259 @@ where pub unsafe fn register_callbacks(b: &mut Box) -> Result<(), Error> { let data_ptr = CallbackContext::raw(b); let client = b.client.raw(); - j::jack_set_thread_init_callback(client, Some(thread_init_callback::), data_ptr); j::jack_on_info_shutdown(client, Some(shutdown::), data_ptr); - j::jack_set_process_callback(client, Some(process::), data_ptr); - if P::SLOW_SYNC { - j::jack_set_sync_callback(client, Some(sync::), data_ptr); - } - j::jack_set_freewheel_callback(client, Some(freewheel::), data_ptr); - j::jack_set_buffer_size_callback(client, Some(buffer_size::), data_ptr); - j::jack_set_sample_rate_callback(client, Some(sample_rate::), data_ptr); - j::jack_set_client_registration_callback( - client, - Some(client_registration::), - data_ptr, - ); - j::jack_set_port_registration_callback(client, Some(port_registration::), data_ptr); - // doesn't compile for testing since it is a weak export - // j::jack_set_port_rename_callback(client, Some(port_rename::), data_ptr); - j::jack_set_graph_order_callback(client, Some(graph_order::), data_ptr); - j::jack_set_xrun_callback(client, Some(xrun::), data_ptr); + let results = [ + j::jack_set_thread_init_callback(client, Some(thread_init_callback::), data_ptr), + j::jack_set_process_callback(client, Some(process::), data_ptr), + if P::SLOW_SYNC { + j::jack_set_sync_callback(client, Some(sync::), data_ptr) + } else { + 0 + }, + j::jack_set_freewheel_callback(client, Some(freewheel::), data_ptr), + j::jack_set_buffer_size_callback(client, Some(buffer_size::), data_ptr), + j::jack_set_sample_rate_callback(client, Some(sample_rate::), data_ptr), + j::jack_set_client_registration_callback( + client, + Some(client_registration::), + data_ptr, + ), + j::jack_set_port_registration_callback( + client, + Some(port_registration::), + data_ptr, + ), + j::jack_set_port_rename_callback(client, Some(port_rename::), data_ptr), + j::jack_set_port_connect_callback(client, Some(port_connect::), data_ptr), + j::jack_set_graph_order_callback(client, Some(graph_order::), data_ptr), + j::jack_set_xrun_callback(client, Some(xrun::), data_ptr), + ]; + if results.iter().any(|&res| res != 0) { + clear_callbacks(client)?; + return Err(Error::CallbackRegistrationError); + } Ok(()) } } + +#[cfg(test)] +mod non_utf8_tests { + use super::*; + + #[derive(Default)] + struct Recorder { + client_names: Vec, + shutdown_reasons: Vec, + } + + impl NotificationHandler for Recorder { + fn shutdown(&mut self, _: ClientStatus, reason: &str) { + self.shutdown_reasons.push(reason.to_string()); + } + + fn client_registration(&mut self, _: &Client, name: &str, _: bool) { + self.client_names.push(name.to_string()); + } + } + + fn new_context() -> Box> { + let (client, _) = Client::new("", crate::ClientOptions::default()).unwrap(); + Box::new(CallbackContext::new(client, Recorder::default(), ())) + } + + #[test] + fn non_utf8_client_name_is_delivered_lossily() { + let mut ctx = new_context(); + let data = CallbackContext::raw(&mut ctx); + let name = b"bad\xff\0"; + unsafe { client_registration::(name.as_ptr().cast(), 1, data) }; + assert!(!ctx.has_panic.load(Ordering::Relaxed)); + assert_eq!( + ctx.notification().client_names, + vec!["bad\u{fffd}".to_string()] + ); + } + + #[test] + fn null_shutdown_reason_is_delivered_as_empty() { + let mut ctx = new_context(); + let data = CallbackContext::raw(&mut ctx); + unsafe { shutdown::(0, std::ptr::null(), data) }; + assert!(!ctx.has_panic.load(Ordering::Relaxed)); + assert_eq!(ctx.notification().shutdown_reasons, vec![String::new()]); + } +} + +#[cfg(test)] +mod tests { + use super::*; + use std::sync::atomic::AtomicUsize; + use std::sync::Arc; + + struct CountingHandler { + process_calls: Arc, + sync_results: Vec, + process_result: Control, + } + + impl ProcessHandler for CountingHandler { + const SLOW_SYNC: bool = true; + + fn process(&mut self, _: &Client, _: &ProcessScope) -> Control { + self.process_calls.fetch_add(1, Ordering::Relaxed); + self.process_result + } + + fn sync( + &mut self, + _: &Client, + _: crate::TransportState, + _: &crate::TransportPosition, + ) -> bool { + self.sync_results.remove(0) + } + } + + fn new_context( + sync_results: Vec, + process_result: Control, + ) -> (Box>, Arc) { + let (client, _) = Client::new("", crate::ClientOptions::default()).unwrap(); + let process_calls = Arc::new(AtomicUsize::new(0)); + let ctx = Box::new(CallbackContext::new( + client, + (), + CountingHandler { + process_calls: process_calls.clone(), + sync_results, + process_result, + }, + )); + (ctx, process_calls) + } + + #[test] + fn quit_from_process_stops_further_process_calls() { + let (mut ctx, process_calls) = new_context(vec![], Control::Quit); + let data = CallbackContext::raw(&mut ctx); + unsafe { + assert_eq!(process::<(), CountingHandler>(128, data), -1); + assert_eq!(process::<(), CountingHandler>(128, data), -1); + } + assert_eq!(process_calls.load(Ordering::Relaxed), 1); + assert!(!ctx.has_panic.load(Ordering::Relaxed)); + } + + #[test] + fn sync_not_ready_does_not_stop_processing() { + let (mut ctx, process_calls) = new_context(vec![false, true], Control::Continue); + let data = CallbackContext::raw(&mut ctx); + let mut pos = crate::TransportPosition::default(); + let pos_ptr = &mut pos as *mut crate::TransportPosition as *mut j::jack_position_t; + unsafe { + assert_eq!( + sync::<(), CountingHandler>(j::JackTransportStarting, pos_ptr, data), + 0 + ); + assert_eq!( + sync::<(), CountingHandler>(j::JackTransportStarting, pos_ptr, data), + 1 + ); + assert_eq!(process::<(), CountingHandler>(128, data), 0); + } + assert_eq!(process_calls.load(Ordering::Relaxed), 1); + } + + #[test] + fn quit_after_panic_keeps_panic_flag() { + let (ctx, _) = new_context(vec![], Control::Quit); + ctx.mark_invalid(true); + ctx.mark_invalid(false); + assert!(ctx.has_panic.load(Ordering::Relaxed)); + } +} + +#[cfg(test)] +mod concurrency_tests { + use super::*; + use std::sync::Arc; + + #[derive(Default)] + struct Counts { + process: usize, + thread_init: std::sync::atomic::AtomicUsize, + client_registration: usize, + } + + impl ProcessHandler for Counts { + fn process(&mut self, _: &Client, _: &ProcessScope) -> Control { + self.process += 1; + Control::Continue + } + } + + impl NotificationHandler for Counts { + fn thread_init(&self, _: &Client) { + self.thread_init.fetch_add(1, Ordering::Relaxed); + } + + fn client_registration(&mut self, _: &Client, _: &str, _: bool) { + self.client_registration += 1; + } + } + + struct SendPtr(*mut libc::c_void); + unsafe impl Send for SendPtr {} + unsafe impl Sync for SendPtr {} + + #[test] + fn process_and_notification_callbacks_can_run_concurrently() { + // JACK calls process (and thread_init) on its process thread while notifications arrive on + // another thread. Callbacks must only share the context, never hold `&mut` to it. Without + // Miri this cannot detect aliasing UB, but it does exercise the concurrent paths and checks + // that no update is lost. + const ITERATIONS: usize = 10_000; + let (client, _) = Client::new("", crate::ClientOptions::default()).unwrap(); + let mut ctx = Box::new(CallbackContext::new( + client, + Counts::default(), + Counts::default(), + )); + let data = Arc::new(SendPtr(CallbackContext::raw(&mut ctx))); + let name = ffi::CString::new("other").unwrap(); + + let process_thread = { + let data = data.clone(); + std::thread::spawn(move || { + for _ in 0..ITERATIONS { + unsafe { + assert_eq!(process::(64, data.0), 0); + thread_init_callback::(data.0); + } + } + }) + }; + let notification_thread = { + let data = data.clone(); + let name_ptr = name.as_ptr() as usize; + std::thread::spawn(move || { + for _ in 0..ITERATIONS { + unsafe { + client_registration::( + name_ptr as *const libc::c_char, + 1, + data.0, + ); + } + } + }) + }; + process_thread.join().unwrap(); + notification_thread.join().unwrap(); + + let (_client, notification, process) = ctx.into_parts(); + assert_eq!(process.process, ITERATIONS); + assert_eq!(notification.client_registration, ITERATIONS); + assert_eq!(notification.thread_init.load(Ordering::Relaxed), ITERATIONS); + } +} diff --git a/src/client/client_impl.rs b/src/client/client_impl.rs index 342bac55e..76daaac19 100644 --- a/src/client/client_impl.rs +++ b/src/client/client_impl.rs @@ -3,9 +3,9 @@ use std::fmt::Debug; use std::sync::Arc; use std::{ffi, fmt, ptr}; -use crate::client::common::CREATE_OR_DESTROY_CLIENT_MUTEX; +use crate::client::common::{ClientLife, CREATE_OR_DESTROY_CLIENT_MUTEX}; use crate::jack_enums::CodeOrMessage; -use crate::jack_utils::collect_strs; +use crate::jack_utils::{collect_strs, lossy_string, to_cstring}; use crate::properties::PropertyChangeHandler; use crate::transport::Transport; use crate::{ @@ -33,7 +33,7 @@ pub type InternalClientID = j::jack_intclient_t; #[allow(dead_code)] pub struct Client( *mut j::jack_client_t, - Arc<()>, + Arc, Option>, ); @@ -52,24 +52,25 @@ impl Client { pub fn new(client_name: &str, options: ClientOptions) -> Result<(Self, ClientStatus), Error> { let _m = CREATE_OR_DESTROY_CLIENT_MUTEX.lock().ok(); - // All of the jack_sys functions below assume the client library is loaded and will panic if - // it is not - #[cfg(feature = "dynamic_loading")] - if let Err(err) = jack_sys::library() { + // All of the jack_sys functions below assume the client library and its functions are + // loaded and will panic if they are not. + if let Err(err) = jack_sys::ensure_loaded() { return Err(Error::LibraryError(err.to_string())); } crate::logging::maybe_init_logging(); let mut status_bits = 0; let client = unsafe { - let client_name = ffi::CString::new(client_name).unwrap(); - j::jack_client_open(client_name.as_ptr(), options.bits(), &mut status_bits) + let client_name = to_cstring(client_name)?; + // Only pass options that need no extra variadic arguments. See `ClientOptions`. + let options = options.bits() & ClientOptions::all().bits(); + j::jack_client_open(client_name.as_ptr(), options, &mut status_bits) }; let status = ClientStatus::from_bits(status_bits).unwrap_or_else(ClientStatus::empty); if client.is_null() { Err(Error::ClientError(status)) } else { - Ok((Client(client, Arc::default(), None), status)) + Ok((Client(client, ClientLife::new(), None), status)) } } @@ -121,8 +122,13 @@ impl Client { pub fn name(&self) -> &str { unsafe { let ptr = j::jack_get_client_name(self.raw()); - let cstr = ffi::CStr::from_ptr(ptr); - cstr.to_str().unwrap() + let bytes = ffi::CStr::from_ptr(ptr).to_bytes(); + // JACK derives the name from the `&str` given to `Client::new`, so it is valid UTF-8 in + // practice. If it ever is not, return the valid prefix rather than panic. + match std::str::from_utf8(bytes) { + Ok(name) => name, + Err(err) => std::str::from_utf8(&bytes[..err.valid_up_to()]).unwrap_or_default(), + } } } @@ -147,6 +153,8 @@ impl Client { /// Get the numeric `uuid` of this client. /// + /// Returns `0`, the empty uuid, in the unlikely case that JACK does not provide one. + /// /// # Remarks /// /// * Deallocates, not realtime safe. @@ -154,8 +162,12 @@ impl Client { unsafe { let mut uuid: j::jack_uuid_t = Default::default(); let uuid_s = j::jack_client_get_uuid(self.raw()); - assert!(!uuid_s.is_null()); - assert_eq!(0, j::jack_uuid_parse(uuid_s, &mut uuid)); + if uuid_s.is_null() { + return 0; + } + if j::jack_uuid_parse(uuid_s, &mut uuid) != 0 { + uuid = 0; + } j::jack_free(uuid_s as _); uuid } @@ -172,32 +184,35 @@ impl Client { raw: *mut jack_sys::jack_client_t, name: &str, ) -> Option { - let name = ffi::CString::new(name).unwrap(); + let name = to_cstring(name).ok()?; let mut uuid: jack_sys::jack_uuid_t = Default::default(); unsafe { let uuid_s = jack_sys::jack_get_uuid_for_client_name(raw, name.as_ptr()); if uuid_s.is_null() { return None; } - assert_eq!(0, jack_sys::jack_uuid_parse(uuid_s, &mut uuid)); + let res = jack_sys::jack_uuid_parse(uuid_s, &mut uuid); jack_sys::jack_free(uuid_s as _); + if res != 0 { + return None; + } } Some(uuid) } /// Get a String representation of the `uuid` of this client. /// + /// Returns an empty string in the unlikely case that JACK does not provide one. + /// /// # Remarks /// /// * Allocates & deallocates, not realtime safe. pub fn uuid_string(&self) -> String { unsafe { let uuid_s = j::jack_client_get_uuid(self.raw()); - assert!(!uuid_s.is_null()); - let uuid = ffi::CStr::from_ptr(uuid_s) - .to_str() - .expect("uuid is valid string") - .to_string(); - j::jack_free(uuid_s as _); + let uuid = lossy_string(uuid_s); + if !uuid_s.is_null() { + j::jack_free(uuid_s as _); + } uuid } } @@ -208,12 +223,7 @@ impl Client { if name_ptr.is_null() { None } else { - Some( - ffi::CStr::from_ptr(name_ptr) - .to_str() - .expect("name convert to a valid str") - .to_string(), - ) + Some(lossy_string(name_ptr)) } } @@ -228,7 +238,7 @@ impl Client { /// Get the name of a client by its `&str` uuid. pub fn name_by_uuid_str(&self, uuid: &str) -> Option { - let uuid = ffi::CString::new(uuid).unwrap(); + let uuid = to_cstring(uuid).ok()?; unsafe { self.name_by_uuid_raw(uuid.as_ptr()) } } @@ -244,14 +254,20 @@ impl Client { /// /// `flags` - A value used to select ports by their flags. Use `PortFlags::empty()` for no flag /// selection. + /// + /// A pattern that contains a NUL byte matches no ports. pub fn ports( &self, port_name_pattern: Option<&str>, type_name_pattern: Option<&str>, flags: PortFlags, ) -> Vec { - let port_name_pattern_cstr = ffi::CString::new(port_name_pattern.unwrap_or("")).unwrap(); - let type_name_pattern_cstr = ffi::CString::new(type_name_pattern.unwrap_or("")).unwrap(); + let (Ok(port_name_pattern_cstr), Ok(type_name_pattern_cstr)) = ( + to_cstring(port_name_pattern.unwrap_or("")), + to_cstring(type_name_pattern.unwrap_or("")), + ) else { + return Vec::new(); + }; let flags = libc::c_ulong::from(flags.bits()); unsafe { let ports = j::jack_get_ports( @@ -271,7 +287,7 @@ impl Client { /// (`AudioIn`, `AudioOut`, `MidiIn`, `MidiOut`) can be used. /// /// Each port has a short name. The port's full name contains the name of the client - /// concatenated with a colon (:) followed by its short name. `Port::name_size()` is the maximum + /// concatenated with a colon (:) followed by its short name. [`PORT_NAME_SIZE`](crate::PORT_NAME_SIZE) is the maximum /// length of the full name. Exceeding that will cause the port registration to fail and return /// `Err(Error::PortRegistrationError)`. /// @@ -286,8 +302,8 @@ impl Client { if port_spec.jack_port_type().is_empty() { return Err(Error::PortRegistrationError(port_name.to_string())); } - let port_name_c = ffi::CString::new(port_name).unwrap(); - let port_type_c = ffi::CString::new(port_spec.jack_port_type()).unwrap(); + let port_name_c = to_cstring(port_name)?; + let port_type_c = to_cstring(port_spec.jack_port_type())?; let port_flags = port_spec.jack_flags().bits(); let buffer_size = port_spec.jack_buffer_size(); let pp = unsafe { @@ -302,7 +318,7 @@ impl Client { if pp.is_null() { Err(Error::PortRegistrationError(port_name.to_string())) } else { - Ok(unsafe { Port::from_raw(port_spec, self.raw(), pp, Arc::downgrade(&self.1)) }) + Ok(unsafe { Port::from_raw(port_spec, self.raw(), pp, self.1.clone()) }) } } @@ -312,18 +328,18 @@ impl Client { if pp.is_null() { None } else { - Some(unsafe { Port::from_raw(Unowned {}, self.raw(), pp, Arc::downgrade(&self.1)) }) + Some(unsafe { Port::from_raw(Unowned {}, self.raw(), pp, self.1.clone()) }) } } /// Get a `Port` by its port name. pub fn port_by_name(&self, port_name: &str) -> Option> { - let port_name = ffi::CString::new(port_name).unwrap(); + let port_name = to_cstring(port_name).ok()?; let pp = unsafe { j::jack_port_by_name(self.raw(), port_name.as_ptr()) }; if pp.is_null() { None } else { - Some(unsafe { Port::from_raw(Unowned {}, self.raw(), pp, Arc::downgrade(&self.1)) }) + Some(unsafe { Port::from_raw(Unowned {}, self.raw(), pp, self.1.clone()) }) } } @@ -346,9 +362,9 @@ impl Client { client_bin_name: &str, client_args: &str, ) -> Result { - let ffi_client_name = ffi::CString::new(client_name).unwrap(); - let ffi_client_bin = ffi::CString::new(client_bin_name).unwrap(); - let ffi_client_args = ffi::CString::new(client_args).unwrap(); + let ffi_client_name = to_cstring(client_name)?; + let ffi_client_bin = to_cstring(client_bin_name)?; + let ffi_client_args = to_cstring(client_args)?; let mut status_bits = 0; let options: j::Enum_JackOptions = j::JackLoadName | j::JackLoadInit; @@ -418,9 +434,6 @@ impl Client { } /// The estimated time in frames for the specified system time. - /// - /// # TODO - /// - Improve test pub fn time_to_frames(&self, t: Time) -> Frames { unsafe { j::jack_time_to_frames(self.raw(), t) } } @@ -440,7 +453,7 @@ impl Client { port_name: &str, enable_monitor: bool, ) -> Result<(), Error> { - let port_name_cstr = ffi::CString::new(port_name).unwrap(); + let port_name_cstr = to_cstring(port_name)?; let res = unsafe { j::jack_port_request_monitor_by_name( self.raw(), @@ -454,30 +467,22 @@ impl Client { } } - // TODO implement - // /// Start/Stop JACK's "freewheel" mode. - // /// - // /// When in "freewheel" mode, JACK no longer waits for any external event to - // /// begin the start of the next process cycle. As a result, freewheel mode - // /// causes "faster than real-time" execution of a JACK graph. If possessed, - // /// real-time scheduling is dropped when entering freewheel mode, and if - // /// appropriate it is reacquired when stopping. - // /// - // /// IMPORTANT: on systems using capabilities to provide real-time scheduling - // /// (i.e. Linux Kernel 2.4), if enabling freewheel, this function must be - // /// called from the thread that originally called `self.activate()`. This - // /// restriction does not apply to other systems (e.g. Linux Kernel 2.6 or OS - // /// X). - // pub pub fn set_freewheel(&self, enable: bool) -> Result<(), Error> { - // let onoff = match enable { - // true => 0, - // false => 1, - // }; - // match unsafe { j::jack_set_freewheel(self.raw(), onoff) } { - // 0 => Ok(()), - // _ => Err(Error::FreewheelError), - // } - // } + /// Start/Stop JACK's "freewheel" mode. + /// + /// When in "freewheel" mode, JACK no longer waits for any external event to begin the start of + /// the next process cycle. As a result, freewheel mode causes "faster than real-time" execution + /// of a JACK graph. If possessed, real-time scheduling is dropped when entering freewheel mode, + /// and if appropriate it is reacquired when stopping. + /// + /// `NotificationHandler::freewheel` is called when the mode changes. + /// + /// `Err(Error::FreewheelError)` is returned on failure. + pub fn set_freewheel(&self, enable: bool) -> Result<(), Error> { + match unsafe { j::jack_set_freewheel(self.raw(), i32::from(enable)) } { + 0 => Ok(()), + _ => Err(Error::FreewheelError), + } + } /// Establish a connection between two ports by their full name. /// @@ -492,15 +497,13 @@ impl Client { /// 3. The port flags of the `destination_port` must include `IS_INPUT`. /// 4. Both ports must be owned by active clients. /// - /// # Panics - /// Panics if it is not possible to convert `source_port` or `destination_port` to a `CString`. pub fn connect_ports_by_name( &self, source_port: &str, destination_port: &str, ) -> Result<(), Error> { - let source_cstr = ffi::CString::new(source_port).unwrap(); - let destination_cstr = ffi::CString::new(destination_port).unwrap(); + let source_cstr = to_cstring(source_port)?; + let destination_cstr = to_cstring(destination_port)?; let res = unsafe { j::jack_connect(self.raw(), source_cstr.as_ptr(), destination_cstr.as_ptr()) }; match res { @@ -512,7 +515,8 @@ impl Client { code => { let code_or_message = if self .port_by_name(source_port) - .map(|p| p.flags().contains(PortFlags::IS_INPUT)) + .and_then(|p| p.flags().ok()) + .map(|f| f.contains(PortFlags::IS_INPUT)) .unwrap_or(false) { CodeOrMessage::Message( @@ -520,7 +524,8 @@ impl Client { ) } else if self .port_by_name(destination_port) - .map(|p| p.flags().contains(PortFlags::IS_OUTPUT)) + .and_then(|p| p.flags().ok()) + .map(|f| f.contains(PortFlags::IS_OUTPUT)) .unwrap_or(false) { CodeOrMessage::Message( @@ -555,7 +560,8 @@ impl Client { source_port: &Port, destination_port: &Port, ) -> Result<(), Error> { - let _m = CREATE_OR_DESTROY_CLIENT_MUTEX.lock().ok(); + // Like the other graph operations, this does not take `CREATE_OR_DESTROY_CLIENT_MUTEX`. + // That lock only serializes opening, activating and closing clients. self.connect_ports_by_name(&source_port.name()?, &destination_port.name()?) } @@ -595,8 +601,8 @@ impl Client { source_port: &str, destination_port: &str, ) -> Result<(), Error> { - let source_port = ffi::CString::new(source_port).unwrap(); - let destination_port = ffi::CString::new(destination_port).unwrap(); + let source_port = to_cstring(source_port)?; + let destination_port = to_cstring(destination_port)?; let res = unsafe { j::jack_disconnect(self.raw(), source_port.as_ptr(), destination_port.as_ptr()) }; @@ -611,8 +617,12 @@ impl Client { /// # Safety /// /// * This function may only be called in a buffer size callback. + /// + /// Returns `0` if `port_type` contains a NUL byte. pub unsafe fn type_buffer_size(&self, port_type: &str) -> usize { - let port_type = ffi::CString::new(port_type).unwrap(); + let Ok(port_type) = to_cstring(port_type) else { + return 0; + }; j::jack_port_type_get_buffer_size(self.raw(), port_type.as_ptr()) } @@ -629,9 +639,11 @@ impl Client { /// This is mostly for use within the jack crate itself. /// /// # Safety - /// It is unsafe to create a `Client` from a raw pointer. + /// * `p` must be a valid, open client returned by `jack_client_open`. + /// * The returned `Client` takes ownership: it closes `p` when dropped, so `p` must not be closed + /// elsewhere or owned by another `Client`. pub unsafe fn from_raw(p: *mut j::jack_client_t) -> Self { - Client(p, Arc::default(), None) + Client(p, ClientLife::new(), None) } /// Get a `Transport` object associated with this client. @@ -641,7 +653,7 @@ impl Client { pub fn transport(&self) -> Transport { Transport { client_ptr: self.0, - client_life: Arc::downgrade(&self.1), + client_life: self.1.clone(), } } @@ -650,13 +662,15 @@ impl Client { /// # Remarks /// * The handler isn't called until after this client is activated. /// - /// # Panics - /// Calling this method more than once on any given client with cause a panic. + /// Only one handler can be registered per client. Calling this method again returns + /// `Err(Error::CallbackRegistrationError)`. pub fn register_property_change_handler( &mut self, handler: H, ) -> Result<(), Error> { - assert!(self.2.is_none()); + if self.2.is_some() { + return Err(Error::CallbackRegistrationError); + } let handler = Box::into_raw(Box::new(handler)); unsafe { self.2 = Some(Box::from_raw(handler)); @@ -679,6 +693,8 @@ impl Drop for Client { let _m = CREATE_OR_DESTROY_CLIENT_MUTEX.lock().ok(); // Rep invariant. debug_assert!(!self.raw().is_null()); + // Refuse new calls from ports and transports, and wait for in-flight ones to finish. + self.1.close(); // Best effort close client. let _res = unsafe { j::jack_client_close(self.raw()) }; self.0 = ptr::null_mut(); @@ -776,8 +792,13 @@ impl ProcessScope { /// This is mostly for use within the jack crate itself. /// /// # Safety - /// It is unsafe to create a `ProcessScope` since it may not be valid. For library user's, the - /// `ProcessScope` is usually passed in as a parameter to a trait's method. + /// * Must only be called from within the process callback of the client `client_ptr`, and the + /// `ProcessScope` must not outlive that callback. + /// * `n_frames` must be the frame count JACK passed to that callback, since port buffers are + /// read with this length. + /// + /// Library users normally receive a `ProcessScope` as a parameter of `ProcessHandler::process` + /// instead. pub unsafe fn from_raw(n_frames: Frames, client_ptr: *mut j::jack_client_t) -> Self { ProcessScope { n_frames, diff --git a/src/client/client_options.rs b/src/client/client_options.rs index 84659e176..f5e164862 100644 --- a/src/client/client_options.rs +++ b/src/client/client_options.rs @@ -3,6 +3,11 @@ use jack_sys as j; bitflags! { /// Option flags for opening a JACK client. + /// + /// JACK's `JackServerName`, `JackLoadName` and `JackLoadInit` options are not provided. They + /// make `jack_client_open` read extra arguments that `Client::new` does not pass, and + /// `Client::new` ignores them if they are set with `ClientOptions::from_bits_retain`. + #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] pub struct ClientOptions: j::Enum_JackOptions { /// Do not automatically start the JACK server when it is not already running. This option /// is always selected if `$JACK_NO_START_SERVER` is defined in the calling process @@ -13,21 +18,6 @@ bitflags! { /// automatically generates a unique one if needed. const USE_EXACT_NAME = j::JackUseExactName; - /// Open with optional `server_name` parameter. - /// - /// TODO: implement - const SERVER_NAME = j::JackServerName; - - /// Load internal client from optional `load_name`, otherwise use the `client_name`. - /// - /// TODO(wmedrano): Implement `load_name` functionality - const LOAD_NAME = j::JackLoadName; - - /// Pass optional `load_init` to `jack_initialize()` entry point of an internal client. - /// - /// TODO: implement - const LOAD_INIT = j::JackLoadInit; - /// Pass a SessionID token. This allows the session manager to identify the client again. const SESSION_ID = j::JackSessionID; } diff --git a/src/client/client_status.rs b/src/client/client_status.rs index 5caa7eafe..ba82e51aa 100644 --- a/src/client/client_status.rs +++ b/src/client/client_status.rs @@ -44,10 +44,11 @@ bitflags! { /// Client's protocol version does not match const VERSION_ERROR = j::JackVersionError; - /// No documentation found. TODO: dig deeper + /// The server's audio backend (driver) reported an error. const BACKEND_ERROR = j::JackBackendError; - /// No documentation found. TODO: dig deeper + /// The client was "zombified" by the server, usually because it took too long in its + /// process callback, and it no longer takes part in processing. const CLIENT_ZOMBIE = j::JackClientZombie; } } diff --git a/src/client/common.rs b/src/client/common.rs index 5ed6c579d..c68b2e056 100644 --- a/src/client/common.rs +++ b/src/client/common.rs @@ -1,6 +1,9 @@ use jack_sys as j; use lazy_static::lazy_static; -use std::sync::Mutex; +use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; +use std::sync::{Arc, Mutex}; + +use crate::Error; /// The maximum length of the JACK client name string. Unlike the "C" JACK API, this does not take /// into account the final `NULL` character and instead corresponds directly to `.len()`. This value @@ -18,3 +21,55 @@ lazy_static! { lazy_static! { pub static ref CREATE_OR_DESTROY_CLIENT_MUTEX: Mutex<()> = Mutex::new(()); } + +/// Tracks whether a client is still open, so that objects derived from it (such as `Port` and +/// `Transport`) can refuse to call into a closed client. +/// +/// Callers enter with `ClientLife::enter` and hold the returned guard for the whole FFI call. +/// `ClientLife::close` marks the client as closed and then waits for every outstanding guard to be +/// dropped, so the client is never closed while it is in use. Entering is lock-free, so it is +/// realtime safe. +pub(crate) struct ClientLife { + closed: AtomicBool, + users: AtomicUsize, +} + +/// Keeps a client open while it is held. See `ClientLife`. +pub(crate) struct ClientLifeGuard<'a>(&'a ClientLife); + +impl ClientLife { + pub(crate) fn new() -> Arc { + Arc::new(ClientLife { + closed: AtomicBool::new(false), + users: AtomicUsize::new(0), + }) + } + + /// Returns a guard that keeps the client open, or `Err(Error::ClientIsNoLongerAlive)` if the + /// client has been closed. + pub(crate) fn enter(&self) -> Result, Error> { + // Increment before checking `closed`. Paired with `close`, which sets `closed` before + // reading `users`, this guarantees that either we see the client as closed or `close` + // waits for us. + self.users.fetch_add(1, Ordering::SeqCst); + let guard = ClientLifeGuard(self); + if self.closed.load(Ordering::SeqCst) { + return Err(Error::ClientIsNoLongerAlive); + } + Ok(guard) + } + + /// Mark the client as closed and wait until no guards are outstanding. + pub(crate) fn close(&self) { + self.closed.store(true, Ordering::SeqCst); + while self.users.load(Ordering::SeqCst) != 0 { + std::thread::yield_now(); + } + } +} + +impl Drop for ClientLifeGuard<'_> { + fn drop(&mut self) { + self.0.users.fetch_sub(1, Ordering::SeqCst); + } +} diff --git a/src/client/handler_impls.rs b/src/client/handler_impls.rs index 6548d610c..4a45722a7 100644 --- a/src/client/handler_impls.rs +++ b/src/client/handler_impls.rs @@ -10,8 +10,3 @@ impl ProcessHandler for () { Control::Continue } } - -/// Wrap a closure that can handle the `process` callback. This is called every time data from ports -/// is available from JACK. -#[deprecated = "Prefer using jack::contrib::ClosureProcessHandler directly."] -pub type ClosureProcessHandler = crate::contrib::ClosureProcessHandler<(), F>; diff --git a/src/client/mod.rs b/src/client/mod.rs index b337131ce..aa55d2312 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -1,7 +1,7 @@ mod async_client; mod callbacks; mod client_impl; -mod common; +pub(crate) mod common; mod handler_impls; /// Contains `ClientOptions` flags used when opening a client. @@ -16,6 +16,3 @@ pub use self::client_impl::{Client, CycleTimes, InternalClientID, ProcessScope}; pub use self::client_options::ClientOptions; pub use self::client_status::ClientStatus; pub use self::common::CLIENT_NAME_SIZE; - -#[allow(deprecated)] -pub use self::handler_impls::ClosureProcessHandler; diff --git a/src/contrib/closure.rs b/src/contrib/closure.rs index 74e9382ca..bc9fca191 100644 --- a/src/contrib/closure.rs +++ b/src/contrib/closure.rs @@ -42,6 +42,24 @@ where } } +/// The process and buffer size callbacks of a [`ClosureProcessHandler`] created with +/// [`ClosureProcessHandler::with_state`]. +/// +/// ``` +/// fn handler() -> jack::contrib::ClosureProcessHandler< +/// u32, +/// jack::contrib::ProcessCallbacks< +/// fn(&mut u32, &jack::Client, &jack::ProcessScope) -> jack::Control, +/// fn(&mut u32, &jack::Client, jack::Frames) -> jack::Control, +/// >, +/// > { +/// jack::contrib::ClosureProcessHandler::with_state( +/// 0, +/// |_, _, _| jack::Control::Continue, +/// |_, _, _| jack::Control::Continue, +/// ) +/// } +/// ``` pub struct ProcessCallbacks { process: ProcessCallback, buffer: BufferCallback, diff --git a/src/jack_enums.rs b/src/jack_enums.rs index 94ab3a2a8..bc327e366 100644 --- a/src/jack_enums.rs +++ b/src/jack_enums.rs @@ -1,18 +1,36 @@ use crate::ClientStatus; /// An error that can occur in JACK. +/// +/// New variants may be added in the future, so matches need a wildcard arm: +/// +/// ```compile_fail +/// fn describe(err: jack::Error) -> &'static str { +/// use jack::Error::*; +/// match err { +/// LibraryError(_) | CallbackRegistrationError | ClientActivationError +/// | ClientDeactivationError | ClientError(_) | FreewheelError | NotEnoughSpace +/// | PortAliasError | PortAlreadyConnected(..) | PortConnectionError { .. } +/// | PortDisconnectionError | PortMonitorError | PortNamingError +/// | PortRegistrationError(_) | SetBufferSizeError | TimeError | WeakFunctionNotFound(_) +/// | ClientIsNoLongerAlive | ClientPanicked | RingbufferCreateFailed +/// | UnknownError { .. } => "error", +/// } +/// } +/// ``` #[derive(Clone, Debug, Eq, PartialEq)] #[non_exhaustive] pub enum Error { LibraryError(String), - CallbackDeregistrationError, + /// A string argument could not be passed to JACK because it contains a NUL byte. + InvalidString(String), CallbackRegistrationError, ClientActivationError, ClientDeactivationError, ClientError(ClientStatus), FreewheelError, - InvalidDeactivation, NotEnoughSpace, + InvalidMidiEvent, PortAliasError, PortAlreadyConnected(String, String), PortConnectionError { @@ -40,14 +58,17 @@ impl std::fmt::Display for Error { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { Error::LibraryError(err) => write!(f, "library error {err}"), - Error::CallbackDeregistrationError => write!(f, "callback deregistration error"), + Error::InvalidString(s) => write!(f, "invalid string {s:?}, it contains a NUL byte"), Error::CallbackRegistrationError => write!(f, "callback registration error"), Error::ClientActivationError => write!(f, "client activation error"), Error::ClientDeactivationError => write!(f, "client deactivation error"), Error::ClientError(status) => write!(f, "client error, status is {status:?}"), Error::FreewheelError => write!(f, "freewheel error"), - Error::InvalidDeactivation => write!(f, "invalid deactivation"), Error::NotEnoughSpace => write!(f, "not enough space"), + Error::InvalidMidiEvent => write!( + f, + "invalid midi event, its time may be out of order or outside the cycle" + ), Error::PortAliasError => write!(f, "port alias error"), Error::PortAlreadyConnected(a, b) => write!(f, "port {a} is already connected to {b}"), Error::PortConnectionError { @@ -78,15 +99,32 @@ impl std::fmt::Display for Error { Error::TimeError => write!(f, "time error"), Error::WeakFunctionNotFound(func) => write!(f, "weak function {func} not found"), Error::ClientIsNoLongerAlive => write!(f, "client is no longer alive"), - Error::ClientPanicked => write!(f, "client notifcation or processor panicked"), + Error::ClientPanicked => write!(f, "client notification or processor panicked"), Error::RingbufferCreateFailed => write!(f, "ringbuffer creation failed"), - Error::UnknownError { error_code } => write!(f, "unkown error with code {error_code}"), + Error::UnknownError { error_code } => write!(f, "unknown error with code {error_code}"), } } } impl std::error::Error for Error {} +/// Details for [`Error::PortConnectionError`]: either the raw JACK error code or an explanation. +/// +/// ``` +/// fn explain(err: &jack::Error) -> Option { +/// match err { +/// jack::Error::PortConnectionError { +/// code_or_message: jack::CodeOrMessage::Message(msg), +/// .. +/// } => Some(msg.to_string()), +/// jack::Error::PortConnectionError { +/// code_or_message: jack::CodeOrMessage::Code(code), +/// .. +/// } => Some(format!("code {code}")), +/// _ => None, +/// } +/// } +/// ``` #[derive(Clone, Debug, Eq, PartialEq)] pub enum CodeOrMessage { Code(libc::c_int), diff --git a/src/jack_utils.rs b/src/jack_utils.rs index 2175ff5ba..d9803c4e4 100644 --- a/src/jack_utils.rs +++ b/src/jack_utils.rs @@ -25,3 +25,78 @@ pub unsafe fn collect_strs(ptr: *const *const libc::c_char) -> Vec { j::jack_free(ptr as *mut ::libc::c_void); strs } + +/// Convert `s` into a `CString` for passing to JACK, or return `Err(Error::InvalidString)` if it +/// contains a NUL byte. +pub(crate) fn to_cstring(s: &str) -> Result { + ffi::CString::new(s).map_err(|_| crate::Error::InvalidString(s.to_string())) +} + +/// Convert a C string returned by JACK into an owned `String`, replacing invalid UTF-8. +/// +/// # Safety +/// `ptr` must be NULL or point to a NUL terminated string. +pub(crate) unsafe fn lossy_string(ptr: *const libc::c_char) -> String { + if ptr.is_null() { + String::new() + } else { + ffi::CStr::from_ptr(ptr).to_string_lossy().into_owned() + } +} + +/// Defers POSIX thread cancellation on the current thread for as long as it is alive. +/// +/// Some JACK implementations, notably PipeWire's, stop their process thread with +/// `pthread_cancel`. If the cancellation is acted on at a cancellation point inside a Rust +/// callback (for example, the `write` behind `eprintln!`), glibc starts a forced unwind through +/// Rust frames. `catch_unwind` cannot handle that and the process aborts with "FATAL: exception not +/// rethrown". Every callback that JACK invokes holds this guard, so any pending cancellation is +/// acted on only after the callback has returned to JACK. +/// +/// This only flips a thread-local flag in libc, so it is realtime safe. +pub(crate) struct DeferThreadCancellation { + #[cfg(unix)] + old_state: libc::c_int, +} + +#[cfg(unix)] +mod cancel { + extern "C" { + // Not exposed by the `libc` crate on all targets. + pub fn pthread_setcancelstate( + state: libc::c_int, + oldstate: *mut libc::c_int, + ) -> libc::c_int; + } + + #[cfg(target_vendor = "apple")] + pub const PTHREAD_CANCEL_DISABLE: libc::c_int = 0x00; + #[cfg(not(target_vendor = "apple"))] + pub const PTHREAD_CANCEL_DISABLE: libc::c_int = 1; +} + +impl DeferThreadCancellation { + #[inline] + pub(crate) fn new() -> Self { + #[cfg(unix)] + { + let mut old_state = cancel::PTHREAD_CANCEL_DISABLE; + unsafe { + cancel::pthread_setcancelstate(cancel::PTHREAD_CANCEL_DISABLE, &mut old_state) + }; + DeferThreadCancellation { old_state } + } + #[cfg(not(unix))] + DeferThreadCancellation {} + } +} + +impl Drop for DeferThreadCancellation { + #[inline] + fn drop(&mut self) { + #[cfg(unix)] + unsafe { + cancel::pthread_setcancelstate(self.old_state, std::ptr::null_mut()); + } + } +} diff --git a/src/lib.rs b/src/lib.rs index dc815c892..082d9d2af 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,16 +30,26 @@ //! [`MidiOut`]. //! //! To access the data of registered ports, use their specialized methods within a `ProcessHandler` -//! callback. For example, [`Port::as_mut_slice`] returns a audio buffer that can be written +//! callback. For example, [`Port::as_mut_slice`] returns an audio buffer that can be written //! to. +//! +//! ```compile_fail +//! // Removed in 1.0: use `Client::time` instead. +//! let _ = jack::get_time(); +//! ``` +//! +//! ```compile_fail +//! // Removed in 1.0: use `jack::contrib::ClosureProcessHandler` instead. +//! let _ = jack::ClosureProcessHandler::new(|_: &jack::Client, _: &jack::ProcessScope| { +//! jack::Control::Continue +//! }); +//! ``` -#[allow(deprecated)] -pub use crate::client::ClosureProcessHandler; pub use crate::client::{ AsyncClient, Client, ClientOptions, ClientStatus, CycleTimes, InternalClientID, NotificationHandler, ProcessHandler, ProcessScope, CLIENT_NAME_SIZE, }; -pub use crate::jack_enums::{Control, Error, LatencyType}; +pub use crate::jack_enums::{CodeOrMessage, Control, Error, LatencyType}; pub use crate::logging::{set_logger, LoggerType}; pub use crate::port::{ AudioIn, AudioOut, MidiIn, MidiIter, MidiOut, MidiWriter, Port, PortFlags, PortSpec, RawMidi, @@ -71,7 +81,7 @@ mod transport; pub mod contrib { mod closure; - pub use closure::ClosureProcessHandler; + pub use closure::{ClosureProcessHandler, ProcessCallbacks}; #[cfg(feature = "controller")] pub mod controller; @@ -79,16 +89,3 @@ pub mod contrib { #[cfg(test)] mod tests; - -static TIME_CLIENT: std::sync::LazyLock = std::sync::LazyLock::new(|| { - Client::new("deprecated_get_time", ClientOptions::default()) - .unwrap() - .0 -}); - -/// Return JACK's current system time in microseconds, using the JACK clock -/// source. -#[deprecated = "Prefer using Client::time. get_time will be eventually be removed and it requires an extra client initialization."] -pub fn get_time() -> primitive_types::Time { - TIME_CLIENT.time() -} diff --git a/src/logging.rs b/src/logging.rs index 18aa90947..9060ce992 100644 --- a/src/logging.rs +++ b/src/logging.rs @@ -43,7 +43,12 @@ impl Default for LoggerType { } /// Set the logger. +/// +/// Does nothing if the JACK library could not be loaded. pub fn set_logger(logger: LoggerType) { + if jack_sys::ensure_loaded().is_err() { + return; + } // Prevents maybe_init_logging from resetting the logger. if !INIT_LOGGING.is_completed() { INIT_LOGGING.call_once(|| {}); @@ -74,6 +79,7 @@ fn set_logger_impl(logger: LoggerType) { #[cfg(feature = "log")] unsafe extern "C" fn error_handler(msg: *const libc::c_char) { + let _defer_cancel = crate::jack_utils::DeferThreadCancellation::new(); let res = catch_unwind(|| match std::ffi::CStr::from_ptr(msg).to_str() { Ok(msg) => log::error!("{}", msg), Err(err) => log::error!("failed to log to JACK error: {:?}", err), @@ -86,6 +92,7 @@ unsafe extern "C" fn error_handler(msg: *const libc::c_char) { #[cfg(feature = "log")] unsafe extern "C" fn info_handler(msg: *const libc::c_char) { + let _defer_cancel = crate::jack_utils::DeferThreadCancellation::new(); let res = catch_unwind(|| match std::ffi::CStr::from_ptr(msg).to_str() { Ok(msg) => log::info!("{}", msg), Err(err) => log::error!("failed to log to JACK info: {:?}", err), @@ -97,6 +104,7 @@ unsafe extern "C" fn info_handler(msg: *const libc::c_char) { } unsafe extern "C" fn stderr_handler(msg: *const libc::c_char) { + let _defer_cancel = crate::jack_utils::DeferThreadCancellation::new(); let res = catch_unwind(|| match std::ffi::CStr::from_ptr(msg).to_str() { Ok(msg) => eprintln!("{}", msg), Err(err) => eprintln!("failed to log to JACK error: {:?}", err), @@ -108,6 +116,7 @@ unsafe extern "C" fn stderr_handler(msg: *const libc::c_char) { } unsafe extern "C" fn stdout_handler(msg: *const libc::c_char) { + let _defer_cancel = crate::jack_utils::DeferThreadCancellation::new(); let res = catch_unwind(|| match std::ffi::CStr::from_ptr(msg).to_str() { Ok(msg) => println!("{}", msg), Err(err) => println!("failed to log to JACK info: {:?}", err), diff --git a/src/port/audio.rs b/src/port/audio.rs index f48b05ef6..e7e5bbd50 100644 --- a/src/port/audio.rs +++ b/src/port/audio.rs @@ -33,7 +33,7 @@ pub struct AudioIn { /// let client = jack::Client::new("rusty_client", jack::ClientOptions::default()) /// .unwrap() /// .0; -/// let spec = jack::AudioIn::default(); +/// let spec = jack::AudioOut::default(); /// let audio_out_port = client.register_port("out", spec).unwrap(); /// ``` #[derive(Copy, Clone, Debug, Default)] @@ -73,6 +73,20 @@ unsafe impl PortSpec for AudioIn { impl Port { /// Read the received audio data. + /// + /// # Aliasing + /// + /// A JACK server may hand out the same memory for an input port and the output port it is + /// connected to. If a client connects one of its own `AudioOut` ports to one of its own + /// `AudioIn` ports, the slices from [`Port::as_slice`] and + /// [`Port::as_mut_slice`] could then overlap, which breaks Rust's aliasing rules. Do + /// not connect a client's output ports to its own input ports while holding both slices. + /// + /// This depends on the server, and more research is needed to say which ones are affected. + /// From reading the source, JACK2 passes an output buffer straight through to an input port + /// with one connection, but copies it when both ports belong to the same client, so it does not + /// alias in this case. PipeWire's JACK layer returns the peer's buffer for a single connection + /// without a same-client check, so it may alias, but this has not been verified at runtime. pub fn as_slice<'a>(&'a self, ps: &'a ProcessScope) -> &'a [f32] { assert_eq!(self.client_ptr(), ps.client_ptr()); unsafe { @@ -86,6 +100,20 @@ impl Port { impl Port { /// Get a slice to write audio data to. + /// + /// # Aliasing + /// + /// A JACK server may hand out the same memory for an input port and the output port it is + /// connected to. If a client connects one of its own `AudioOut` ports to one of its own + /// `AudioIn` ports, the slices from [`Port::as_slice`] and + /// [`Port::as_mut_slice`] could then overlap, which breaks Rust's aliasing rules. Do + /// not connect a client's output ports to its own input ports while holding both slices. + /// + /// This depends on the server, and more research is needed to say which ones are affected. + /// From reading the source, JACK2 passes an output buffer straight through to an input port + /// with one connection, but copies it when both ports belong to the same client, so it does not + /// alias in this case. PipeWire's JACK layer returns the peer's buffer for a single connection + /// without a same-client check, so it may alias, but this has not been verified at runtime. pub fn as_mut_slice<'a>(&'a mut self, ps: &'a ProcessScope) -> &'a mut [f32] { assert_eq!(self.client_ptr(), ps.client_ptr()); unsafe { diff --git a/src/port/midi.rs b/src/port/midi.rs index 6f757be33..d5f967491 100644 --- a/src/port/midi.rs +++ b/src/port/midi.rs @@ -176,6 +176,19 @@ impl Port { } } +/// Convert the return value of `jack_midi_event_write` into a `Result`. +/// +/// JACK1 returns a positive errno on failure, while JACK2 and PipeWire return a negative one, so +/// both are accepted. +fn midi_write_result(res: libc::c_int) -> Result<(), Error> { + match res.abs() { + 0 => Ok(()), + libc::ENOBUFS => Err(Error::NotEnoughSpace), + libc::EINVAL => Err(Error::InvalidMidiEvent), + _ => Err(Error::UnknownError { error_code: res }), + } +} + /// Write midi events to an output midi port. #[derive(Debug)] pub struct MidiWriter<'a> { @@ -189,6 +202,10 @@ impl MidiWriter<'_> { /// Clients must write normalised MIDI data to the port - no running status and no (1-byte) /// realtime messages interspersed with other messagse (realtime messages are fine when they /// occur on their own, like other messages). + /// + /// Returns `Err(Error::NotEnoughSpace)` if the event does not fit in the buffer, and + /// `Err(Error::InvalidMidiEvent)` if JACK rejects it, for example because its time is earlier + /// than the previously written event or outside the current cycle. pub fn write(&mut self, message: &RawMidi) -> Result<(), Error> { let ev = j::jack_midi_event_t { time: message.time, @@ -196,11 +213,7 @@ impl MidiWriter<'_> { buffer: message.bytes.as_ptr() as *mut u8, }; let res = unsafe { j::jack_midi_event_write(self.buffer, ev.time, ev.buffer, ev.size) }; - match -res { - 0 => Ok(()), - libc::ENOBUFS => Err(Error::NotEnoughSpace), - error_code => Err(Error::UnknownError { error_code }), - } + midi_write_result(res) } /// Get the number of events that could not be written to port_buffer. @@ -261,4 +274,29 @@ mod tests { } assert_eq!(iter.size_hint(), (0, Some(0))); } + + #[test] + fn midi_write_result_accepts_both_errno_conventions() { + assert_eq!(midi_write_result(0), Ok(())); + // JACK1 returns a positive errno, JACK2 and PipeWire a negative one. + assert_eq!(midi_write_result(libc::ENOBUFS), Err(Error::NotEnoughSpace)); + assert_eq!( + midi_write_result(-libc::ENOBUFS), + Err(Error::NotEnoughSpace) + ); + assert_eq!( + midi_write_result(libc::EINVAL), + Err(Error::InvalidMidiEvent) + ); + assert_eq!( + midi_write_result(-libc::EINVAL), + Err(Error::InvalidMidiEvent) + ); + assert_eq!( + midi_write_result(-libc::EIO), + Err(Error::UnknownError { + error_code: -libc::EIO + }) + ); + } } diff --git a/src/port/port_flags.rs b/src/port/port_flags.rs index a913dbfcf..d1799070a 100644 --- a/src/port/port_flags.rs +++ b/src/port/port_flags.rs @@ -14,9 +14,7 @@ bitflags! { /// Port corresponds to some kind of physical I/O connector. const IS_PHYSICAL = j::JackPortIsPhysical; - /// A call to `jack_port_request_monitor()` makes sense. - /// - /// # TODO implement + /// A call to [`Port::request_monitor`](crate::Port::request_monitor) makes sense. /// /// Precisely what this means it dependent on the client. A typical result of it being /// called with `true` as the second argument is that data that would be available from an diff --git a/src/port/port_impl.rs b/src/port/port_impl.rs index fbb1b3811..5eb47e7f2 100644 --- a/src/port/port_impl.rs +++ b/src/port/port_impl.rs @@ -4,9 +4,11 @@ use std::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd}; use std::fmt::Debug; use std::hash::{Hash, Hasher}; use std::marker::Sized; -use std::sync::Weak; +use std::sync::Arc; use std::{ffi, fmt, iter}; +use crate::client::common::ClientLife; +use crate::jack_utils::to_cstring; use crate::{Error, Frames, LatencyType, PortFlags}; lazy_static! { @@ -37,8 +39,8 @@ pub unsafe trait PortSpec: Sized { /// An endpoint to interact with JACK data streams, for audio, midi, etc... /// /// The `Port` struct contains mostly metadata and exposes data as raw pointers. For a better data -/// consumption/production API, see the `AudioInPort`, `AudioOutPort`, `MidiInPort`, and -/// `MidiOutPort`. +/// consumption/production API, see the methods of `Port`, `Port`, +/// `Port`, and `Port`. /// /// Most JACK functionality is exposed, including the raw pointers, but it should be possible to /// create a client without the need for calling `unsafe` `Port` methods. @@ -48,7 +50,7 @@ pub struct Port { spec: PS, client_ptr: *mut j::jack_client_t, port_ptr: *mut j::jack_port_t, - client_life: Weak<()>, + client_life: Arc, } unsafe impl Send for Port {} @@ -73,7 +75,7 @@ impl Port { /// Returns the full name of the port, including the "client_name:" prefix. pub fn name(&self) -> Result { - self.check_client_life()?; + let _life = self.client_life.enter()?; let s = unsafe { ffi::CStr::from_ptr(j::jack_port_name(self.raw())) .to_string_lossy() @@ -85,7 +87,7 @@ impl Port { /// Returns the short name of the port, it excludes the "client_name:" /// prefix. pub fn short_name(&self) -> Result { - self.check_client_life()?; + let _life = self.client_life.enter()?; let s = unsafe { ffi::CStr::from_ptr(j::jack_port_short_name(self.raw())) .to_string_lossy() @@ -96,15 +98,18 @@ impl Port { /// The flags for the port. These are set when the port is registered with /// its client. - pub fn flags(&self) -> PortFlags { + pub fn flags(&self) -> Result { + let _life = self.client_life.enter()?; let bits = unsafe { j::jack_port_flags(self.raw()) }; - PortFlags::from_bits(bits as j::Enum_JackPortFlags).unwrap() + // Keep flags that this crate does not know about, such as `JackPortIsCV`, instead of + // panicking on them. + Ok(PortFlags::from_bits_retain(bits as j::Enum_JackPortFlags)) } /// The port type. JACK's built in types include `"32 bit float mono audio`" and `"8 bit raw /// midi"`. Custom types may also be used. pub fn port_type(&self) -> Result { - self.check_client_life()?; + let _life = self.client_life.enter()?; let s = unsafe { ffi::CStr::from_ptr(j::jack_port_type(self.raw())) .to_string_lossy() @@ -115,7 +120,7 @@ impl Port { /// Number of ports connected to/from `&self`. pub fn connected_count(&self) -> Result { - self.check_client_life()?; + let _life = self.client_life.enter()?; let n = unsafe { j::jack_port_connected(self.raw()) }; Ok(n as usize) } @@ -123,11 +128,9 @@ impl Port { /// Returns `true` if the port is directly connected to a port with the /// name `port_name`. pub fn is_connected_to(&self, port_name: &str) -> Result { - self.check_client_life()?; - let res = unsafe { - let port_name = ffi::CString::new(port_name).unwrap(); - j::jack_port_connected_to(self.raw(), port_name.as_ptr()) - }; + let _life = self.client_life.enter()?; + let port_name = to_cstring(port_name)?; + let res = unsafe { j::jack_port_connected_to(self.raw(), port_name.as_ptr()) }; match res { 0 => Ok(false), _ => Ok(true), @@ -138,7 +141,7 @@ impl Port { /// /// Will return up to 2 strings. pub fn aliases(&self) -> Result, Error> { - self.check_client_life()?; + let _life = self.client_life.enter()?; let mut a: Vec = iter::repeat_n(0, *PORT_NAME_SIZE + 1).collect(); let mut b = a.clone(); unsafe { @@ -155,7 +158,7 @@ impl Port { /// Returns `true` if monitoring has been requested for `self`. pub fn is_monitoring_input(&self) -> Result { - self.check_client_life()?; + let _life = self.client_life.enter()?; match unsafe { j::jack_port_monitoring_input(self.raw()) } { 0 => Ok(false), _ => Ok(true), @@ -166,7 +169,7 @@ impl Port { /// /// This only works if the port has the `CAN_MONITOR` flag set. pub fn request_monitor(&self, enable_monitor: bool) -> Result<(), Error> { - self.check_client_life()?; + let _life = self.client_life.enter()?; let onoff = i32::from(enable_monitor); let res = unsafe { j::jack_port_request_monitor(self.raw(), onoff) }; match res { @@ -179,7 +182,7 @@ impl Port { /// off, and turns it off if only one request has been made to turn it on. Otherwise it does /// nothing. pub fn ensure_monitor(&self, enable_monitor: bool) -> Result<(), Error> { - self.check_client_life()?; + let _life = self.client_life.enter()?; let onoff = i32::from(enable_monitor); let res = unsafe { j::jack_port_ensure_monitor(self.raw(), onoff) }; match res { @@ -191,9 +194,14 @@ impl Port { /// Set's the short name of the port. If the full name is longer than `PORT_NAME_SIZE`, then it /// will be truncated. pub fn set_name(&mut self, short_name: &str) -> Result<(), Error> { - self.check_client_life()?; - let short_name = ffi::CString::new(short_name).unwrap(); - let res = unsafe { j::jack_port_set_name(self.raw(), short_name.as_ptr()) }; + let _life = self.client_life.enter()?; + let short_name = to_cstring(short_name)?; + // Prefer `jack_port_rename`. The deprecated `jack_port_set_name` does not notify port rename + // callbacks, and PipeWire ignores it entirely. + let res = unsafe { + j::jack_port_rename(self.client_ptr, self.raw(), short_name.as_ptr()) + .unwrap_or_else(|| j::jack_port_set_name(self.raw(), short_name.as_ptr())) + }; match res { 0 => Ok(()), _ => Err(Error::PortNamingError), @@ -211,8 +219,8 @@ impl Port { /// Ports can have up to two aliases - if both are already set, this function will return an /// error. pub fn set_alias(&mut self, alias: &str) -> Result<(), Error> { - self.check_client_life()?; - let alias = ffi::CString::new(alias).unwrap(); + let _life = self.client_life.enter()?; + let alias = to_cstring(alias)?; let res = unsafe { j::jack_port_set_alias(self.raw(), alias.as_ptr()) }; match res { 0 => Ok(()), @@ -224,8 +232,8 @@ impl Port { /// /// After a successful call, `alias` can no longer be used as an alternate name for `self`. pub fn unset_alias(&mut self, alias: &str) -> Result<(), Error> { - self.check_client_life()?; - let alias = ffi::CString::new(alias).unwrap(); + let _life = self.client_life.enter()?; + let alias = to_cstring(alias)?; let res = unsafe { j::jack_port_unset_alias(self.raw(), alias.as_ptr()) }; match res { 0 => Ok(()), @@ -239,11 +247,11 @@ impl Port { /// /// # Safety /// It is unsafe to create a `Port` from raw pointers. - pub unsafe fn from_raw( + pub(crate) unsafe fn from_raw( spec: PS, client_ptr: *mut j::jack_client_t, port_ptr: *mut j::jack_port_t, - client_life: Weak<()>, + client_life: Arc, ) -> Self { Port { spec, @@ -270,13 +278,14 @@ impl Port { } /// Obtain the buffer that the Port is holding. For standard audio and midi ports, consider - /// using the `AudioInPort`, `AudioOutPort`, `MidiInPort`, or `MidiOutPort` adapter. For more + /// using `Port::as_slice`, `Port::as_mut_slice`, `Port::iter`, or + /// `Port::writer` instead. For more /// custom data, consider implementing your own adapter that safely uses the `Port::buffer` /// method. /// /// # Safety /// It is unsafe to extract a buffer. Prefer to use one of the type specific wrappers such as - /// `.as_mut_slice()` for audio and `.midi_iter` for midi. + /// `.as_mut_slice()` for audio and `.iter()` for midi. #[inline(always)] pub unsafe fn buffer(&self, n_frames: Frames) -> *mut libc::c_void { // We don't check for life to improve performance in a very hot codepath. @@ -291,12 +300,18 @@ impl Port { /// for a description of what the latency values mean and some best practices. This function should /// **only** be used inside a latency callback. #[inline(always)] - pub fn set_latency_range(&self, mode: LatencyType, range: (Frames, Frames)) { + pub fn set_latency_range( + &self, + mode: LatencyType, + range: (Frames, Frames), + ) -> Result<(), Error> { + let _life = self.client_life.enter()?; let mut ffi_range = j::Struct__jack_latency_range { min: range.0, max: range.1, }; unsafe { j::jack_port_set_latency_range(self.port_ptr, mode.to_ffi(), &mut ffi_range) }; + Ok(()) } /// Returns a tuple of the minimum and maximum latencies defined by mode for port, in frames. @@ -305,39 +320,39 @@ impl Port { /// for a description of what the latency values mean and some best practices. This is normally /// used in the LatencyCallback. and therefore safe to execute from callbacks. #[inline(always)] - pub fn get_latency_range(&self, mode: LatencyType) -> (Frames, Frames) { + pub fn get_latency_range(&self, mode: LatencyType) -> Result<(Frames, Frames), Error> { + let _life = self.client_life.enter()?; let mut ffi_range = j::Struct__jack_latency_range { min: 0, max: 0 }; unsafe { j::jack_port_get_latency_range(self.port_ptr, mode.to_ffi(), &mut ffi_range) }; - (ffi_range.min, ffi_range.max) - } - - fn check_client_life(&self) -> Result<(), Error> { - self.client_life - .upgrade() - .map(|_| ()) - .ok_or(Error::ClientIsNoLongerAlive) + Ok((ffi_range.min, ffi_range.max)) } } impl Port { /// Returns the fully-qualified name of all ports currently connected to this one /// Remarks: Not realtime safe - pub fn get_connections(&self) -> Vec { - unsafe { + pub fn get_connections(&self) -> Result, Error> { + let _life = self.client_life.enter()?; + Ok(unsafe { crate::jack_utils::collect_strs(jack_sys::jack_port_get_connections(self.port_ptr)) - } + }) } /// Returns the UUIDs of all clients currently connected to this one + /// + /// Clients that disconnect or close while this runs are left out. + /// /// Remarks: Not realtime safe - pub fn get_connected_client_uuids(&self) -> Vec { - self.get_connections() + pub fn get_connected_client_uuids(&self) -> Result, Error> { + let _life = self.client_life.enter()?; + Ok(self + .get_connections()? .into_iter() - .map(|name| { - let (client, _port) = name.split_once(':').unwrap(); - crate::Client::uuid_of_client_by_name_raw(self.client_ptr(), client).unwrap() + .filter_map(|name| { + let (client, _port) = name.split_once(':')?; + crate::Client::uuid_of_client_by_name_raw(self.client_ptr(), client) }) - .collect() + .collect()) } } diff --git a/src/properties.rs b/src/properties.rs index 70ab23803..d95821e20 100644 --- a/src/properties.rs +++ b/src/properties.rs @@ -9,16 +9,26 @@ use jack_sys as j; /// `subject` and `key`. #[derive(Debug, PartialEq, Eq)] pub enum PropertyChange<'a> { - Created { subject: uuid, key: &'a str }, - Changed { subject: uuid, key: &'a str }, - Deleted { subject: uuid, key: &'a str }, + Created { + subject: uuid, + key: &'a str, + }, + Changed { + subject: uuid, + key: &'a str, + }, + /// A property was deleted. `key` is `None` when every property of `subject` was removed at + /// once, for example by [`Client::property_remove_subject`](crate::Client::property_remove_subject) + /// or [`Client::property_remove_all`](crate::Client::property_remove_all). + Deleted { + subject: uuid, + key: Option<&'a str>, + }, } /// A trait for reacting to property changes. /// -/// # Remarks -/// -/// * Only used if the `metadata` feature is enabled. +/// Register one with [`Client::register_property_change_handler`](crate::Client::register_property_change_handler). pub trait PropertyChangeHandler: Send { fn property_changed(&mut self, change: &PropertyChange); } @@ -31,14 +41,27 @@ pub(crate) unsafe extern "C" fn property_changed

( ) where P: PropertyChangeHandler, { + let _defer_cancel = crate::jack_utils::DeferThreadCancellation::new(); let res = catch_unwind(|| { let h: &mut P = &mut *(arg as *mut P); - let key_c = std::ffi::CStr::from_ptr(key); - let key = key_c.to_str().expect("to convert key to valid str"); + // JACK passes a NULL key when all properties of `subject` were removed. Keys should be + // URIs, but convert lossily rather than panic if one is not valid UTF-8. + let key = if key.is_null() { + None + } else { + Some(std::ffi::CStr::from_ptr(key).to_string_lossy()) + }; + let key = key.as_deref(); let c = match change { - j::PropertyCreated => PropertyChange::Created { subject, key }, + j::PropertyCreated => PropertyChange::Created { + subject, + key: key.unwrap_or_default(), + }, j::PropertyDeleted => PropertyChange::Deleted { subject, key }, - _ => PropertyChange::Changed { subject, key }, + _ => PropertyChange::Changed { + subject, + key: key.unwrap_or_default(), + }, }; h.property_changed(&c); }); @@ -52,6 +75,7 @@ pub use metadata::*; mod metadata { use super::{j, uuid, PropertyChange, PropertyChangeHandler}; + use crate::jack_utils::to_cstring; use crate::Error; use std::{ collections::HashMap, @@ -67,7 +91,7 @@ mod metadata { pub enum PropertyChangeOwned { Created { subject: uuid, key: String }, Changed { subject: uuid, key: String }, - Deleted { subject: uuid, key: String }, + Deleted { subject: uuid, key: Option }, } /// A piece of Metadata on a Jack `subject`: either a port or a client. @@ -193,7 +217,7 @@ mod metadata { /// * `subject` - The subject of the property. /// * `key` - The key of the property, a URI String. pub fn property_get(&self, subject: uuid, key: &str) -> Option { - let key = ffi::CString::new(key).expect("key to be convert to CString"); + let key = to_cstring(key).ok()?; let mut value: MaybeUninit<*mut ::libc::c_char> = MaybeUninit::uninit(); let mut typ: MaybeUninit<*mut ::libc::c_char> = MaybeUninit::uninit(); @@ -278,12 +302,11 @@ mod metadata { key: &str, property: &Property, ) -> Result<(), Error> { - let key = ffi::CString::new(key).expect("to create cstring from key"); - let value = - ffi::CString::new(property.value.as_str()).expect("to create cstring from value"); + let key = to_cstring(key)?; + let value = to_cstring(property.value.as_str())?; + let typ = property.typ().map(to_cstring).transpose()?; map_error(|| unsafe { - if let Some(t) = property.typ() { - let t = ffi::CString::new(t).unwrap(); + if let Some(t) = typ { j::jack_set_property( self.raw(), subject, @@ -310,7 +333,7 @@ mod metadata { /// * `subject` - The subject to remove all properties from. /// * `key` - The key of the property to be removed. A URI string. pub fn property_remove(&self, subject: uuid, key: &str) -> Result<(), Error> { - let key = ffi::CString::new(key).expect("to create cstring from key"); + let key = to_cstring(key)?; map_error(|| unsafe { j::jack_remove_property(self.raw(), subject, key.as_ptr()) }) } @@ -352,7 +375,7 @@ mod metadata { }, PropertyChange::Deleted { subject, key } => Self::Deleted { subject: *subject, - key: key.to_string(), + key: key.map(str::to_string), }, } } @@ -403,6 +426,53 @@ mod metadata { assert_eq!(sub.get("asdf"), None); } + /// Calls the C property-change callback directly and returns what the handler received. + fn deliver_change( + subject: uuid, + key: *const libc::c_char, + change: j::jack_property_change_t, + ) -> Vec { + struct Recorder(Vec); + impl PropertyChangeHandler for Recorder { + fn property_changed(&mut self, change: &PropertyChange) { + self.0.push(change.into()); + } + } + let mut recorder = Recorder(Vec::new()); + unsafe { + super::super::property_changed::( + subject, + key, + change, + &mut recorder as *mut Recorder as *mut libc::c_void, + ); + } + recorder.0 + } + + #[test] + fn property_changed_with_null_key_reports_all_keys_deleted() { + assert_eq!( + deliver_change(7, ptr::null(), j::PropertyDeleted), + vec![PropertyChangeOwned::Deleted { + subject: 7, + key: None + }] + ); + } + + #[test] + fn property_changed_with_non_utf8_key_is_delivered() { + let key = b"bad\xff\0"; + assert_eq!( + deliver_change(7, key.as_ptr() as *const libc::c_char, j::PropertyCreated), + vec![PropertyChangeOwned::Created { + subject: 7, + key: "bad\u{fffd}".into() + }] + ); + } + #[test] fn property_get_subject_without_properties_is_empty() { let (c, _) = Client::new("", ClientOptions::default()).unwrap(); @@ -579,7 +649,7 @@ mod metadata { assert_eq!( Ok(PropertyChangeOwned::Deleted { subject: c2.uuid(), - key: "blah".into() + key: Some("blah".into()) }), r ); @@ -608,15 +678,16 @@ mod metadata { } #[test] - #[should_panic] fn double_register() { let (mut c, _) = Client::new("client1", ClientOptions::default()).unwrap(); assert_eq!( Ok(()), c.register_property_change_handler(ClosurePropertyChangeHandler::new(|_| {})) ); - let _panic = - c.register_property_change_handler(ClosurePropertyChangeHandler::new(|_| {})); + assert_eq!( + Err(Error::CallbackRegistrationError), + c.register_property_change_handler(ClosurePropertyChangeHandler::new(|_| {})) + ); } } } diff --git a/src/ringbuffer.rs b/src/ringbuffer.rs index e89352d8b..e151ac17d 100644 --- a/src/ringbuffer.rs +++ b/src/ringbuffer.rs @@ -1,6 +1,8 @@ use jack_sys as j; -use std::mem; +use std::mem::ManuallyDrop; +use std::ptr; use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::Arc; /// A lock-free ringbuffer. The key attribute of a ringbuffer is that it can be safely accessed by /// two threads simultaneously, one reading from the buffer and the other writing to it - without @@ -25,6 +27,9 @@ pub struct RingBuffer(*mut j::jack_ringbuffer_t); impl RingBuffer { /// Allocates a ringbuffer of a specified size. pub fn new(size: usize) -> Result { + if let Err(err) = jack_sys::ensure_loaded() { + return Err(crate::Error::LibraryError(err.to_string())); + } let insize = size as libc::size_t; let handle = unsafe { j::jack_ringbuffer_create(insize) }; @@ -47,9 +52,14 @@ impl RingBuffer { /// Create a reader and writer, to use the ring buffer. pub fn into_reader_writer(self) -> (RingBufferReader, RingBufferWriter) { - let out = unsafe { (RingBufferReader::new(self.0), RingBufferWriter::new(self.0)) }; - mem::forget(self); - out + let this = ManuallyDrop::new(self); + let both_live = Arc::new(AtomicBool::new(true)); + unsafe { + ( + RingBufferReader::new(this.0, both_live.clone()), + RingBufferWriter::new(this.0, both_live), + ) + } } /// Re-create the ring buffer object from reader and writer. useful if you need to call reset. @@ -65,20 +75,30 @@ impl RingBuffer { panic!("mismatching read and write handles!") } - // The next 3 lines transfer ownership of the ringbuffer from both reader and writer to the - // new buffer object. - let handle = RingBuffer(r.ringbuffer_handle); - mem::forget(r); - mem::forget(w); - - handle + // Transfer ownership of the ringbuffer from both reader and writer to the new buffer + // object. Their `Drop` must not run, but their shared liveness flag still has to be freed. + let r = ManuallyDrop::new(r); + let w = ManuallyDrop::new(w); + unsafe { + drop(ptr::read(&r.both_live)); + drop(ptr::read(&w.both_live)); + } + RingBuffer(r.ringbuffer_handle) } } +// Counts the ring buffers freed on the current thread, so tests can detect leaks. +#[cfg(test)] +thread_local! { + pub(crate) static FREED_COUNT: std::cell::Cell = const { std::cell::Cell::new(0) }; +} + impl Drop for RingBuffer { fn drop(&mut self) { if !self.0.is_null() { unsafe { j::jack_ringbuffer_free(self.0) }; + #[cfg(test)] + FREED_COUNT.with(|c| c.set(c.get() + 1)); } self.0 = std::ptr::null_mut(); } @@ -91,9 +111,9 @@ unsafe impl Sync for RingBuffer {} /// thread). pub struct RingBufferReader { ringbuffer_handle: *mut j::jack_ringbuffer_t, - /// A marker to check if both halves of the ringbuffer are live. Destroying a ringbuffer is not - /// a realtime operation. - both_live: AtomicBool, + /// Shared with the writer. `true` while both halves are live. The half that is dropped last + /// frees the ringbuffer. Destroying a ringbuffer is not a realtime operation. + both_live: Arc, } unsafe impl Send for RingBufferReader {} @@ -103,7 +123,8 @@ unsafe impl Sync for RingBufferReader {} /// thread). pub struct RingBufferWriter { ringbuffer_handle: *mut j::jack_ringbuffer_t, - both_live: AtomicBool, + /// Shared with the reader. See `RingBufferReader::both_live`. + both_live: Arc, } unsafe impl Send for RingBufferWriter {} @@ -112,10 +133,10 @@ unsafe impl Sync for RingBufferWriter {} impl RingBufferReader { // safety: this method must be called as part of the splitting of the ringbuffer into 2 // channels. - unsafe fn new(raw: *mut j::jack_ringbuffer_t) -> Self { + unsafe fn new(raw: *mut j::jack_ringbuffer_t, both_live: Arc) -> Self { RingBufferReader { ringbuffer_handle: raw, - both_live: AtomicBool::new(true), + both_live, } } @@ -217,14 +238,10 @@ impl std::io::Read for RingBufferReader { impl Drop for RingBufferReader { fn drop(&mut self) { - match self - .both_live - .compare_exchange(true, false, Ordering::SeqCst, Ordering::SeqCst) - { - Ok(false) | Err(false) => { - drop(RingBuffer(self.ringbuffer_handle)); - } - _ => (), + // The first half to be dropped flips the flag. The second one sees it already cleared and + // frees the ringbuffer. + if !self.both_live.swap(false, Ordering::AcqRel) { + drop(RingBuffer(self.ringbuffer_handle)); } } } @@ -232,10 +249,10 @@ impl Drop for RingBufferReader { impl RingBufferWriter { // safety: this method must be called as part of the splitting of the ringbuffer into 2 // channels. - unsafe fn new(raw: *mut j::jack_ringbuffer_t) -> Self { + unsafe fn new(raw: *mut j::jack_ringbuffer_t, both_live: Arc) -> Self { RingBufferWriter { ringbuffer_handle: raw, - both_live: AtomicBool::new(true), + both_live, } } @@ -317,14 +334,10 @@ impl std::io::Write for RingBufferWriter { impl Drop for RingBufferWriter { fn drop(&mut self) { - match self - .both_live - .compare_exchange(true, false, Ordering::SeqCst, Ordering::SeqCst) - { - Ok(false) | Err(false) => { - drop(RingBuffer(self.ringbuffer_handle)); - } - _ => (), + // The first half to be dropped flips the flag. The second one sees it already cleared and + // frees the ringbuffer. + if !self.both_live.swap(false, Ordering::AcqRel) { + drop(RingBuffer(self.ringbuffer_handle)); } } } diff --git a/src/tests/client.rs b/src/tests/client.rs index cef4508f6..b73dea2cd 100644 --- a/src/tests/client.rs +++ b/src/tests/client.rs @@ -1,4 +1,6 @@ -use crate::tests::DEFAULT_TEST_CLIENT; +use std::time::Duration; + +use crate::tests::{active_client, wait_for}; #[test] fn client_can_open() { @@ -10,37 +12,45 @@ fn client_can_open() { assert_ne!(client.buffer_size(), 0); assert_ne!(client.uuid_string(), ""); assert_ne!(client.uuid(), 0); + // An idle server, such as the dummy backend, may report no load at all. let cpu_load = client.cpu_load(); - assert!(cpu_load >= 0.0, "client.cpu_load() = {}", cpu_load); + assert!( + (0.0..=100.0).contains(&cpu_load), + "client.cpu_load() = {}", + cpu_load + ); } #[test] fn time_is_montonically_increasing() { - let (client, _) = crate::Client::new("", crate::ClientOptions::default()).unwrap(); - let ac = client.activate_async((), ()).unwrap(); + let ac = active_client(); let client = ac.as_client(); let t0 = client.time(); - let frames0 = client.frames_since_cycle_start(); let frame_time0 = client.frame_time(); - std::thread::sleep(std::time::Duration::from_millis(50)); - assert_ne!(client.time(), t0); - assert_ne!(client.frames_since_cycle_start(), frames0); - assert_ne!(client.frame_time(), frame_time0); + std::thread::sleep(Duration::from_millis(50)); + // `frames_since_cycle_start` is an offset within the current cycle, so it is not monotonic and + // is not checked here. + assert!(client.time() > t0); + assert!(client.frame_time() > frame_time0); } #[test] #[ignore = "unsupported on pipewire-jack; CI runs ignored tests with JACK2"] fn maybe_client_can_set_buffer_size() { - let initial_buffer_size = DEFAULT_TEST_CLIENT.buffer_size(); - if let Err(err) = DEFAULT_TEST_CLIENT.set_buffer_size(initial_buffer_size * 2) { + let ac = active_client(); + let client = ac.as_client(); + let initial_buffer_size = client.buffer_size(); + if let Err(err) = client.set_buffer_size(initial_buffer_size * 2) { eprintln!("client does not support setting buffer size: {err}"); return; } - assert_eq!(DEFAULT_TEST_CLIENT.buffer_size(), 2 * initial_buffer_size); - DEFAULT_TEST_CLIENT - .set_buffer_size(initial_buffer_size) - .unwrap(); + // The server applies the change asynchronously. + let changed = wait_for(Duration::from_secs(1), || { + client.buffer_size() == 2 * initial_buffer_size + }); + client.set_buffer_size(initial_buffer_size).unwrap(); + assert!(changed, "buffer size is still {}", client.buffer_size()); } #[test] @@ -87,8 +97,11 @@ fn nonexistant_uuid_to_client_name_returns_none() { let uuid_string = client.uuid_string(); let uuid = client.uuid(); drop(client); - assert_eq!(DEFAULT_TEST_CLIENT.name_by_uuid_str(&uuid_string), None); - assert_eq!(DEFAULT_TEST_CLIENT.name_by_uuid(uuid), None); + let (observer, _) = crate::Client::new("", crate::ClientOptions::default()).unwrap(); + // The server may take a moment to forget the closed client. + assert!(wait_for(Duration::from_secs(1), || { + observer.name_by_uuid_str(&uuid_string).is_none() && observer.name_by_uuid(uuid).is_none() + })); } #[test] @@ -105,7 +118,6 @@ fn unregistering_another_clients_port_is_an_unregistration_error() { Err(crate::Error::PortUnregistrationError) ); } - #[test] fn registering_an_unowned_port_is_an_error() { let (client, _) = crate::Client::new("", crate::ClientOptions::default()).unwrap(); @@ -114,3 +126,65 @@ fn registering_an_unowned_port_is_an_error() { Err(crate::Error::PortRegistrationError("p".to_string())) ); } + +#[test] +fn error_messages_are_spelled_correctly() { + assert_eq!( + crate::Error::UnknownError { error_code: 3 }.to_string(), + "unknown error with code 3" + ); + assert_eq!( + crate::Error::ClientPanicked.to_string(), + "client notification or processor panicked" + ); +} + +#[test] +fn client_options_support_common_traits() { + let options = crate::ClientOptions::NO_START_SERVER | crate::ClientOptions::USE_EXACT_NAME; + let copy = options; + assert_eq!(copy.clone(), options); + assert!(format!("{:?}", options).contains("USE_EXACT_NAME")); +} + +#[test] +fn options_that_need_variadic_arguments_are_ignored() { + // `jack_client_open` reads an extra variadic argument for each of these flags. `Client::new` + // passes none, so they must be masked out instead of making JACK read garbage. + for flag in [ + jack_sys::JackServerName, + jack_sys::JackLoadName, + jack_sys::JackLoadInit, + ] { + let options = + crate::ClientOptions::from_bits_retain(crate::ClientOptions::default().bits() | flag); + let (client, status) = crate::Client::new("variadic-options", options).unwrap(); + assert!(!status.contains(crate::ClientStatus::INVALID_OPTION)); + drop(client); + } +} + +#[test] +fn shutdown_can_be_implemented_as_a_safe_fn() { + struct Handler; + impl crate::NotificationHandler for Handler { + fn shutdown(&mut self, _status: crate::ClientStatus, _reason: &str) {} + } + let (client, _) = crate::Client::new("", crate::ClientOptions::default()).unwrap(); + let ac = client.activate_async(Handler, ()).unwrap(); + ac.deactivate().unwrap(); +} + +#[test] +fn set_name_renames_the_port() { + let (client, _) = crate::Client::new("", crate::ClientOptions::default()).unwrap(); + let mut port = client + .register_port("before", crate::AudioIn::default()) + .unwrap(); + port.set_name("after").unwrap(); + assert!( + port.name().unwrap().ends_with(":after"), + "{:?}", + port.name() + ); +} diff --git a/src/tests/invalid_input.rs b/src/tests/invalid_input.rs new file mode 100644 index 000000000..b875b2686 --- /dev/null +++ b/src/tests/invalid_input.rs @@ -0,0 +1,77 @@ +//! The safe API must report bad input as an error instead of panicking. + +use crate::{AudioIn, AudioOut, Client, ClientOptions, Error, PortFlags, Property}; + +fn is_invalid_string(res: Result) -> bool { + matches!(res, Err(Error::InvalidString(_))) +} + +#[test] +fn strings_with_nul_bytes_are_rejected() { + let (client, _) = Client::new("", ClientOptions::default()).unwrap(); + let mut port = client.register_port("ok", AudioOut::default()).unwrap(); + let port_name = port.name().unwrap(); + + assert!(is_invalid_string( + client.register_port("a\0b", AudioIn::default()) + )); + assert!(is_invalid_string( + client.connect_ports_by_name("a\0b", &port_name) + )); + assert!(is_invalid_string( + client.connect_ports_by_name(&port_name, "a\0b") + )); + assert!(is_invalid_string( + client.disconnect_ports_by_name("a\0b", &port_name) + )); + assert!(is_invalid_string( + client.request_monitor_by_name("a\0b", true) + )); + assert!(is_invalid_string( + client.load_internal_client("a\0b", "x", "") + )); + assert!(is_invalid_string(port.is_connected_to("a\0b"))); + assert!(is_invalid_string(port.set_name("a\0b"))); + assert!(is_invalid_string(port.set_alias("a\0b"))); + assert!(is_invalid_string(port.unset_alias("a\0b"))); + assert!(is_invalid_string(client.property_set( + client.uuid(), + "a\0b", + &Property::new("v", None) + ))); + assert!(is_invalid_string(client.property_set( + client.uuid(), + "k", + &Property::new("a\0b", None) + ))); + assert!(is_invalid_string(client.property_set( + client.uuid(), + "k", + &Property::new("v", Some("a\0b".into())) + ))); + assert!(is_invalid_string( + client.property_remove(client.uuid(), "a\0b") + )); + + assert!(client.port_by_name("a\0b").is_none()); + assert!(client + .ports(Some("a\0b"), None, PortFlags::empty()) + .is_empty()); + assert!(client + .ports(None, Some("a\0b"), PortFlags::empty()) + .is_empty()); + assert!(client.uuid_of_client_by_name("a\0b").is_none()); + assert!(client.name_by_uuid_str("a\0b").is_none()); + assert!(client.property_get(client.uuid(), "a\0b").is_none()); +} + +#[test] +fn registering_a_second_property_change_handler_is_an_error() { + let (mut client, _) = Client::new("", ClientOptions::default()).unwrap(); + let handler = || crate::ClosurePropertyChangeHandler::new(|_| {}); + assert_eq!(client.register_property_change_handler(handler()), Ok(())); + assert_eq!( + client.register_property_change_handler(handler()), + Err(Error::CallbackRegistrationError) + ); +} diff --git a/src/tests/mod.rs b/src/tests/mod.rs index 0f82d0616..c50cf7bf0 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -1,21 +1,44 @@ -use std::sync::LazyLock; +use std::time::{Duration, Instant}; use ctor::ctor; -use crate::{Client, ClientOptions}; +use crate::{AsyncClient, Client, ClientOptions}; mod client; +mod invalid_input; mod log; +mod port; mod processing; mod ringbuffer; mod time; mod transport; -pub static DEFAULT_TEST_CLIENT: LazyLock = LazyLock::new(|| { - Client::new("default-test-client", ClientOptions::default()) - .unwrap() - .0 -}); +// There is deliberately no shared static test client. A client that is still open when the test +// binary exits races with PipeWire's library destructors and can abort the process. + +/// Open a new client and activate it with handlers that do nothing. +/// +/// Some servers, such as PipeWire, only report timing information for active clients. +pub fn active_client() -> AsyncClient<(), ()> { + let (client, _) = Client::new("", ClientOptions::default()).unwrap(); + client.activate_async((), ()).unwrap() +} + +/// Poll `f` until it returns `true` or `timeout` passes. Returns the last result. +/// +/// Servers apply some changes asynchronously, so tests wait for them instead of checking once. +pub fn wait_for(timeout: Duration, mut f: impl FnMut() -> bool) -> bool { + let deadline = Instant::now() + timeout; + loop { + if f() { + return true; + } + if Instant::now() >= deadline { + return false; + } + std::thread::sleep(Duration::from_millis(10)); + } +} #[ctor] fn log_to_stdio() { diff --git a/src/tests/port.rs b/src/tests/port.rs new file mode 100644 index 000000000..42c1a34a0 --- /dev/null +++ b/src/tests/port.rs @@ -0,0 +1,56 @@ +use crate::{AudioIn, Client, ClientOptions, Error, LatencyType}; + +#[test] +fn port_methods_fail_after_client_is_dropped() { + let (client, _) = Client::new("", ClientOptions::default()).unwrap(); + let port = client.register_port("in", AudioIn::default()).unwrap(); + let transport = client.transport(); + drop(client); + + assert_eq!(port.name(), Err(Error::ClientIsNoLongerAlive)); + assert_eq!(port.flags(), Err(Error::ClientIsNoLongerAlive)); + assert_eq!( + port.get_latency_range(LatencyType::Capture), + Err(Error::ClientIsNoLongerAlive) + ); + assert_eq!( + port.set_latency_range(LatencyType::Capture, (1, 2)), + Err(Error::ClientIsNoLongerAlive) + ); + assert_eq!(port.get_connections(), Err(Error::ClientIsNoLongerAlive)); + assert_eq!( + port.get_connected_client_uuids(), + Err(Error::ClientIsNoLongerAlive) + ); + assert!(transport.query_state().is_err()); +} + +#[test] +fn port_methods_race_with_client_drop() { + // A port used on another thread while its client is dropped must either succeed or report + // that the client is gone. It must never call into a closed client. + for _ in 0..20 { + let (client, _) = Client::new("", ClientOptions::default()).unwrap(); + let port = client.register_port("in", AudioIn::default()).unwrap(); + let stop = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false)); + let user = { + let stop = stop.clone(); + std::thread::spawn(move || { + while !stop.load(std::sync::atomic::Ordering::Relaxed) { + match port.name() { + Ok(name) => assert!(name.ends_with(":in"), "{}", name), + Err(err) => { + assert_eq!(err, Error::ClientIsNoLongerAlive); + return; + } + } + } + }) + }; + std::thread::sleep(std::time::Duration::from_millis(5)); + drop(client); + std::thread::sleep(std::time::Duration::from_millis(5)); + stop.store(true, std::sync::atomic::Ordering::Relaxed); + user.join().unwrap(); + } +} diff --git a/src/tests/processing.rs b/src/tests/processing.rs index 93b47f069..b12412f3f 100644 --- a/src/tests/processing.rs +++ b/src/tests/processing.rs @@ -202,3 +202,162 @@ fn activating_client_notifies_buffer_size_before_beginning() { let initial_buffer_size = client.buffer_size() as usize; assert_ne!(initial_buffer_size, 0); } + +#[test] +fn deactivated_client_survives_graph_changes() { + // After deactivation, JACK must not call into the freed callback context. Before all callbacks + // were cleared on deactivation, this crashed the test binary with a use-after-free. + struct Handler(std::sync::Arc); + impl crate::NotificationHandler for Handler { + fn client_registration(&mut self, _: &crate::Client, _: &str, _: bool) { + self.0.fetch_add(1, std::sync::atomic::Ordering::SeqCst); + } + } + let registrations = std::sync::Arc::new(std::sync::atomic::AtomicUsize::new(0)); + let (client, _) = crate::Client::new("deactivated", crate::ClientOptions::default()).unwrap(); + let ac = client + .activate_async(Handler(registrations.clone()), ()) + .unwrap(); + let (client, _handler, _) = ac.deactivate().unwrap(); + let registrations_at_deactivation = registrations.load(std::sync::atomic::Ordering::SeqCst); + for i in 0..3 { + let name = format!("graph-change-{i}"); + let (other, _) = crate::Client::new(&name, crate::ClientOptions::default()).unwrap(); + std::thread::sleep(std::time::Duration::from_millis(100)); + drop(other); + } + std::thread::sleep(std::time::Duration::from_millis(200)); + assert_eq!( + registrations.load(std::sync::atomic::Ordering::SeqCst), + registrations_at_deactivation + ); + drop(client); +} + +#[test] +fn set_freewheel_notifies_freewheel_handler() { + struct Handler(std::sync::mpsc::SyncSender); + impl crate::NotificationHandler for Handler { + fn freewheel(&mut self, _: &crate::Client, is_freewheel_enabled: bool) { + self.0.try_send(is_freewheel_enabled).ok(); + } + } + let (client, _) = crate::Client::new("", crate::ClientOptions::default()).unwrap(); + let (send, recv) = std::sync::mpsc::sync_channel(4); + let ac = client.activate_async(Handler(send), ()).unwrap(); + let timeout = std::time::Duration::from_secs(1); + ac.as_client().set_freewheel(true).unwrap(); + assert_eq!(recv.recv_timeout(timeout), Ok(true)); + ac.as_client().set_freewheel(false).unwrap(); + assert_eq!(recv.recv_timeout(timeout), Ok(false)); + ac.deactivate().unwrap(); +} + +#[test] +fn renaming_a_port_calls_port_rename() { + struct Handler(std::sync::mpsc::SyncSender<(String, String)>); + impl crate::NotificationHandler for Handler { + fn port_rename( + &mut self, + _: &crate::Client, + _: crate::PortId, + old_name: &str, + new_name: &str, + ) -> crate::Control { + self.0 + .try_send((old_name.to_string(), new_name.to_string())) + .ok(); + crate::Control::Continue + } + } + let (owner, _) = crate::Client::new("renamer", crate::ClientOptions::default()).unwrap(); + let mut port = owner + .register_port("before", crate::AudioIn::default()) + .unwrap(); + let _owner = owner.activate_async((), ()).unwrap(); + let (observer, _) = crate::Client::new("observer", crate::ClientOptions::default()).unwrap(); + let (send, recv) = std::sync::mpsc::sync_channel(4); + let ac = observer.activate_async(Handler(send), ()).unwrap(); + std::thread::sleep(std::time::Duration::from_millis(100)); + port.set_name("after").unwrap(); + let (old_name, new_name) = recv + .recv_timeout(std::time::Duration::from_secs(1)) + .unwrap(); + assert!(old_name.ends_with(":before"), "{}", old_name); + assert!(new_name.ends_with(":after"), "{}", new_name); + ac.deactivate().unwrap(); +} + +#[test] +fn writing_too_much_midi_returns_not_enough_space() { + let (client, _) = crate::Client::new("", crate::ClientOptions::default()).unwrap(); + let mut output = client + .register_port("out", crate::MidiOut::default()) + .unwrap(); + let (send, recv) = std::sync::mpsc::sync_channel(1); + let process_handler = crate::contrib::ClosureProcessHandler::new(move |_, ps| { + let mut writer = output.writer(ps); + let too_big = vec![0x90; writer.max_event_size() + 1]; + let result = writer.write(&crate::RawMidi { + time: 0, + bytes: &too_big, + }); + send.try_send(result).ok(); + crate::Control::Quit + }); + let ac = client.activate_async((), process_handler).unwrap(); + let result = recv + .recv_timeout(std::time::Duration::from_secs(1)) + .unwrap(); + ac.deactivate().ok(); + assert_eq!(result, Err(crate::Error::NotEnoughSpace)); +} + +#[test] +fn failed_activation_returns_an_error_and_drops_the_handlers() { + struct DropFlag(std::sync::Arc); + impl Drop for DropFlag { + fn drop(&mut self) { + self.0.store(true, std::sync::atomic::Ordering::SeqCst); + } + } + impl crate::NotificationHandler for DropFlag {} + + let dropped = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false)); + let (client, _) = crate::Client::new("", crate::ClientOptions::default()).unwrap(); + // JACK refuses to register callbacks on a client that is already active. + assert_eq!(unsafe { jack_sys::jack_activate(client.raw()) }, 0); + let res = client.activate_async(DropFlag(dropped.clone()), ()); + assert!( + matches!(res, Err(crate::Error::CallbackRegistrationError)), + "{:?}", + res.map(|_| ()) + ); + assert!(dropped.load(std::sync::atomic::Ordering::SeqCst)); +} + +#[test] +fn deactivating_while_process_writes_to_stderr_does_not_abort() { + // PipeWire's JACK stops its process thread with `pthread_cancel`. If the cancellation lands + // on a cancellation point inside a Rust callback (such as the `write` behind `eprintln!`), the + // forced unwind used to run through `catch_unwind` and abort the whole process with "FATAL: + // exception not rethrown". + for _ in 0..10 { + let (client, _) = crate::Client::new("", crate::ClientOptions::default()).unwrap(); + let (send, recv) = std::sync::mpsc::sync_channel(1); + let process_handler = crate::contrib::ClosureProcessHandler::new(move |_, _| { + send.try_send(()).ok(); + for _ in 0..1000 { + eprint!(""); + std::io::Write::flush(&mut std::io::stderr()).ok(); + // `write` with a zero length still reaches a cancellation point. + unsafe { libc::write(2, std::ptr::null(), 0) }; + } + crate::Control::Continue + }); + let ac = client.activate_async((), process_handler).unwrap(); + recv.recv_timeout(std::time::Duration::from_secs(1)) + .unwrap(); + ac.deactivate().unwrap(); + } +} diff --git a/src/tests/ringbuffer.rs b/src/tests/ringbuffer.rs index 2dd24b69a..d95575dd4 100644 --- a/src/tests/ringbuffer.rs +++ b/src/tests/ringbuffer.rs @@ -91,3 +91,52 @@ fn reading_and_writing_from_separate_threads_is_ok() { .unwrap(); assert_eq!(reader.read_slice(&mut [0; 8]), &[0, 1, 2, 3]); } + +fn freed_count() -> usize { + crate::ringbuffer::FREED_COUNT.with(|c| c.get()) +} + +#[test] +fn dropping_reader_then_writer_frees_ringbuffer() { + let before = freed_count(); + let (reader, writer) = RingBuffer::new(1024).unwrap().into_reader_writer(); + drop(reader); + assert_eq!(freed_count(), before); + drop(writer); + assert_eq!(freed_count(), before + 1); +} + +#[test] +fn dropping_writer_then_reader_frees_ringbuffer() { + let before = freed_count(); + let (reader, writer) = RingBuffer::new(1024).unwrap().into_reader_writer(); + drop(writer); + assert_eq!(freed_count(), before); + drop(reader); + assert_eq!(freed_count(), before + 1); +} + +#[test] +fn dropping_halves_on_different_threads_frees_ringbuffer_once() { + // The count is per thread, so check that exactly one of the two threads freed it. + let (reader, writer) = RingBuffer::new(1024).unwrap().into_reader_writer(); + let a = std::thread::spawn(move || { + drop(reader); + freed_count() + }); + let b = std::thread::spawn(move || { + drop(writer); + freed_count() + }); + assert_eq!(a.join().unwrap() + b.join().unwrap(), 1); +} + +#[test] +fn rejoined_ringbuffer_is_freed_once() { + let before = freed_count(); + let (reader, writer) = RingBuffer::new(1024).unwrap().into_reader_writer(); + let ringbuf = RingBuffer::from_reader_writer(reader, writer); + assert_eq!(freed_count(), before); + drop(ringbuf); + assert_eq!(freed_count(), before + 1); +} diff --git a/src/tests/time.rs b/src/tests/time.rs index 42ac2c3e4..0cf082ff8 100644 --- a/src/tests/time.rs +++ b/src/tests/time.rs @@ -1,27 +1,16 @@ use approx::assert_abs_diff_eq; -use crate::contrib::ClosureProcessHandler; - -fn active_client() -> crate::AsyncClient<(), impl crate::ProcessHandler> { - let (client, _) = crate::Client::new("", crate::ClientOptions::empty()).unwrap(); - let (send, recv) = std::sync::mpsc::sync_channel(1); - let ac = client - .activate_async( - (), - ClosureProcessHandler::new(move |_, _| { - send.try_send(()).ok(); - crate::Control::Continue - }), - ) - .unwrap(); - recv.recv_timeout(std::time::Duration::from_secs(1)) - .unwrap(); - ac +/// Wait until the server reports timing information, which it may only do once process cycles +/// have run. +fn wait_for_timing(client: &crate::Client) { + crate::tests::wait_for(std::time::Duration::from_secs(1), || { + client.frames_to_time(client.sample_rate()) != client.frames_to_time(0) + }); } #[test] fn frame_and_time_are_convertable() { - let ac = active_client(); + let ac = crate::tests::active_client(); let client = ac.as_client(); let frame_time = client.frame_time(); assert_abs_diff_eq!( @@ -33,8 +22,10 @@ fn frame_and_time_are_convertable() { #[test] fn one_frame_duration_is_inverse_of_sample_rate() { - let ac = active_client(); + // Some servers, such as PipeWire, only convert times for active clients. + let ac = crate::tests::active_client(); let client = ac.as_client(); + wait_for_timing(client); let sample_rate = client.sample_rate(); assert_abs_diff_eq!( (client.frames_to_time(sample_rate as _) - client.frames_to_time(0)) as f64, @@ -45,8 +36,11 @@ fn one_frame_duration_is_inverse_of_sample_rate() { #[test] fn one_second_is_sample_rate_frames() { - let ac = active_client(); + let ac = crate::tests::active_client(); let client = ac.as_client(); + wait_for_timing(client); + // Convert times near now. Times far from the current cycle, such as 0, may not be + // representable by every server. let now = client.time(); let t0 = client.time_to_frames(now); let t1 = client.time_to_frames(now + 1_000_000); @@ -56,3 +50,22 @@ fn one_second_is_sample_rate_frames() { epsilon = client.sample_rate() as f64 * 1e-3 ); } + +#[test] +fn cycle_times_are_available_in_process() { + // `jack_get_cycle_times` is an optional symbol. It must be found both with dynamic loading and + // with static linking (`--no-default-features`). + let (client, _) = crate::Client::new("", Default::default()).unwrap(); + let (send, recv) = std::sync::mpsc::sync_channel(1); + let handler = crate::contrib::ClosureProcessHandler::new(move |_, ps| { + send.try_send(ps.cycle_times()).ok(); + crate::Control::Continue + }); + let ac = client.activate_async((), handler).unwrap(); + let cycle_times = recv + .recv_timeout(std::time::Duration::from_secs(1)) + .unwrap(); + ac.deactivate().unwrap(); + let cycle_times = cycle_times.unwrap(); + assert!(cycle_times.period_usecs > 0.0, "{:?}", cycle_times); +} diff --git a/src/tests/transport.rs b/src/tests/transport.rs index aa7779c3d..fdce1ad6d 100644 --- a/src/tests/transport.rs +++ b/src/tests/transport.rs @@ -1,9 +1,6 @@ -use std::{ - thread::sleep, - time::{Duration, Instant}, -}; +use std::time::Duration; -use crate::{Client, TransportPosition, TransportState}; +use crate::{TransportPosition, TransportState}; #[test] fn new_transport_is_not_valid() { @@ -18,34 +15,53 @@ fn new_transport_is_not_valid() { #[test] fn starting_transport_sets_state_to_started() { - let (client, _) = Client::new("", Default::default()).unwrap(); - let ac = client.activate_async((), ()).unwrap(); + // The transport only moves while process cycles run, so the client must be active. + let ac = crate::tests::active_client(); let transport = ac.as_client().transport(); - // Transport requests take effect asynchronously over subsequent process cycles. - let wait_for_state = |expected| { - let deadline = Instant::now() + Duration::from_secs(3); - loop { - let state = transport.query().unwrap().state; - if state == expected { - break; - } - assert!( - Instant::now() < deadline, - "timed out waiting for transport state {:?}; last state: {:?}", - expected, - state - ); - sleep(Duration::from_millis(5)); - } + let state_becomes = |state| { + crate::tests::wait_for(Duration::from_secs(3), || { + transport.query().unwrap().state == state + }) }; transport.stop().unwrap(); - wait_for_state(TransportState::Stopped); + assert!(state_becomes(TransportState::Stopped)); transport.start().unwrap(); - wait_for_state(TransportState::Rolling); - + let rolled = state_becomes(TransportState::Rolling); transport.stop().unwrap(); - wait_for_state(TransportState::Stopped); + assert!(rolled, "{:?}", transport.query().unwrap().state); + assert!(state_becomes(TransportState::Stopped)); +} + +#[test] +fn bbt_with_nan_is_invalid() { + use crate::{TransportBBT, TransportBBTValidationError as E}; + let nan = |f: fn(&mut TransportBBT)| { + let mut bbt = TransportBBT::default(); + f(&mut bbt); + bbt.validated() + }; + assert_eq!(nan(|b| b.sig_num = f32::NAN), Err(E::SigNumRange)); + assert_eq!(nan(|b| b.sig_denom = f32::NAN), Err(E::SigDenomRange)); + assert_eq!( + nan(|b| b.ticks_per_beat = f64::NAN), + Err(E::TicksPerBeatRange) + ); + assert_eq!(nan(|b| b.bpm = f64::NAN), Err(E::BPMRange)); + assert_eq!( + nan(|b| b.bar_start_tick = f64::NAN), + Err(E::BarStartTickRange) + ); + assert!(TransportBBT::default().validated().is_ok()); +} + +#[test] +fn bbt_offset_round_trips() { + let mut pos = TransportPosition::default(); + let () = pos.set_bbt_offset(Some(5)); + assert_eq!(pos.bbt_offset(), Some(5)); + let () = pos.set_bbt_offset(None); + assert_eq!(pos.bbt_offset(), None); } diff --git a/src/transport.rs b/src/transport.rs index ae95ad0df..1fffe0f36 100644 --- a/src/transport.rs +++ b/src/transport.rs @@ -1,15 +1,16 @@ //! JACK transport wrappers. //! See the [transport design api docs](https://jackaudio.org/api/transport-design.html) for more info. +use crate::client::common::ClientLife; use crate::{Frames, Time}; use jack_sys as j; -use std::sync::Weak; +use std::sync::Arc; pub type Result = ::std::result::Result; /// A structure for querying and manipulating the JACK transport. pub struct Transport { pub(crate) client_ptr: *mut j::jack_client_t, - pub(crate) client_life: Weak<()>, + pub(crate) client_life: Arc, } //all exposed methods are realtime safe @@ -21,7 +22,20 @@ unsafe impl Sync for Transport {} pub struct TransportPosition(j::jack_position_t); /// A representation of transport state. +/// +/// New states may be added in the future, so matches need a wildcard arm: +/// +/// ```compile_fail +/// fn describe(state: jack::TransportState) -> &'static str { +/// match state { +/// jack::TransportState::Stopped => "stopped", +/// jack::TransportState::Rolling => "rolling", +/// jack::TransportState::Starting => "starting", +/// } +/// } +/// ``` #[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[non_exhaustive] pub enum TransportState { Stopped, Rolling, @@ -79,6 +93,8 @@ pub enum TransportBBTValidationError { BPMRange, ///`tick` must be less than `ticks_per_beat` TickRange, + ///`bar_start_tick` must be a finite number + BarStartTickRange, } impl std::fmt::Display for TransportBBTValidationError { @@ -202,11 +218,8 @@ impl Transport { } fn with_client R, R>(&self, func: F) -> Result { - if self.client_life.upgrade().is_some() { - Ok(func(self.client_ptr)) - } else { - Err(crate::Error::ClientIsNoLongerAlive) - } + let _life = self.client_life.enter()?; + Ok(func(self.client_ptr)) } // Helper to create generic error from jack response @@ -274,6 +287,9 @@ impl TransportPosition { } /// Get the BarBeatsTick data if it is valid. + /// + /// Returns `None` if the position has no BarBeatsTick data, or if the data fails + /// [`TransportBBT::validated`]. pub fn bbt(&self) -> Option { if self.valid_bbt() { TransportBBT { @@ -351,16 +367,14 @@ impl TransportPosition { /// /// * If this value is 0, the bbt time refers to the first frame of this cycle. /// * Otherwise, the bbt time refers to a frame that many frames **before** the start of the cycle. - pub fn set_bbt_offset(&mut self, frame: Option) -> std::result::Result<(), Frames> { + pub fn set_bbt_offset(&mut self, frame: Option) { match frame { None => { self.0.valid &= !j::JackBBTFrameOffset; - Ok(()) } Some(frame) => { self.0.bbt_offset = frame; self.0.valid |= j::JackBBTFrameOffset; - Ok(()) } } } @@ -433,21 +447,29 @@ impl TransportBBT { } /// Returns `self` is valid, otherwise returns an error describing what is invalid. + /// + /// NaN and infinite values are invalid. pub fn validated(&'_ self) -> std::result::Result { + // The comparisons are written so that NaN fails them. The time signature is checked + // before `beat` and `ticks_per_beat` before `tick`, since those ranges depend on them. + let positive_f32 = |x: f32| x > 0. && x.is_finite(); + let positive_f64 = |x: f64| x > 0. && x.is_finite(); if self.bar == 0 { Err(TransportBBTValidationError::BarZero) + } else if !positive_f32(self.sig_num) { + Err(TransportBBTValidationError::SigNumRange) + } else if !positive_f32(self.sig_denom) { + Err(TransportBBTValidationError::SigDenomRange) } else if self.beat == 0 || self.beat > self.sig_num.ceil() as _ { Err(TransportBBTValidationError::BeatRange) - } else if self.ticks_per_beat <= 0. { + } else if !positive_f64(self.ticks_per_beat) { Err(TransportBBTValidationError::TicksPerBeatRange) - } else if self.sig_num <= 0. { - Err(TransportBBTValidationError::SigNumRange) - } else if self.sig_denom <= 0. { - Err(TransportBBTValidationError::SigDenomRange) - } else if self.bpm < 0. { + } else if !(self.bpm >= 0. && self.bpm.is_finite()) { Err(TransportBBTValidationError::BPMRange) } else if self.tick >= self.ticks_per_beat.ceil() as _ { Err(TransportBBTValidationError::TickRange) + } else if !self.bar_start_tick.is_finite() { + Err(TransportBBTValidationError::BarStartTickRange) } else { Ok(*self) }