JACK: expose --nperiods option
[ardour.git] / libs / backends / jack / weak_libjack.c
1 /* runtime/weak dynamic JACK linking
2  *
3  * (C) 2014 Robin Gareus <robin@gareus.org>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2, or (at your option)
8  * any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software Foundation,
17  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  */
19
20 #include "weak_libjack.h"
21
22 #ifndef USE_WEAK_JACK
23
24 int have_libjack (void) {
25         return 0;
26 }
27
28 #else
29
30 #include <stdio.h>
31 #include <string.h>
32 #include <assert.h>
33
34 #ifdef PLATFORM_WINDOWS
35 #include <windows.h>
36 #else
37 #include <dlfcn.h>
38 #endif
39
40 static void* lib_open(const char* const so) {
41 #ifdef PLATFORM_WINDOWS
42         return (void*) LoadLibraryA(so);
43 #else
44         return dlopen(so, RTLD_NOW|RTLD_LOCAL);
45 #endif
46 }
47
48 static void* lib_symbol(void* const lib, const char* const sym) {
49 #ifdef PLATFORM_WINDOWS
50         return (void*) GetProcAddress((HMODULE)lib, sym);
51 #else
52         return dlsym(lib, sym);
53 #endif
54 }
55
56 #ifdef COMPILER_MSVC
57 typedef void * pvoid_t;
58 #define MAPSYM(SYM, FAIL) _j._ ## SYM = (func_t)lib_symbol(lib, "jack_" # SYM); \
59         if (!_j._ ## SYM) err |= FAIL;
60 #elif defined NDEBUG
61 typedef void * __attribute__ ((__may_alias__)) pvoid_t;
62 #define MAPSYM(SYM, FAIL) *(pvoid_t *)(&_j._ ## SYM) = lib_symbol(lib, "jack_" # SYM); \
63         if (!_j._ ## SYM) err |= FAIL;
64 #else
65 typedef void * __attribute__ ((__may_alias__)) pvoid_t;
66 #define MAPSYM(SYM, FAIL) *(pvoid_t *)(&_j._ ## SYM) = lib_symbol(lib, "jack_" # SYM); \
67         if (!_j._ ## SYM) { \
68                 if (FAIL) { \
69                         fprintf(stderr, "*** WEAK-JACK: required symbol 'jack_%s' was not found\n", "" # SYM); \
70                 } \
71                 err |= FAIL; \
72         }
73 #endif
74
75 typedef void (* func_t) (void);
76
77 /* function pointers to the real jack API */
78 static struct WeakJack {
79         func_t _client_open; // special case due to varargs
80
81 #define JCFUN(ERR, RTYPE, NAME, RVAL)              func_t _ ## NAME ;
82 #define JPFUN(ERR, RTYPE, NAME, DEF, ARGS, RVAL)   func_t _ ## NAME ;
83 #define JXFUN(ERR, RTYPE, NAME, DEF, ARGS, CODE)   func_t _ ## NAME ;
84 #define JVFUN(ERR, NAME, DEF, ARGS, CODE)          func_t _ ## NAME ;
85
86 #include "weak_libjack.def"
87
88 #undef JCFUN
89 #undef JPFUN
90 #undef JXFUN
91 #undef JVFUN
92 } _j;
93
94 static int _status = -1;
95
96 __attribute__((constructor))
97 static void init_weak_jack(void)
98 {
99         void* lib;
100         int err = 0;
101 #ifndef NDEBUG
102         fprintf(stderr, "*** WEAK-JACK: initializing\n");
103 #endif
104
105         memset(&_j, 0, sizeof(_j));
106
107 #ifdef __APPLE__
108         lib = lib_open("libjack.dylib");
109         if (!lib) {
110                 lib = lib_open("/usr/local/lib/libjack.dylib");
111         }
112 #elif (defined PLATFORM_WINDOWS)
113 # if ( defined(__x86_64__) || defined(_M_X64) )
114         lib = lib_open("libjack64.dll");
115 # else
116         lib = lib_open("libjack.dll");
117 # endif
118 #else
119         lib = lib_open("libjack.so.0");
120 #endif
121         if (!lib) {
122 #ifndef NDEBUG
123                 fprintf(stderr, "*** WEAK-JACK: libjack was not found\n");
124 #endif
125                 _status = -2;
126                 return;
127         }
128
129         /* found library, now lookup functions */
130         MAPSYM(client_open, 2)
131
132 #define JCFUN(ERR, RTYPE, NAME, RVAL)             MAPSYM(NAME, ERR)
133 #define JPFUN(ERR, RTYPE, NAME, DEF, ARGS, RVAL)  MAPSYM(NAME, ERR)
134 #define JXFUN(ERR, RTYPE, NAME, DEF, ARGS, CODE)  MAPSYM(NAME, ERR)
135 #define JVFUN(ERR, NAME, DEF, ARGS, CODE)         MAPSYM(NAME, ERR)
136
137 #include "weak_libjack.def"
138
139 #undef JCFUN
140 #undef JPFUN
141 #undef JXFUN
142 #undef JVFUN
143
144         /* if a required symbol is not found, disable JACK completly */
145         if (err) {
146                 _j._client_open = NULL;
147         }
148         _status = err;
149 #ifndef NDEBUG
150         fprintf(stderr, "*** WEAK-JACK: %s. (%d)\n", err ? "jack is not available" : "OK", _status);
151 #endif
152 }
153
154 int have_libjack (void) {
155         if (_status == -1) {
156                 init_weak_jack();
157         }
158         return _status;
159 }
160
161 /*******************************************************************************
162  * helper macros
163  */
164
165 #if defined(__GNUC__) && (__GNUC__ > 2) && !defined(NDEBUG)
166 #define likely(expr) (__builtin_expect (!!(expr), 1))
167 #else
168 #define likely(expr) (expr)
169 #endif
170
171 #ifndef NDEBUG
172 # define WJACK_WARNING(NAME) \
173         fprintf(stderr, "*** WEAK-JACK: function 'jack_%s' ignored\n", "" # NAME);
174 #else
175 # define WJACK_WARNING(NAME) ;
176 #endif
177
178 /******************************************************************************
179  * JACK API wrapper functions.
180  *
181  * if a function pointer is set in the static struct WeakJack _j,
182  * the function is called directly.
183  * Otherwise a dummy NOOP implementation is provided.
184  * The latter is mainly for compile-time warnings.
185  *
186  * If libjack is not found, jack_client_open() will fail.
187  * In that case the application should not call any other libjack
188  * functions. Hence a real implementation is not needed.
189  * (jack ringbuffer may be an exception for some apps)
190  */
191
192 /* dedicated support for jack_client_open(,..) variable arg function macro */
193 func_t WJACK_get_client_open(void) {
194         if (_status == -1) {
195                 init_weak_jack();
196         }
197         return _j._client_open;
198 }
199
200 /* callback to set status */
201 jack_client_t * WJACK_no_client_open (const char *client_name, jack_options_t options, jack_status_t *status, ...) {
202         WJACK_WARNING(client_open);
203         if (status) { *status = JackFailure; }
204         return NULL;
205 }
206
207 /*******************************************************************************
208  * Macros to wrap jack API
209  */
210
211 /* abstraction for jack_client functions
212  *  rtype jack_function_name (jack_client_t *client) { return rval; }
213  */
214 #define JCFUN(ERR, RTYPE, NAME, RVAL) \
215         RTYPE WJACK_ ## NAME (jack_client_t *client) { \
216                 if likely(_j._ ## NAME) { \
217                         return ((RTYPE (*)(jack_client_t *client)) _j._ ## NAME)(client); \
218                 } else { \
219                         WJACK_WARNING(NAME) \
220                         return RVAL; \
221                 } \
222         }
223
224 /* abstraction for NOOP functions with return value
225  *  rtype jack_function_name (ARGS) { return rval; }
226  */
227 #define JPFUN(ERR, RTYPE, NAME, DEF, ARGS, RVAL) \
228         RTYPE WJACK_ ## NAME DEF { \
229                 if likely(_j._ ## NAME) { \
230                         return ((RTYPE (*)DEF) _j._ ## NAME) ARGS; \
231                 } else { \
232                         WJACK_WARNING(NAME) \
233                         return RVAL; \
234                 } \
235         }
236
237 /* abstraction for functions that need custom code.
238  * e.g. functions with return-value-pointer args,
239  * use CODE to initialize value
240  *
241  *  rtype jack_function_name (ARGS) { CODE }
242  */
243 #define JXFUN(ERR, RTYPE, NAME, DEF, ARGS, CODE) \
244         RTYPE WJACK_ ## NAME DEF { \
245                 if likely(_j._ ## NAME) { \
246                         return ((RTYPE (*)DEF) _j._ ## NAME) ARGS; \
247                 } else { \
248                         WJACK_WARNING(NAME) \
249                         CODE \
250                 } \
251         }
252
253 /* abstraction for void functions with return-value-pointer args
254  *  void jack_function_name (ARGS) { CODE }
255  */
256 #define JVFUN(ERR, NAME, DEF, ARGS, CODE) \
257         void WJACK_ ## NAME DEF { \
258                 if likely(_j._ ## NAME) { \
259                         ((void (*)DEF) _j._ ## NAME) ARGS; \
260                 } else { \
261                         WJACK_WARNING(NAME) \
262                         CODE \
263                 } \
264         }
265
266 #include "weak_libjack.def"
267
268 #undef JCFUN
269 #undef JPFUN
270 #undef JXFUN
271 #undef JVFUN
272
273 #endif // end USE_WEAK_JACK