From f3ff1b9669a2e56f73867ab7ebe3128833c4ab93 Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Thu, 23 Oct 2014 13:01:45 +0200 Subject: [PATCH] weak/runtime jack linking: load libjack dynamically at runtime --- libs/backends/jack/jack_audiobackend.cc | 3 - libs/backends/jack/jack_audiobackend.h | 3 +- libs/backends/jack/jack_connection.cc | 5 +- libs/backends/jack/jack_connection.h | 2 +- libs/backends/jack/jack_portengine.cc | 1 - libs/backends/jack/jack_session.cc | 3 - libs/backends/jack/jack_session.h | 3 +- libs/backends/jack/jack_utils.cc | 2 - libs/backends/jack/weak_libjack.c | 496 ++++++++++++++++++++++++ libs/backends/jack/weak_libjack.h | 188 +++++++++ libs/backends/jack/wscript | 32 +- wscript | 3 + 12 files changed, 717 insertions(+), 24 deletions(-) create mode 100644 libs/backends/jack/weak_libjack.c create mode 100644 libs/backends/jack/weak_libjack.h diff --git a/libs/backends/jack/jack_audiobackend.cc b/libs/backends/jack/jack_audiobackend.cc index 65df9a93fc..64991c1623 100644 --- a/libs/backends/jack/jack_audiobackend.cc +++ b/libs/backends/jack/jack_audiobackend.cc @@ -27,9 +27,6 @@ #include "pbd/error.h" -#include "jack/jack.h" -#include "jack/thread.h" - #include "ardour/audioengine.h" #include "ardour/session.h" #include "ardour/types.h" diff --git a/libs/backends/jack/jack_audiobackend.h b/libs/backends/jack/jack_audiobackend.h index 0fd06407f3..3a1225f90d 100644 --- a/libs/backends/jack/jack_audiobackend.h +++ b/libs/backends/jack/jack_audiobackend.h @@ -29,8 +29,7 @@ #include -#include -#include +#include "weak_libjack.h" #include "ardour/audio_backend.h" diff --git a/libs/backends/jack/jack_connection.cc b/libs/backends/jack/jack_connection.cc index fee1b299ba..201769070b 100644 --- a/libs/backends/jack/jack_connection.cc +++ b/libs/backends/jack/jack_connection.cc @@ -19,7 +19,6 @@ #include #include -#include #include @@ -75,7 +74,7 @@ JackConnection::JackConnection (const std::string& arg1, const std::string& arg2 } jack_status_t status; - jack_client_t* c = jack_client_open ("ardourprobe", JackNoStartServer, &status); + jack_client_t* c = jack_client_open1 ("ardourprobe", JackNoStartServer, &status); if (status == 0) { jack_client_close (c); @@ -115,7 +114,7 @@ JackConnection::open () get_jack_server_dir_paths (dirs); set_path_env_for_jack_autostart (dirs); - if ((_jack = jack_client_open (_client_name.c_str(), JackSessionID, &status, session_uuid.c_str())) == 0) { + if ((_jack = jack_client_open2 (_client_name.c_str(), JackSessionID, &status, session_uuid.c_str())) == 0) { return -1; } diff --git a/libs/backends/jack/jack_connection.h b/libs/backends/jack/jack_connection.h index 8d15be6e3a..a7462344dc 100644 --- a/libs/backends/jack/jack_connection.h +++ b/libs/backends/jack/jack_connection.h @@ -2,7 +2,7 @@ #define __libardour_jack_connection_h__ #include -#include +#include "weak_libjack.h" #include "pbd/signals.h" diff --git a/libs/backends/jack/jack_portengine.cc b/libs/backends/jack/jack_portengine.cc index 1fe77fbb70..368f64bae7 100644 --- a/libs/backends/jack/jack_portengine.cc +++ b/libs/backends/jack/jack_portengine.cc @@ -24,7 +24,6 @@ #include "jack_audiobackend.h" #include "jack_connection.h" -#include "jack/midiport.h" #include "ardour/port_manager.h" diff --git a/libs/backends/jack/jack_session.cc b/libs/backends/jack/jack_session.cc index 60d11a8f0c..c9ee8c61e0 100644 --- a/libs/backends/jack/jack_session.cc +++ b/libs/backends/jack/jack_session.cc @@ -22,9 +22,6 @@ #include -#include -#include - #include "pbd/localtime_r.h" #include "ardour/audioengine.h" diff --git a/libs/backends/jack/jack_session.h b/libs/backends/jack/jack_session.h index c912b5f170..996ab1fd6b 100644 --- a/libs/backends/jack/jack_session.h +++ b/libs/backends/jack/jack_session.h @@ -20,8 +20,7 @@ #ifndef __ardour_jack_audiobackend_jack_session_h__ #define __ardour_jack_audiobackend_jack_session_h__ -#include -#include +#include "weak_libjack.h" #include "ardour/types.h" #include "ardour/session_handle.h" diff --git a/libs/backends/jack/jack_utils.cc b/libs/backends/jack/jack_utils.cc index 8bbfab5cf1..92e19985a0 100644 --- a/libs/backends/jack/jack_utils.cc +++ b/libs/backends/jack/jack_utils.cc @@ -38,8 +38,6 @@ #include #endif -#include - #include #include diff --git a/libs/backends/jack/weak_libjack.c b/libs/backends/jack/weak_libjack.c new file mode 100644 index 0000000000..69d670b117 --- /dev/null +++ b/libs/backends/jack/weak_libjack.c @@ -0,0 +1,496 @@ +/* runtime/weak dynamic JACK linking + * + * (C) 2014 Robin Gareus + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "weak_libjack.h" + +#ifndef USE_WEAK_JACK + +int have_libjack (void) { + return 0; +} + +#else + +#include +#include +#include + +#ifdef PLATFORM_WINDOWS +#include +#else +#include +#endif + +#include +#include +#include +#include +#include +#include + +static void* lib_open(const char* const so) { +#ifdef PLATFORM_WINDOWS + return (void*) LoadLibraryA(so); +#else + return dlopen(so, RTLD_NOW|RTLD_LOCAL); +#endif +} + +static void* lib_symbol(void* const lib, const char* const sym) { +#ifdef PLATFORM_WINDOWS + return (void*) GetProcAddress((HMODULE)lib, sym); +#else + return dlsym(lib, sym); +#endif +} + +#ifdef COMPILER_MSVC +typedef void * pvoid_t; +#define MAPSYM(SYM, FAIL) _j._ ## SYM = lib_symbol(lib, "jack_" # SYM); \ + if (!_j._ ## SYM) err |= FAIL; +#else +typedef void * __attribute__ ((__may_alias__)) pvoid_t; +#define MAPSYM(SYM, FAIL) *(pvoid_t *)(&_j._ ## SYM) = lib_symbol(lib, "jack_" # SYM); \ + if (!_j._ ## SYM) err |= FAIL; +#endif +typedef void (* func_t) (void); + +/* function pointers to the real jack API */ +static struct WeakJack { + func_t _client_open; + func_t _client_close; + func_t _get_client_name; + + func_t _get_buffer_size; + func_t _get_sample_rate; + func_t _frames_since_cycle_start; + func_t _frame_time; + func_t _last_frame_time; + func_t _cpu_load; + func_t _is_realtime; + + func_t _set_freewheel; + func_t _set_buffer_size; + + func_t _on_shutdown; + func_t _on_info_shutdown; + func_t _set_process_callback; + func_t _set_freewheel_callback; + func_t _set_buffer_size_callback; + func_t _set_sample_rate_callback; + func_t _set_port_registration_callback; + func_t _set_port_connect_callback; + func_t _set_graph_order_callback; + func_t _set_xrun_callback; + func_t _set_latency_callback; + func_t _set_error_function; + + func_t _activate; + func_t _deactivate; + + func_t _recompute_total_latencies; + func_t _port_get_total_latency; + func_t _port_get_latency_range; + func_t _port_set_latency_range; + func_t _port_get_buffer; + func_t _port_request_monitor; + func_t _port_ensure_monitor; + func_t _port_monitoring_input; + + func_t _port_name; + func_t _port_flags; + func_t _get_ports; + func_t _port_name_size; + func_t _port_type_size; + func_t _port_type_get_buffer_size; + func_t _port_by_name; + func_t _port_by_id; + func_t _port_register; + func_t _port_unregister; + func_t _port_type; + func_t _port_get_connections; + func_t _port_get_all_connections; + func_t _port_set_name; + func_t _port_disconnect; + func_t _connect; + func_t _disconnect; + func_t _free; + func_t _cycle_wait; + func_t _cycle_signal; + func_t _set_process_thread; + func_t _set_thread_init_callback; + + func_t _get_current_transport_frame; + func_t _transport_locate; + func_t _transport_start; + func_t _transport_stop; + func_t _transport_query; + func_t _set_sync_callback; + func_t _set_timebase_callback; + func_t _release_timebase; + + func_t _midi_get_event_count; + func_t _midi_event_get; + func_t _midi_event_write; + func_t _midi_clear_buffer; + + func_t _set_session_callback; + func_t _session_reply; + func_t _session_event_free; + + func_t _ringbuffer_create; + func_t _ringbuffer_free; + func_t _ringbuffer_reset; + func_t _ringbuffer_read_advance; + func_t _ringbuffer_write_advance; + func_t _ringbuffer_read_space; + func_t _ringbuffer_write_space; + func_t _ringbuffer_read; + func_t _ringbuffer_write; + func_t _ringbuffer_mlock; + + func_t _client_real_time_priority; + func_t _client_max_real_time_priority; + func_t _acquire_real_time_scheduling; + func_t _drop_real_time_scheduling; + func_t _client_stop_thread; + func_t _client_kill_thread; + func_t _client_create_thread; +} _j; + +static int _status = -1; + +int have_libjack (void) { + return _status; +} + +__attribute__((constructor)) +static void init_weak_jack(void) +{ + void* lib; + int err = 0; + + memset(&_j, 0, sizeof(_j)); + +#ifdef __APPLE__ + lib = lib_open("libjack.dylib"); + if (!lib) { + lib = lib_open("/usr/local/lib/libjack.dylib"); + } +#elif (defined PLATFORM_WINDOWS) + lib = lib_open("libjack.dll"); +#else + lib = lib_open("libjack.so"); +#endif + if (!lib) { + _status = -2; + return; + } + + MAPSYM(client_open, 2) + MAPSYM(client_close, 1) + MAPSYM(get_client_name, 1) + MAPSYM(get_sample_rate, 1) + MAPSYM(get_buffer_size, 1) + MAPSYM(frames_since_cycle_start, 1) + MAPSYM(frame_time, 1) + MAPSYM(last_frame_time, 1) + MAPSYM(cpu_load, 1) + MAPSYM(is_realtime, 1) + MAPSYM(set_freewheel, 1) + MAPSYM(set_buffer_size, 1) + MAPSYM(on_shutdown, 0) + MAPSYM(on_info_shutdown, 0) + MAPSYM(set_process_callback, 1) + MAPSYM(set_freewheel_callback, 1) + MAPSYM(set_buffer_size_callback, 1) + MAPSYM(set_sample_rate_callback, 1) + MAPSYM(set_port_registration_callback, 1) + MAPSYM(set_port_connect_callback, 1) + MAPSYM(set_graph_order_callback, 1) + MAPSYM(set_xrun_callback, 1) + MAPSYM(set_latency_callback, 1) + MAPSYM(set_error_function, 1) + MAPSYM(activate, 1) + MAPSYM(deactivate, 1) + MAPSYM(recompute_total_latencies, 0) + MAPSYM(port_get_total_latency, 0) + MAPSYM(port_get_latency_range, 0) + MAPSYM(port_set_latency_range, 0) + MAPSYM(port_get_buffer, 1) + MAPSYM(port_request_monitor, 1) + MAPSYM(port_ensure_monitor, 1) + MAPSYM(port_monitoring_input, 1) + MAPSYM(port_name, 1) + MAPSYM(port_flags, 1) + MAPSYM(get_ports, 1) + MAPSYM(port_name_size, 1) + MAPSYM(port_type_size, 1) + MAPSYM(port_type_get_buffer_size, 1) + MAPSYM(port_by_name, 1) + MAPSYM(port_by_id, 1) + MAPSYM(port_register, 1) + MAPSYM(port_unregister, 1) + MAPSYM(port_type, 1) + MAPSYM(port_get_connections, 1) + MAPSYM(port_get_all_connections, 1) + MAPSYM(port_set_name, 1) + MAPSYM(port_disconnect, 1) + MAPSYM(connect, 1) + MAPSYM(disconnect, 1) + MAPSYM(free, 0) + MAPSYM(cycle_wait, 0) + MAPSYM(cycle_signal, 0) + MAPSYM(set_process_thread, 0) + MAPSYM(set_thread_init_callback, 0) + MAPSYM(get_current_transport_frame, 1) + MAPSYM(transport_locate, 1) + MAPSYM(transport_start, 1) + MAPSYM(transport_stop, 1) + MAPSYM(transport_query, 1) + MAPSYM(set_sync_callback, 1) + MAPSYM(set_timebase_callback, 1) + MAPSYM(release_timebase, 1) + MAPSYM(midi_get_event_count, 1) + MAPSYM(midi_event_get, 1) + MAPSYM(midi_event_write, 1) + MAPSYM(midi_clear_buffer, 1) + MAPSYM(set_session_callback, 0) + MAPSYM(session_reply, 0) + MAPSYM(session_event_free, 0) + MAPSYM(ringbuffer_create, 1) + MAPSYM(ringbuffer_free, 1) + MAPSYM(ringbuffer_reset, 1) + MAPSYM(ringbuffer_read_advance, 1) + MAPSYM(ringbuffer_write_advance, 1) + MAPSYM(ringbuffer_read_space, 1) + MAPSYM(ringbuffer_write_space, 1) + MAPSYM(ringbuffer_read, 1) + MAPSYM(ringbuffer_write, 1) + MAPSYM(ringbuffer_mlock, 0) + MAPSYM(client_real_time_priority, 0) + MAPSYM(client_max_real_time_priority, 0) + MAPSYM(acquire_real_time_scheduling, 0) + MAPSYM(client_create_thread, 0) + MAPSYM(drop_real_time_scheduling, 0) + MAPSYM(client_stop_thread, 0) + MAPSYM(client_kill_thread, 0) + + /* if a required symbol is not found, disable JACK completly */ + if (err) { + _j._client_open = NULL; + } + + _status = err; +} + +/******************************************************************************* + * Macros to wrap jack API + */ + +#ifndef NDEBUG +# define WJACK_WARNING(NAME) \ + fprintf(stderr, "*** WEAK-JACK: function 'jack_%s' ignored\n", "" # NAME); +#else +# define WJACK_WARNING(NAME) ; +#endif + +/* abstraction for jack_client functions */ +#define JCFUN(RTYPE, NAME, RVAL) \ + RTYPE WJACK_ ## NAME (jack_client_t *client) { \ + if (_j._ ## NAME) { \ + return ((RTYPE (*)(jack_client_t *client)) _j._ ## NAME)(client); \ + } else { \ + WJACK_WARNING(NAME) \ + return RVAL; \ + } \ + } + +/* abstraction for NOOP functions */ +#define JPFUN(RTYPE, NAME, DEF, ARGS, RVAL) \ + RTYPE WJACK_ ## NAME DEF { \ + if (_j._ ## NAME) { \ + return ((RTYPE (*)DEF) _j._ ## NAME) ARGS; \ + } else { \ + WJACK_WARNING(NAME) \ + return RVAL; \ + } \ + } + +/* abstraction for functions with return-value-pointer args */ +#define JXFUN(RTYPE, NAME, DEF, ARGS, CODE) \ + RTYPE WJACK_ ## NAME DEF { \ + if (_j._ ## NAME) { \ + return ((RTYPE (*)DEF) _j._ ## NAME) ARGS; \ + } else { \ + WJACK_WARNING(NAME) \ + CODE \ + } \ + } + +/* abstraction for void functions with return-value-pointer args */ +#define JVFUN(RTYPE, NAME, DEF, ARGS, CODE) \ + RTYPE WJACK_ ## NAME DEF { \ + if (_j._ ## NAME) { \ + ((RTYPE (*)DEF) _j._ ## NAME) ARGS; \ + } else { \ + WJACK_WARNING(NAME) \ + CODE \ + } \ + } + +/****************************************************************************** + * wrapper functions. + * + * if a function pointer is set in the static struct WeakJack _j, + * call the function, if not a dummy NOOP implementation is provided. + * + * The latter is mainly for the benefit for compile-time (warnings), + * if libjack is not found, jack_client_open() will fail and none + * of the application will never call any of the other functions. + */ + +/* */ + +/* expand ellipsis for jack-session */ +jack_client_t * WJACK_client_open2 (const char *client_name, jack_options_t options, jack_status_t *status, const char *uuid) { + if (_j._client_open) { + return ((jack_client_t* (*)(const char *, jack_options_t, jack_status_t *, ...))(_j._client_open))(client_name, options, status, uuid); + } else { + WJACK_WARNING(client_open); + if (status) *status = 0; + return NULL; + } +} + +jack_client_t * WJACK_client_open1 (const char *client_name, jack_options_t options, jack_status_t *status) { + if (_j._client_open) { + return ((jack_client_t* (*)(const char *, jack_options_t, jack_status_t *, ...))_j._client_open)(client_name, options, status); + } else { + WJACK_WARNING(client_open); + if (status) *status = 0; + return NULL; + } +} + +JCFUN(int, client_close, 0) +JCFUN(char*, get_client_name, NULL) +JVFUN(void, on_shutdown, (jack_client_t *c, JackShutdownCallback s, void *a), (c,s,a),) +JVFUN(void, on_info_shutdown, (jack_client_t *c, JackInfoShutdownCallback s, void *a), (c,s,a),) + +JPFUN(int, set_process_callback, (jack_client_t *c, JackProcessCallback p, void *a), (c,p,a), -1) +JPFUN(int, set_freewheel_callback, (jack_client_t *c, JackFreewheelCallback p, void *a), (c,p,a), -1) +JPFUN(int, set_buffer_size_callback, (jack_client_t *c, JackBufferSizeCallback p, void *a), (c,p,a), -1) +JPFUN(int, set_sample_rate_callback, (jack_client_t *c, JackSampleRateCallback p, void *a), (c,p,a), -1) +JPFUN(int, set_port_registration_callback, (jack_client_t *c, JackPortRegistrationCallback p, void *a), (c,p,a), -1) +JPFUN(int, set_port_connect_callback, (jack_client_t *c, JackPortConnectCallback p, void *a), (c,p,a), -1) +JPFUN(int, set_graph_order_callback, (jack_client_t *c, JackGraphOrderCallback g, void *a), (c,g,a), -1) +JPFUN(int, set_xrun_callback, (jack_client_t *c, JackXRunCallback g, void *a), (c,g,a), -1) +JPFUN(int, set_latency_callback, (jack_client_t *c, JackLatencyCallback g, void *a), (c,g,a), -1) +JVFUN(void, set_error_function, (void (*f)(const char *)), (f),) + +JCFUN(int, activate, -1) +JCFUN(int, deactivate, -1) + +JCFUN(jack_nframes_t, get_sample_rate, 0) +JCFUN(jack_nframes_t, get_buffer_size, 0) +JPFUN(jack_nframes_t, frames_since_cycle_start, (const jack_client_t *c), (c), 0) +JPFUN(jack_nframes_t, frame_time, (const jack_client_t *c), (c), 0) +JPFUN(jack_nframes_t, last_frame_time, (const jack_client_t *c), (c), 0) +JCFUN(float, cpu_load, 0) +JCFUN(int, is_realtime, 0) + +JPFUN(int, set_freewheel, (jack_client_t *c, int o), (c,o), 0) +JPFUN(int, set_buffer_size, (jack_client_t *c, jack_nframes_t b), (c,b), 0) + +JCFUN(int, recompute_total_latencies, 0) +JPFUN(jack_nframes_t, port_get_total_latency, (jack_client_t *c, jack_port_t *p), (c,p), 0) +JVFUN(void, port_get_latency_range, (jack_port_t *p, jack_latency_callback_mode_t m, jack_latency_range_t *r), (p,m,r), if (r) {r->min = r->max = 0;}) +JVFUN(void, port_set_latency_range, (jack_port_t *p, jack_latency_callback_mode_t m, jack_latency_range_t *r), (p,m,r),) +JPFUN(void*, port_get_buffer, (jack_port_t *p, jack_nframes_t n), (p,n), NULL) +JPFUN(int, port_request_monitor, (jack_port_t *p, int o), (p,o), 0) +JPFUN(int, port_ensure_monitor, (jack_port_t *p, int o), (p,o), 0) +JPFUN(int, port_monitoring_input, (jack_port_t *p), (p), 0) + +JPFUN(const char*, port_name, (const jack_port_t *p), (p), NULL) +JPFUN(int, port_flags, (const jack_port_t *p), (p), 0) +JPFUN(const char**, get_ports,(jack_client_t *c, const char *p, const char *t, unsigned long f), (c,p,t,f), NULL) +JPFUN(int, port_name_size, (void), (), 0) +JPFUN(int, port_type_size, (void), (), 0) +JPFUN(size_t, port_type_get_buffer_size, (jack_client_t *c, const char *t), (c,t), 0) +JPFUN(jack_port_t*, port_by_name, (jack_client_t *c, const char *n), (c,n), NULL) +JPFUN(jack_port_t*, port_by_id, (jack_client_t *c, jack_port_id_t i), (c,i), NULL) +JPFUN(jack_port_t*, port_register, (jack_client_t *c, const char *n, const char *t, unsigned long f, unsigned long b), (c,n,t,f,b), NULL) +JPFUN(int, port_unregister, (jack_client_t *c, jack_port_t *p), (c,p), 0) +JPFUN(const char *, port_type, (const jack_port_t *p), (p), 0) +JPFUN(const char **, port_get_connections, (const jack_port_t *p), (p), 0) +JPFUN(const char **, port_get_all_connections, (const jack_client_t *c, const jack_port_t *p), (c,p), 0) +JPFUN(int, port_set_name, (jack_port_t *p, const char *n), (p,n), 0) +JPFUN(int, port_disconnect, (jack_client_t *c, jack_port_t *p), (c,p), 0) +JPFUN(int, connect, (jack_client_t *c, const char *s, const char *d), (c,s,d), -1) +JPFUN(int, disconnect, (jack_client_t *c, const char *s, const char *d), (c,s,d), -1) +JVFUN(void, free, (void *p), (p), free(p);) +JCFUN(jack_nframes_t, cycle_wait, 0) +JVFUN(void, cycle_signal, (jack_client_t *c, int s), (c,s),) +JPFUN(int, set_process_thread, (jack_client_t *c, JackThreadCallback p, void *a), (c,p,a), -1) +JPFUN(int, set_thread_init_callback, (jack_client_t *c, JackThreadInitCallback p, void *a), (c,p,a), -1) + +JPFUN(int, transport_locate, (jack_client_t *c, jack_nframes_t f), (c,f), 0) +JVFUN(void, transport_start, (jack_client_t *c), (c),) +JVFUN(void, transport_stop, (jack_client_t *c), (c),) +JPFUN(jack_nframes_t, get_current_transport_frame, (const jack_client_t *c), (c), 0) +JXFUN(jack_transport_state_t, transport_query, (const jack_client_t *c, jack_position_t *p), (c,p), memset(p, 0, sizeof(jack_position_t)); return 0;) +JPFUN(int, set_sync_callback, (jack_client_t *c, JackSyncCallback p, void *a), (c,p,a), -1) +JPFUN(int, set_timebase_callback, (jack_client_t *c, int l, JackTimebaseCallback p, void *a), (c,l,p,a), -1) +JCFUN(int, release_timebase, 0) + +/* */ +JPFUN(uint32_t, midi_get_event_count, (void* p), (p), 0) +JPFUN(int, midi_event_get, (jack_midi_event_t *e, void *p, uint32_t i), (e,p,i), -1) +JPFUN(int, midi_event_write, (void *b, jack_nframes_t t, const jack_midi_data_t *d, size_t s), (b,t,d,s), -1) +JVFUN(void, midi_clear_buffer, (void *b), (b),) + +/* */ +JPFUN(int, set_session_callback, (jack_client_t *c, JackSessionCallback s, void *a), (c,s,a), -1) +JPFUN(int, session_reply, (jack_client_t *c, jack_session_event_t *e), (c,e), -1) +JVFUN(void, session_event_free, (jack_session_event_t *e), (e), ) + +/* */ +JPFUN(jack_ringbuffer_t *, ringbuffer_create, (size_t s), (s), NULL) +JVFUN(void, ringbuffer_free, (jack_ringbuffer_t *rb), (rb), ) +JVFUN(void, ringbuffer_reset, (jack_ringbuffer_t *rb), (rb), ) +JVFUN(void, ringbuffer_read_advance, (jack_ringbuffer_t *rb, size_t c), (rb,c), ) +JVFUN(void, ringbuffer_write_advance, (jack_ringbuffer_t *rb, size_t c), (rb,c), ) +JPFUN(size_t, ringbuffer_read_space, (const jack_ringbuffer_t *rb), (rb), 0) +JPFUN(size_t, ringbuffer_write_space, (const jack_ringbuffer_t *rb), (rb), 0) +JPFUN(size_t, ringbuffer_read, (jack_ringbuffer_t *rb, char *d, size_t c), (rb,d,c), 0) +JPFUN(size_t, ringbuffer_write, (jack_ringbuffer_t *rb, const char *s, size_t c), (rb,s,c), 0) +JPFUN(int, ringbuffer_mlock, (jack_ringbuffer_t *rb), (rb), 0) + +/* */ +JCFUN(int, client_real_time_priority, 0) +JCFUN(int, client_max_real_time_priority, 0) +JPFUN(int, acquire_real_time_scheduling, (jack_native_thread_t t, int p), (t,p), 0) +JPFUN(int, drop_real_time_scheduling, (jack_native_thread_t t), (t), 0) +JPFUN(int, client_stop_thread, (jack_client_t* c, jack_native_thread_t t), (c,t), 0) +JPFUN(int, client_kill_thread, (jack_client_t* c, jack_native_thread_t t), (c,t), 0) +JPFUN(int, client_create_thread, \ + (jack_client_t* c, jack_native_thread_t *t, int p, int r, void *(*f)(void*), void *a), (c,t,p,r,f,a), 0) + +#endif diff --git a/libs/backends/jack/weak_libjack.h b/libs/backends/jack/weak_libjack.h new file mode 100644 index 0000000000..3985014dfb --- /dev/null +++ b/libs/backends/jack/weak_libjack.h @@ -0,0 +1,188 @@ +/* runtime/weak dynamic JACK linking + * + * (C) 2014 Robin Gareus + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#ifndef _WEAK_JACK_H +#define _WEAK_JACK_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** check if libjack is available + * + * return 0 if libjack is dynamically linked of was + * successfully dl-opened. Otherwise: + * + * -1: library was not initialized + * -2: libjack was not found + * > 0 bitwise flags: + * 1: a required function was not found in libjack + * 2: jack_client_open was not found in libjack + */ +int have_libjack(void); + +#ifdef __cplusplus +} +#endif + +#ifdef USE_WEAK_JACK + +/* */ +#define jack_client_open WJACK_client_openX +#define jack_client_close WJACK_client_close +#define jack_get_client_name WJACK_get_client_name +#define jack_get_sample_rate WJACK_get_sample_rate +#define jack_get_buffer_size WJACK_get_buffer_size +#define jack_frames_since_cycle_start WJACK_frames_since_cycle_start +#define jack_frame_time WJACK_frame_time +#define jack_last_frame_time WJACK_last_frame_time +#define jack_cpu_load WJACK_cpu_load +#define jack_is_realtime WJACK_is_realtime + +#define jack_set_freewheel WJACK_set_freewheel +#define jack_set_buffer_size WJACK_set_buffer_size + +#define jack_on_shutdown WJACK_on_shutdown +#define jack_on_info_shutdown WJACK_on_info_shutdown +#define jack_set_process_callback WJACK_set_process_callback +#define jack_set_freewheel_callback WJACK_set_freewheel_callback +#define jack_set_buffer_size_callback WJACK_set_buffer_size_callback +#define jack_set_sample_rate_callback WJACK_set_sample_rate_callback +#define jack_set_port_registration_callback WJACK_set_port_registration_callback +#define jack_set_port_connect_callback WJACK_set_port_connect_callback +#define jack_set_graph_order_callback WJACK_set_graph_order_callback +#define jack_set_xrun_callback WJACK_set_xrun_callback +#define jack_set_latency_callback WJACK_set_latency_callback +#define jack_set_error_function WJACK_set_error_function + +#define jack_activate WJACK_activate +#define jack_deactivate WJACK_deactivate + +#define jack_recompute_total_latencies WJACK_recompute_total_latencies +#define jack_port_get_total_latency WJACK_port_get_total_latency +#define jack_port_get_latency_range WJACK_port_get_latency_range +#define jack_port_set_latency_range WJACK_port_set_latency_range +#define jack_port_get_buffer WJACK_port_get_buffer +#define jack_port_request_monitor WJACK_port_request_monitor +#define jack_port_ensure_monitor WJACK_port_ensure_monitor +#define jack_port_monitoring_input WJACK_port_monitoring_input + +#define jack_port_name WJACK_port_name +#define jack_port_flags WJACK_port_flags +#define jack_get_ports WJACK_get_ports +#define jack_port_name_size WJACK_port_name_size +#define jack_port_type_size WJACK_port_type_size +#define jack_port_type_get_buffer_size WJACK_port_type_get_buffer_size +#define jack_port_by_name WJACK_port_by_name +#define jack_port_by_id WJACK_port_by_id +#define jack_port_set_name WJACK_port_set_name +#define jack_port_disconnect WJACK_port_disconnect +#define jack_port_register WJACK_port_register +#define jack_port_unregister WJACK_port_unregister +#define jack_port_type WJACK_port_type +#define jack_port_get_connections WJACK_port_get_connections +#define jack_port_get_all_connections WJACK_port_get_all_connections +#define jack_connect WJACK_connect +#define jack_disconnect WJACK_disconnect +#define jack_free WJACK_free + +#define jack_cycle_wait WJACK_cycle_wait +#define jack_cycle_signal WJACK_cycle_signal +#define jack_set_process_thread WJACK_set_process_thread +#define jack_set_thread_init_callback WJACK_set_thread_init_callback + +/* */ +#define jack_get_current_transport_frame WJACK_get_current_transport_frame +#define jack_transport_locate WJACK_transport_locate +#define jack_transport_start WJACK_transport_start +#define jack_transport_stop WJACK_transport_stop +#define jack_transport_query WJACK_transport_query +#define jack_set_sync_callback WJACK_set_sync_callback +#define jack_set_timebase_callback WJACK_set_timebase_callback +#define jack_release_timebase WJACK_release_timebase + +/* */ +#define jack_midi_get_event_count WJACK_midi_get_event_count +#define jack_midi_event_get WJACK_midi_event_get +#define jack_midi_event_write WJACK_midi_event_write +#define jack_midi_clear_buffer WJACK_midi_clear_buffer + +/* */ +#define jack_set_session_callback WJACK_set_session_callback +#define jack_session_reply WJACK_session_reply +#define jack_session_event_free WJACK_session_event_free + +/* */ +#define jack_ringbuffer_create WJACK_ringbuffer_create +#define jack_ringbuffer_free WJACK_ringbuffer_free +#define jack_ringbuffer_reset WJACK_ringbuffer_reset +#define jack_ringbuffer_read_advance WJACK_ringbuffer_read_advance +#define jack_ringbuffer_write_advance WJACK_ringbuffer_write_advance +#define jack_ringbuffer_read_space WJACK_ringbuffer_read_space +#define jack_ringbuffer_write_space WJACK_ringbuffer_write_space +#define jack_ringbuffer_read WJACK_ringbuffer_read +#define jack_ringbuffer_write WJACK_ringbuffer_write +#define jack_ringbuffer_mlock WJACK_ringbuffer_mlock + +/* */ +#define jack_client_real_time_priority WJACK_client_real_time_priority +#define jack_client_max_real_time_priority WJACK_client_max_real_time_priority +#define jack_acquire_real_time_scheduling WJACK_acquire_real_time_scheduling +#define jack_client_create_thread WJACK_client_create_thread +#define jack_drop_real_time_scheduling WJACK_drop_real_time_scheduling +#define jack_client_stop_thread WJACK_client_stop_thread +#define jack_client_kill_thread WJACK_client_kill_thread + +/* var-args hack */ +#define jack_client_open1 WJACK_client_open1 +#define jack_client_open2 WJACK_client_open2 +#include + +#ifdef __cplusplus +extern "C" +{ +#endif +jack_client_t * WJACK_client_open1 ( + const char *client_name, + jack_options_t options, jack_status_t *status); + +jack_client_t * WJACK_client_open2 ( + const char *client_name, + jack_options_t options, jack_status_t *status, const char *uuid); + +#ifdef __cplusplus +} +#endif + +#else + +/* var-args hack */ +#define jack_client_open1 jack_client_open +#define jack_client_open2 jack_client_open + +#endif // USE_WEAK_JACK + +#include +#include +#include +#include +#include +#include + +#endif // _WEAK_JACK_H diff --git a/libs/backends/jack/wscript b/libs/backends/jack/wscript index b8138d2473..edb9cb1850 100644 --- a/libs/backends/jack/wscript +++ b/libs/backends/jack/wscript @@ -32,6 +32,17 @@ def configure(conf): atleast_version='19') autowaf.configure(conf) + if Options.options.libjack_link == 'auto': + if Options.options.dist_target == 'mingw' or sys.platform == 'darwin': + conf.env['libjack_link'] = "weak" + else: + conf.env['libjack_link'] = "link" + elif Options.options.libjack_link == 'weak': + conf.env['libjack_link'] = "weak" + else: + conf.env['libjack_link'] = "link" + + def build(bld): obj = bld(features = 'cxx cxxshlib') obj.source = [ @@ -41,20 +52,27 @@ def build(bld): 'jack_portengine.cc', 'jack_utils.cc', 'jack_session.cc', + 'weak_libjack.c', ] obj.includes = ['.'] obj.name = 'jack_audiobackend' obj.target = 'jack_audiobackend' - if (bld.env['build_target'] == 'mingw'): - obj.uselib = [ 'JACK', 'PORTAUDIO' ] - else: - obj.uselib = [ 'JACK' ] - obj.vnum = JACKBACKEND_VERSION - obj.use = 'libardour libpbd ardouralsautil' - obj.install_path = os.path.join(bld.env['LIBDIR'], 'backends') obj.defines = ['PACKAGE="' + I18N_PACKAGE + '"', 'ARDOURBACKEND_DLL_EXPORTS' ] + obj.use = 'libardour libpbd ardouralsautil' + obj.install_path = os.path.join(bld.env['LIBDIR'], 'backends') + + if (bld.env['build_target'] == 'mingw'): + obj.uselib = [ 'PORTAUDIO' ] + else: + obj.uselib = [ ] + obj.vnum = JACKBACKEND_VERSION + + if bld.env['libjack_link'] == 'link': + obj.uselib += [ 'JACK' ] + else: + obj.defines += [ 'USE_WEAK_JACK' ] # # device discovery code in the jack backend needs ALSA diff --git a/wscript b/wscript index d46a70e75d..506f4a589c 100644 --- a/wscript +++ b/wscript @@ -461,6 +461,8 @@ def options(opt): help='Build a version suitable for distribution as a zero-cost binary') opt.add_option('--gprofile', action='store_true', default=False, dest='gprofile', help='Compile for use with gprofile') + opt.add_option('--libjack', type='string', default="auto", dest='libjack_link', + help='libjack link mode [auto|link|weak]') opt.add_option('--internal-shared-libs', action='store_true', default=True, dest='internal_shared_libs', help='Build internal libs as shared libraries') opt.add_option('--internal-static-libs', action='store_false', dest='internal_shared_libs', @@ -838,6 +840,7 @@ const char* const ardour_config_info = "\\n\\ write_config_text('FLAC', conf.is_defined('HAVE_FLAC')) write_config_text('FPU optimization', opts.fpu_optimization) write_config_text('Freedesktop files', opts.freedesktop) + write_config_text('Libjack linking', conf.env['libjack_link']) write_config_text('LV2 UI embedding', conf.is_defined('HAVE_SUIL')) write_config_text('LV2 support', conf.is_defined('LV2_SUPPORT')) write_config_text('LXVST support', conf.is_defined('LXVST_SUPPORT'))