Use weak loading of libjack (#3887)

This commit is contained in:
Tres Finocchiaro
2017-10-16 14:46:25 -04:00
committed by GitHub
parent 221d0cb355
commit c051e9bf34
9 changed files with 694 additions and 2 deletions

View File

@@ -51,6 +51,7 @@ OPTION(WANT_CAPS "Include C* Audio Plugin Suite (LADSPA plugins)" ON)
OPTION(WANT_CARLA "Include Carla plugin" ON)
OPTION(WANT_CMT "Include Computer Music Toolkit LADSPA plugins" ON)
OPTION(WANT_JACK "Include JACK (Jack Audio Connection Kit) support" ON)
OPTION(WANT_WEAKJACK "Loosely link JACK libraries" ON)
OPTION(WANT_MP3LAME "Include MP3/Lame support" ON)
OPTION(WANT_OGGVORBIS "Include OGG/Vorbis support" ON)
OPTION(WANT_PULSEAUDIO "Include PulseAudio support" ON)
@@ -364,8 +365,16 @@ ENDIF(NOT LMMS_HAVE_ALSA)
IF(WANT_JACK)
PKG_CHECK_MODULES(JACK jack>=0.77)
IF(JACK_FOUND)
IF(WANT_WEAKJACK)
SET(LMMS_HAVE_WEAKJACK TRUE)
SET(STATUS_JACK "OK (weak linking enabled)")
SET(JACK_INCLUDE_DIRS "")
# use dlsym instead
SET(JACK_LIBRARIES "dl")
ELSE()
SET(STATUS_JACK "OK")
ENDIF()
SET(LMMS_HAVE_JACK TRUE)
SET(STATUS_JACK "OK")
ELSE(JACK_FOUND)
SET(STATUS_JACK "not found, please install libjack0.100.0-dev (or similar) "
"if you require JACK support")

View File

@@ -28,7 +28,11 @@
#include "lmmsconfig.h"
#ifdef LMMS_HAVE_JACK
#ifndef LMMS_HAVE_WEAKJACK
#include <jack/jack.h>
#else
#include "AudioWeakJack.h"
#endif
#include <QtCore/QVector>
#include <QtCore/QList>

159
include/AudioWeakJack.def Normal file
View File

@@ -0,0 +1,159 @@
/* macro-absraction of the JACK API
*
* see weak_libjack.c for details, in general arguments are:
*
* [required], [return type], [name], [arguments], [code or return value]
*
* This file is included multiple times with different macro definitions
* do not add header guards.
* see https://en.wikibooks.org/wiki/C_Programming/Preprocessor#X-Macros
*/
#ifdef USE_WEAK_JACK
/* <jack/jack.h> */
JCFUN(1, int, client_close, 0)
JCFUN(1, char*, get_client_name, NULL)
JVFUN(0, on_shutdown, (jack_client_t *c, JackShutdownCallback s, void *a), (c,s,a),)
JVFUN(0, on_info_shutdown, (jack_client_t *c, JackInfoShutdownCallback s, void *a), (c,s,a),)
JPFUN(1, int, set_process_callback, (jack_client_t *c, JackProcessCallback p, void *a), (c,p,a), -1)
JPFUN(1, int, set_freewheel_callback, (jack_client_t *c, JackFreewheelCallback p, void *a), (c,p,a), -1)
JPFUN(1, int, set_buffer_size_callback, (jack_client_t *c, JackBufferSizeCallback p, void *a), (c,p,a), -1)
JPFUN(1, int, set_sample_rate_callback, (jack_client_t *c, JackSampleRateCallback p, void *a), (c,p,a), -1)
JPFUN(1, int, set_port_registration_callback, (jack_client_t *c, JackPortRegistrationCallback p, void *a), (c,p,a), -1)
JPFUN(1, int, set_port_connect_callback, (jack_client_t *c, JackPortConnectCallback p, void *a), (c,p,a), -1)
JPFUN(1, int, set_graph_order_callback, (jack_client_t *c, JackGraphOrderCallback g, void *a), (c,g,a), -1)
JPFUN(1, int, set_xrun_callback, (jack_client_t *c, JackXRunCallback g, void *a), (c,g,a), -1)
JPFUN(1, int, set_latency_callback, (jack_client_t *c, JackLatencyCallback g, void *a), (c,g,a), -1)
JVFUN(1, set_error_function, (void (*f)(const char *)), (f),)
JVFUN(1, set_info_function, (void (*f)(const char *)), (f),)
JCFUN(1, int, activate, -1)
JCFUN(1, int, deactivate, -1)
JPFUN(1, int, client_name_size, (), (), 32)
JCFUN(1, jack_nframes_t, get_sample_rate, 0)
JCFUN(1, jack_nframes_t, get_buffer_size, 0)
JPFUN(1, jack_nframes_t, frames_since_cycle_start, (const jack_client_t *c), (c), 0)
JPFUN(1, jack_nframes_t, frame_time, (const jack_client_t *c), (c), 0)
JPFUN(1, jack_nframes_t, last_frame_time, (const jack_client_t *c), (c), 0)
JPFUN(1, jack_time_t, get_time, (void), (), 0)
JCFUN(1, float, cpu_load, 0)
JCFUN(1, int, is_realtime, 0)
JPFUN(1, int, set_freewheel, (jack_client_t *c, int o), (c,o), 0)
JPFUN(1, int, set_buffer_size, (jack_client_t *c, jack_nframes_t b), (c,b), 0)
JCFUN(0, int, recompute_total_latencies, 0)
JPFUN(0, jack_nframes_t, port_get_total_latency, (jack_client_t *c, jack_port_t *p), (c,p), 0)
JVFUN(0, 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(0, port_set_latency_range, (jack_port_t *p, jack_latency_callback_mode_t m, jack_latency_range_t *r), (p,m,r),)
JPFUN(1, void*, port_get_buffer, (jack_port_t *p, jack_nframes_t n), (p,n), NULL)
JPFUN(1, int, port_request_monitor, (jack_port_t *p, int o), (p,o), 0)
JPFUN(1, int, port_ensure_monitor, (jack_port_t *p, int o), (p,o), 0)
JPFUN(1, int, port_monitoring_input, (jack_port_t *p), (p), 0)
JPFUN(1, const char*, port_name, (const jack_port_t *p), (p), NULL)
JPFUN(1, const char*, port_short_name, (const jack_port_t *p), (p), NULL)
JPFUN(1, int, port_flags, (const jack_port_t *p), (p), 0)
JPFUN(1, const char**, get_ports,(jack_client_t *c, const char *p, const char *t, unsigned long f), (c,p,t,f), NULL)
JPFUN(1, int, port_name_size, (void), (), 0)
JPFUN(1, int, port_type_size, (void), (), 0)
JPFUN(1, size_t, port_type_get_buffer_size, (jack_client_t *c, const char *t), (c,t), 0)
JPFUN(1, jack_port_t*, port_by_name, (jack_client_t *c, const char *n), (c,n), NULL)
JPFUN(1, jack_port_t*, port_by_id, (jack_client_t *c, jack_port_id_t i), (c,i), NULL)
JPFUN(1, 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(1, int, port_unregister, (jack_client_t *c, jack_port_t *p), (c,p), 0)
JPFUN(1, const char *, port_type, (const jack_port_t *p), (p), 0)
JPFUN(1, const char **, port_get_connections, (const jack_port_t *p), (p), 0)
JPFUN(1, const char **, port_get_all_connections, (const jack_client_t *c, const jack_port_t *p), (c,p), 0)
JPFUN(1, int, port_set_name, (jack_port_t *p, const char *n), (p,n), -1)
JXFUN(0, int, port_rename, (jack_client_t *c, jack_port_t *p, const char *n), (c,p,n), return jack_port_set_name (p,n);)
JPFUN(1, int, port_get_aliases, (const jack_port_t *port, char* const aliases[2]), (port,aliases), 0)
JPFUN(1, int, port_disconnect, (jack_client_t *c, jack_port_t *p), (c,p), 0)
JPFUN(1, int, connect, (jack_client_t *c, const char *s, const char *d), (c,s,d), -1)
JPFUN(1, int, disconnect, (jack_client_t *c, const char *s, const char *d), (c,s,d), -1)
JVFUN(0, free, (void *p), (p), free(p);)
JCFUN(1, jack_nframes_t, cycle_wait, 0)
JVFUN(1, cycle_signal, (jack_client_t *c, int s), (c,s),)
JPFUN(1, int, set_process_thread, (jack_client_t *c, JackThreadCallback p, void *a), (c,p,a), -1)
JPFUN(1, int, set_thread_init_callback, (jack_client_t *c, JackThreadInitCallback p, void *a), (c,p,a), -1)
JPFUN(1, int, transport_locate, (jack_client_t *c, jack_nframes_t f), (c,f), 0)
JVFUN(1, transport_start, (jack_client_t *c), (c),)
JVFUN(1, transport_stop, (jack_client_t *c), (c),)
JPFUN(1, jack_nframes_t, get_current_transport_frame, (const jack_client_t *c), (c), 0)
JXFUN(1, 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 JackTransportStopped;)
JPFUN(1, int, set_sync_callback, (jack_client_t *c, JackSyncCallback p, void *a), (c,p,a), -1)
JPFUN(1, int, set_timebase_callback, (jack_client_t *c, int l, JackTimebaseCallback p, void *a), (c,l,p,a), -1)
JCFUN(1, int, release_timebase, 0)
/* <jack/midiport.h> */
JPFUN(1, uint32_t, midi_get_event_count, (void* p), (p), 0)
JPFUN(1, int, midi_event_get, (jack_midi_event_t *e, void *p, uint32_t i), (e,p,i), -1)
JPFUN(1, 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(1, midi_clear_buffer, (void *b), (b),)
/* <jack/session.h> */
JPFUN(0, int, set_session_callback, (jack_client_t *c, JackSessionCallback s, void *a), (c,s,a), -1)
JPFUN(0, int, session_reply, (jack_client_t *c, jack_session_event_t *e), (c,e), -1)
JVFUN(0, session_event_free, (jack_session_event_t *e), (e), )
/* <jack/ringbuffer.h> */
JPFUN(1, jack_ringbuffer_t *, ringbuffer_create, (size_t s), (s), NULL)
JVFUN(1, ringbuffer_free, (jack_ringbuffer_t *rb), (rb), )
JVFUN(1, ringbuffer_reset, (jack_ringbuffer_t *rb), (rb), )
JVFUN(1, ringbuffer_read_advance, (jack_ringbuffer_t *rb, size_t c), (rb,c), )
JVFUN(1, ringbuffer_write_advance, (jack_ringbuffer_t *rb, size_t c), (rb,c), )
JPFUN(1, size_t, ringbuffer_read_space, (const jack_ringbuffer_t *rb), (rb), 0)
JPFUN(1, size_t, ringbuffer_write_space, (const jack_ringbuffer_t *rb), (rb), 0)
JPFUN(1, size_t, ringbuffer_read, (jack_ringbuffer_t *rb, char *d, size_t c), (rb,d,c), 0)
JPFUN(1, size_t, ringbuffer_write, (jack_ringbuffer_t *rb, const char *s, size_t c), (rb,s,c), 0)
JPFUN(0, int, ringbuffer_mlock, (jack_ringbuffer_t *rb), (rb), 0)
JVFUN(0, ringbuffer_get_read_vector, (const jack_ringbuffer_t *rb, jack_ringbuffer_data_t *v), (rb,v), if (v) {v->buf=NULL; v->len=0;} )
JVFUN(0, ringbuffer_get_write_vector, (const jack_ringbuffer_t *rb, jack_ringbuffer_data_t *v), (rb,v), if (v) {v->buf=NULL; v->len=0;} )
JPFUN(0, size_t, ringbuffer_peek, (jack_ringbuffer_t *rb, char *d, size_t c), (rb,d,c), 0)
/* <jack/thread.h> */
JCFUN(0, int, client_real_time_priority, 0)
JCFUN(0, int, client_max_real_time_priority, 0)
JPFUN(0, int, acquire_real_time_scheduling, (jack_native_thread_t t, int p), (t,p), 0)
JPFUN(0, int, drop_real_time_scheduling, (jack_native_thread_t t), (t), 0)
JPFUN(0, int, client_stop_thread, (jack_client_t* c, jack_native_thread_t t), (c,t), 0)
JPFUN(0, int, client_kill_thread, (jack_client_t* c, jack_native_thread_t t), (c,t), 0)
#ifndef _WIN32
JVFUN(0, set_thread_creator, (jack_thread_creator_t c), (c),)
#endif
JPFUN(1, 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)
#ifndef NO_JACK_METADATA
/* <jack/uuid.h> - TODO*/
/* <jack/jack.h> */
JPFUN(0, char *, get_uuid_for_client_name, (jack_client_t* c, const char* n), (c,n), NULL)
JPFUN(0, char *, get_client_name_by_uuid, (jack_client_t* c, const char* u), (c,u), NULL)
JPFUN(0, jack_uuid_t, port_uuid, (const jack_port_t *p), (p), 0)
/* <jack/metadata.h> */
JPFUN(0, int, set_property, (jack_client_t* c, jack_uuid_t s, const char* k, const char* v, const char* t), (c,s,k,v,t), -1)
JXFUN(0, int, get_property, (jack_uuid_t s, const char* k, char** v, char** t), (s,k,v,t), if (v) *v=NULL; if (t) *t=NULL; return -1;)
JVFUN(0, free_description, (jack_description_t* d, int f), (d,f),)
JXFUN(0, int, get_properties, (jack_uuid_t s, jack_description_t* d), (s,d), if (d) {d->properties = NULL; d->property_cnt = 0;} return -1;)
JXFUN(0, int, get_all_properties, (jack_description_t** d), (d), if (d) *d=NULL; return -1;)
JPFUN(0, int, remove_property, (jack_client_t* c, jack_uuid_t s, const char* k), (c,s,k), -1)
JPFUN(0, int, remove_properties, (jack_client_t* c, jack_uuid_t s), (c,s), -1)
JPFUN(0, int, remove_all_properties, (jack_client_t* c), (c), -1)
JPFUN(0, int, set_property_change_callback, (jack_client_t *c, JackPropertyChangeCallback s, void *a), (c,s,a), -1)
#endif
/* <jack/statistics.h> */
JCFUN(1, float, get_max_delayed_usecs, 0.0)
JCFUN(1, float, get_xrun_delayed_usecs, 0.0)
JVFUN(0, reset_max_delayed_usecs, (jack_client_t *c), (c),)
#endif // end USE_WEAK_JACK

237
include/AudioWeakJack.h Normal file
View File

@@ -0,0 +1,237 @@
/* runtime/weak dynamic JACK linking
*
* (C) 2014 Robin Gareus <robin@gareus.org>
*
* The wrapped jack API itself is
* (C) 2001 Paul Davis
* (C) 2004 Jack O'Quin
*
* 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
// LMMS uses LMMS_HAVE_WEAKJACK instead
#ifndef USE_WEAK_JACK
#define USE_WEAK_JACK
#endif
// LMMS doesn't use metadata.h
#ifndef NO_JACK_METADATA
#define NO_JACK_METADATA
#endif
#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
/* <jack/jack.h> */
#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_get_time WJACK_get_time
#define jack_cpu_load WJACK_cpu_load
#define jack_is_realtime WJACK_is_realtime
#define jack_client_name_size WJACK_client_name_size
#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_set_info_function WJACK_set_info_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_short_name WJACK_port_short_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_get_aliases WJACK_port_get_aliases
#define jack_port_rename WJACK_port_rename
#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
/* <jack/transport.h> */
#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
/* <jack/midiport.h> */
#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
/* <jack/session.h> */
#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
/* <jack/ringbuffer.h> */
#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_ringbuffer_get_read_vector WJACK_ringbuffer_get_read_vector
#define jack_ringbuffer_get_write_vector WJACK_ringbuffer_get_write_vector
#define jack_ringbuffer_peek WJACK_ringbuffer_peek
/* <jack/thread.h> */
#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
#define jack_set_thread_creator WJACK_set_thread_creator
#define jack_client_open WJACK_client_client_openXXX
#ifndef NO_JACK_METADATA
/* <jack/metadata.h> */
#define jack_get_uuid_for_client_name WJACK_get_uuid_for_client_name
#define jack_get_client_name_by_uuid WJACK_get_client_name_by_uuid
#define jack_port_uuid WJACK_port_uuid
#define jack_set_property WJACK_set_property
#define jack_get_property WJACK_get_property
#define jack_free_description WJACK_free_description
#define jack_get_properties WJACK_get_properties
#define jack_get_all_properties WJACK_get_all_properties
#define jack_remove_property WJACK_remove_property
#define jack_remove_properties WJACK_remove_properties
#define jack_remove_all_properties WJACK_remove_all_properties
#define jack_set_property_change_callback WJACK_set_property_change_callback
#endif
/* <jack/statistics.h> */
#define jack_get_max_delayed_usecs WJACK_get_max_delayed_usecs
#define jack_get_xrun_delayed_usecs WJACK_get_xrun_delayed_usecs
#define jack_reset_max_delayed_usecs WJACK_reset_max_delayed_usecs
#endif // end USE_WEAK_JACK
#include <jack/jack.h>
#include <jack/transport.h>
#include <jack/ringbuffer.h>
#include <jack/midiport.h>
#include <jack/session.h>
#include <jack/thread.h>
#ifndef NO_JACK_METADATA
#include <jack/metadata.h>
#endif
#ifdef USE_WEAK_JACK
#undef jack_client_open
/* var-args hack */
#ifdef __cplusplus
extern "C" {
#endif
void (* WJACK_get_client_open (void)) (void);
jack_client_t * WJACK_no_client_open (const char *client_name, jack_options_t options, jack_status_t *status, ...);
#ifdef __cplusplus
}
#endif
#define jack_client_open(...) \
( \
(WJACK_get_client_open() != NULL) \
? ((jack_client_t* (*)(const char *, jack_options_t, jack_status_t *, ...))(WJACK_get_client_open()))(__VA_ARGS__) \
: WJACK_no_client_open(__VA_ARGS__) \
)
#endif // end USE_WEAK_JACK
#endif // _WEAK_JACK_H

View File

@@ -28,8 +28,12 @@
#include "lmmsconfig.h"
#ifdef LMMS_HAVE_JACK
#ifndef LMMS_HAVE_WEAKJACK
#include <jack/jack.h>
#include <jack/midiport.h>
#else
#include "AudioWeakJack.h"
#endif
#include <QtCore/QThread>
#include <QMutex>

View File

@@ -8,7 +8,7 @@ SET(CMAKE_AUTOMOC ON)
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
# Enable C++11
ADD_DEFINITIONS(-std=c++0x)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
IF(LMMS_BUILD_APPLE)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")

View File

@@ -1,3 +1,7 @@
IF(LMMS_HAVE_WEAKJACK)
set(WEAKJACK core/audio/AudioWeakJack.c)
ENDIF()
set(LMMS_SRCS
${LMMS_SRCS}
core/AutomatableModel.cpp
@@ -72,6 +76,7 @@ set(LMMS_SRCS
core/audio/AudioFileMP3.cpp
core/audio/AudioFileOgg.cpp
core/audio/AudioFileWave.cpp
${WEAKJACK}
core/audio/AudioJack.cpp
core/audio/AudioOss.cpp
core/audio/AudioSndio.cpp

View File

@@ -0,0 +1,273 @@
/* runtime/weak dynamic JACK linking
*
* (C) 2014 Robin Gareus <robin@gareus.org>
*
* 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 "AudioWeakJack.h"
#ifndef USE_WEAK_JACK
int have_libjack (void) {
return 0;
}
#else
#include <stdio.h>
#include <string.h>
#include <assert.h>
#ifdef _WIN32
#include <windows.h>
#else
#include <dlfcn.h>
#endif
static void* lib_open(const char* const so) {
#ifdef _WIN32
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 _WIN32
return (void*) GetProcAddress((HMODULE)lib, sym);
#else
return dlsym(lib, sym);
#endif
}
#if _MSC_VER && !__INTEL_COMPILER
typedef void * pvoid_t;
#define MAPSYM(SYM, FAIL) _j._ ## SYM = (func_t)lib_symbol(lib, "jack_" # SYM); \
if (!_j._ ## SYM) err |= FAIL;
#elif defined NDEBUG
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;
#else
typedef void * __attribute__ ((__may_alias__)) pvoid_t;
#define MAPSYM(SYM, FAIL) *(pvoid_t *)(&_j._ ## SYM) = lib_symbol(lib, "jack_" # SYM); \
if (!_j._ ## SYM) { \
if (FAIL) { \
fprintf(stderr, "*** WEAK-JACK: required symbol 'jack_%s' was not found\n", "" # SYM); \
} \
err |= FAIL; \
}
#endif
typedef void (* func_t) (void);
/* function pointers to the real jack API */
static struct WeakJack {
func_t _client_open; // special case due to varargs
#define JCFUN(ERR, RTYPE, NAME, RVAL) func_t _ ## NAME ;
#define JPFUN(ERR, RTYPE, NAME, DEF, ARGS, RVAL) func_t _ ## NAME ;
#define JXFUN(ERR, RTYPE, NAME, DEF, ARGS, CODE) func_t _ ## NAME ;
#define JVFUN(ERR, NAME, DEF, ARGS, CODE) func_t _ ## NAME ;
#include "AudioWeakJack.def"
#undef JCFUN
#undef JPFUN
#undef JXFUN
#undef JVFUN
} _j;
static int _status = -1;
__attribute__((constructor))
static void init_weak_jack(void)
{
void* lib;
int err = 0;
#ifndef NDEBUG
fprintf(stderr, "*** WEAK-JACK: initializing\n");
#endif
memset(&_j, 0, sizeof(_j));
#ifdef __APPLE__
lib = lib_open("libjack.dylib");
if (!lib) {
lib = lib_open("/usr/local/lib/libjack.dylib");
}
#elif (defined _WIN32)
# ifdef __x86_64__
lib = lib_open("libjack64.dll");
# else
lib = lib_open("libjack.dll");
# endif
#else
lib = lib_open("libjack.so.0");
#endif
if (!lib) {
#ifndef NDEBUG
fprintf(stderr, "*** WEAK-JACK: libjack was not found\n");
#endif
_status = -2;
return;
}
/* found library, now lookup functions */
MAPSYM(client_open, 2)
#define JCFUN(ERR, RTYPE, NAME, RVAL) MAPSYM(NAME, ERR)
#define JPFUN(ERR, RTYPE, NAME, DEF, ARGS, RVAL) MAPSYM(NAME, ERR)
#define JXFUN(ERR, RTYPE, NAME, DEF, ARGS, CODE) MAPSYM(NAME, ERR)
#define JVFUN(ERR, NAME, DEF, ARGS, CODE) MAPSYM(NAME, ERR)
#include "AudioWeakJack.def"
#undef JCFUN
#undef JPFUN
#undef JXFUN
#undef JVFUN
/* if a required symbol is not found, disable JACK completly */
if (err) {
_j._client_open = NULL;
}
_status = err;
#ifndef NDEBUG
fprintf(stderr, "*** WEAK-JACK: %s. (%d)\n", err ? "jack is not available" : "OK", _status);
#endif
}
int have_libjack (void) {
if (_status == -1) {
init_weak_jack();
}
return _status;
}
/*******************************************************************************
* helper macros
*/
#if defined(__GNUC__) && (__GNUC__ > 2) && !defined(NDEBUG)
#define likely(expr) (__builtin_expect (!!(expr), 1))
#else
#define likely(expr) (expr)
#endif
#ifndef NDEBUG
# define WJACK_WARNING(NAME) \
fprintf(stderr, "*** WEAK-JACK: function 'jack_%s' ignored\n", "" # NAME);
#else
# define WJACK_WARNING(NAME) ;
#endif
/******************************************************************************
* JACK API wrapper functions.
*
* if a function pointer is set in the static struct WeakJack _j,
* the function is called directly.
* Otherwise a dummy NOOP implementation is provided.
* The latter is mainly for compile-time warnings.
*
* If libjack is not found, jack_client_open() will fail.
* In that case the application should not call any other libjack
* functions. Hence a real implementation is not needed.
* (jack ringbuffer may be an exception for some apps)
*/
/* dedicated support for jack_client_open(,..) variable arg function macro */
func_t WJACK_get_client_open(void) {
if (_status == -1) {
init_weak_jack();
}
return _j._client_open;
}
/* callback to set status */
jack_client_t * WJACK_no_client_open (const char *client_name, jack_options_t options, jack_status_t *status, ...) {
WJACK_WARNING(client_open);
if (status) { *status = JackFailure; }
return NULL;
}
/*******************************************************************************
* Macros to wrap jack API
*/
/* abstraction for jack_client functions
* rtype jack_function_name (jack_client_t *client) { return rval; }
*/
#define JCFUN(ERR, RTYPE, NAME, RVAL) \
RTYPE WJACK_ ## NAME (jack_client_t *client) { \
if likely(_j._ ## NAME) { \
return ((RTYPE (*)(jack_client_t *client)) _j._ ## NAME)(client); \
} else { \
WJACK_WARNING(NAME) \
return RVAL; \
} \
}
/* abstraction for NOOP functions with return value
* rtype jack_function_name (ARGS) { return rval; }
*/
#define JPFUN(ERR, RTYPE, NAME, DEF, ARGS, RVAL) \
RTYPE WJACK_ ## NAME DEF { \
if likely(_j._ ## NAME) { \
return ((RTYPE (*)DEF) _j._ ## NAME) ARGS; \
} else { \
WJACK_WARNING(NAME) \
return RVAL; \
} \
}
/* abstraction for functions that need custom code.
* e.g. functions with return-value-pointer args,
* use CODE to initialize value
*
* rtype jack_function_name (ARGS) { CODE }
*/
#define JXFUN(ERR, RTYPE, NAME, DEF, ARGS, CODE) \
RTYPE WJACK_ ## NAME DEF { \
if likely(_j._ ## NAME) { \
return ((RTYPE (*)DEF) _j._ ## NAME) ARGS; \
} else { \
WJACK_WARNING(NAME) \
CODE \
} \
}
/* abstraction for void functions with return-value-pointer args
* void jack_function_name (ARGS) { CODE }
*/
#define JVFUN(ERR, NAME, DEF, ARGS, CODE) \
void WJACK_ ## NAME DEF { \
if likely(_j._ ## NAME) { \
((void (*)DEF) _j._ ## NAME) ARGS; \
} else { \
WJACK_WARNING(NAME) \
CODE \
} \
}
#include "AudioWeakJack.def"
#undef JCFUN
#undef JPFUN
#undef JXFUN
#undef JVFUN
#endif // end USE_WEAK_JACK

View File

@@ -11,6 +11,7 @@
#cmakedefine LMMS_HAVE_ALSA
#cmakedefine LMMS_HAVE_FLUIDSYNTH
#cmakedefine LMMS_HAVE_JACK
#cmakedefine LMMS_HAVE_WEAKJACK
#cmakedefine LMMS_HAVE_MP3LAME
#cmakedefine LMMS_HAVE_OGGVORBIS
#cmakedefine LMMS_HAVE_OSS