UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
jack_common.h
Go to the documentation of this file.
1
6/*
7 * Copyright (c) 2019-2024 CESNET, z. s. p. o.
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, is permitted provided that the following conditions
12 * are met:
13 *
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 *
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 *
21 * 3. Neither the name of CESNET nor the names of its contributors may be
22 * used to endorse or promote products derived from this software without
23 * specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
27 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
28 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
29 * EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
30 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
31 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
32 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
35 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
36 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 */
38
39#ifndef JACK_COMMON_H
40#define JACK_COMMON_H
41
42#ifdef __cplusplus
43#include <cassert>
44#include <cerrno>
45#include <cstring>
46#else
47#include <assert.h>
48#include <errno.h>
49#include <stdbool.h>
50#include <string.h>
51#endif // ! defined __cplusplus
52
53#include <jack/jack.h>
54#include <stdio.h>
55#include <stdlib.h>
56
57#include "compat/dlfunc.h"
58#include "debug.h"
59#include "types.h"
60#include "utils/macros.h"
61
62#if defined (__linux__) && defined (_GNU_SOURCE)
63#include "utils/fs.h"
64#define HAVE_DLINFO 1
65#endif
66
67#define MOD_NAME "[jack_common] "
68
69typedef int (*jack_activate_t)(jack_client_t *client) JACK_OPTIONAL_WEAK_EXPORT;
70typedef int (*jack_client_close_t)(jack_client_t *client) JACK_OPTIONAL_WEAK_EXPORT;
71typedef jack_client_t *(*jack_client_open_t)(const char *client_name,
72 jack_options_t options,
73 jack_status_t *status, ...) JACK_OPTIONAL_WEAK_EXPORT;
74typedef int (*jack_connect_t)(jack_client_t *client,
75 const char *source_port,
76 const char *destination_port) JACK_OPTIONAL_WEAK_EXPORT;
77typedef int (*jack_deactivate_t)(jack_client_t *client) JACK_OPTIONAL_WEAK_EXPORT;
78typedef int (*jack_disconnect_t)(jack_client_t *client,
79 const char *source_port,
80 const char *destination_port) JACK_OPTIONAL_WEAK_EXPORT;
81typedef void (*jack_free_t)(void* ptr) JACK_OPTIONAL_WEAK_EXPORT;
82typedef const char **(*jack_get_ports_t)(jack_client_t *client,
83 const char *port_name_pattern,
84 const char *type_name_pattern,
85 unsigned long flags) JACK_OPTIONAL_WEAK_EXPORT;
86typedef jack_nframes_t (*jack_get_sample_rate_t)(jack_client_t *) JACK_OPTIONAL_WEAK_EXPORT;
87typedef void * (*jack_port_get_buffer_t)(jack_port_t *port, jack_nframes_t) JACK_OPTIONAL_WEAK_EXPORT;
88typedef const char * (*jack_port_name_t)(const jack_port_t *port) JACK_OPTIONAL_WEAK_EXPORT;
89typedef jack_port_t * (*jack_port_register_t)(jack_client_t *client,
90 const char *port_name,
91 const char *port_type,
92 unsigned long flags,
93 unsigned long buffer_size) JACK_OPTIONAL_WEAK_EXPORT;
94typedef int (*jack_set_process_callback_t)(jack_client_t *client,
95 JackProcessCallback process_callback,
96 void *arg) JACK_OPTIONAL_WEAK_EXPORT;
97typedef int (*jack_set_sample_rate_callback_t)(jack_client_t *client,
98 JackSampleRateCallback srate_callback,
99 void *arg) JACK_OPTIONAL_WEAK_EXPORT;
100
119
120static void close_libjack(struct libjack_connection *s)
121{
122 if (s == NULL) {
123 return;
124 }
125#ifdef RTLD_DEFAULT
126 if (s->libjack != RTLD_DEFAULT) {
127 dlclose(s->libjack);
128 }
129#else
130 dlclose(s->libjack);
131#endif // defined RTLD_DEFAULT
132 free(s);
133}
134
135#define JACK_DLSYM(sym) s->sym = (void *) dlsym(s->libjack, "jack_" #sym); if (s->sym == NULL) { log_msg(LOG_LEVEL_ERROR, "JACK symbol %s not found: %s\n", "jack_" #sym, dlerror()); return false; }
136
138{
139 JACK_DLSYM(activate);
140 JACK_DLSYM(client_close)
141 JACK_DLSYM(client_open)
142 JACK_DLSYM(connect);
143 JACK_DLSYM(deactivate);
144 JACK_DLSYM(disconnect);
145 JACK_DLSYM(free)
146 JACK_DLSYM(get_ports)
147 JACK_DLSYM(get_sample_rate);
148 JACK_DLSYM(set_sample_rate_callback);
149 JACK_DLSYM(port_get_buffer);
150 JACK_DLSYM(port_name);
151 JACK_DLSYM(port_register);
152 JACK_DLSYM(set_process_callback);
153 return true;
154}
155
157{
158 struct libjack_connection *s = calloc(1, sizeof(struct libjack_connection));
159
160#ifdef RTLD_DEFAULT
161 // try to load from already loaded library (eg. by LD_PRELOAD), RTLD_DEFAULT is POSIX-only
162 if (dlsym(RTLD_DEFAULT, "jack_activate") != NULL) {
163 s->libjack = RTLD_DEFAULT;
164 if (load_jack_symbols(s)) {
165 log_msg(LOG_LEVEL_VERBOSE, "Using preloaded JACK library.\n");
166 return s;
167 }
168 }
169#endif
170
171 const char *shlib[] = {
172#ifdef _WIN32
173 "C:/Windows/libjack64.dll"
174#elif defined(__APPLE__)
175#ifdef __aarch64__
176 "/opt/homebrew/lib/libjack.dylib",
177#endif // defined __aarch64__
178 "libjack.dylib",
179 "/usr/local/lib/libjack.dylib"
180#elif defined(__linux__)
181 "libjack.so"
182#endif
183 };
184 char err[STR_LEN];
185 err[0] = '\0';
186 for (unsigned i = 0; i < sizeof shlib / sizeof shlib[0]; ++i) {
187 s->libjack = dlopen(shlib[i], RTLD_NOW);
188 if (s->libjack != NULL) {
189 MSG(VERBOSE, "library loaded from: %s\n", shlib[i]);
190 break;
191 }
192 snprintf(err + strlen(err), sizeof err - strlen(err),
193 "JACK library \"%s\" opening failed: %s\n", shlib[i],
194 dlerror());
195 }
196 if (s->libjack == NULL) {
197 log_msg(LOG_LEVEL_ERROR, "%s", err);
198 free(s);
199 return NULL;
200 }
201 if (!load_jack_symbols(s)) {
202 close_libjack(s);
203 return NULL;
204 }
205#ifdef HAVE_DLINFO
206 char path[MAX_PATH_SIZE] = "(unknown)";
207 dlinfo(s->libjack, RTLD_DI_ORIGIN, path); // nonstandard GNU extension
208 log_msg(LOG_LEVEL_VERBOSE, "Loaded JACK library from %s.\n", path);
209#endif // defined HAVE_DLINFO
210 return s;
211}
212
213static inline struct device_info *audio_jack_probe(const char *client_name,
214 unsigned long port_flags,
215 int *count)
216{
217 jack_client_t *client;
218 jack_status_t status;
219 char *last_name = NULL;
220 int i;
221 const char **ports;
222 int port_count = 0;
224 if (!libjack) {
225 return NULL;
226 }
227
228 *count = 0;
229 client = libjack->client_open(client_name, JackNoStartServer, &status);
230 if(status & JackFailure) {
231 log_msg(LOG_LEVEL_ERROR, "Opening JACK client failed.\n");
233 return NULL;
234 }
235
236 ports = libjack->get_ports(client, NULL, NULL, port_flags);
237 if(ports == NULL) {
238 log_msg(LOG_LEVEL_ERROR, "Unable to enumerate JACK ports.\n");
240 return NULL;
241 }
242
243 for(port_count = 0; ports[port_count] != NULL; port_count++);
244
245 struct device_info *available_devices = port_count > 0 ? calloc(port_count, sizeof(struct device_info)) : NULL;
246
247 int channel_count = 0;
248 for(i = 0; ports[i] != NULL; i++) {
249 char *item = strdup(ports[i]);
250 assert(item != NULL);
251 char *save_ptr = NULL;
252 char *name;
253
254 ++channel_count;
255 name = strtok_r(item, "_", &save_ptr);
256 if (name == NULL) { // shouldn't happen
257 log_msg(LOG_LEVEL_ERROR, "Incorrect JACK name: %s!\n", ports[i]);
258 free(item);
259 continue;
260 }
261 if(last_name && strcmp(last_name, name) != 0) {
262 snprintf(available_devices[*count].name, sizeof available_devices[*count].name, "jack:%s (%d channels)", last_name, channel_count);
263 snprintf(available_devices[*count].dev, sizeof available_devices[*count].dev, ":\"%s\"", last_name);
264 channel_count = 0;
265 (*count)++;
266 }
267 free(last_name);
268 last_name = strdup(name);
269 free(item);
270 }
271 if(last_name) {
272 snprintf(available_devices[*count].name, sizeof available_devices[*count].name, "jack:%s (%d channels)", last_name, channel_count);
273 snprintf(available_devices[*count].dev, sizeof available_devices[*count].dev, ":\"%s\"", last_name);
274 (*count)++;
275 }
276 free(last_name);
277 libjack->free(ports);
278 libjack->client_close(client);
279 close_libjack(libjack);
280
281 return available_devices;
282}
283
284#undef MOD_NAME
285
286#endif //JACK_COMMON_H
287
const char unsigned int flags
void log_msg(int level, const char *format,...)
Definition debug.cpp:130
#define LOG_LEVEL_ERROR
general errors
Definition debug.h:59
#define LOG_LEVEL_VERBOSE
Definition debug.h:63
#define MSG(l, fmt,...)
Definition debug.h:96
#define LIB_HANDLE
Definition dlfunc.h:51
#define MAX_PATH_SIZE
Definition fs.h:48
int count
Definition hd-rum.c:44
static int buffer_size(int sock, int optname, int size)
Definition hd-rum.c:64
static struct device_info * audio_jack_probe(const char *client_name, unsigned long port_flags, int *count)
int(* jack_activate_t)(jack_client_t *client) JACK_OPTIONAL_WEAK_EXPORT
Definition jack_common.h:69
int(* jack_client_close_t)(jack_client_t *client) JACK_OPTIONAL_WEAK_EXPORT
Definition jack_common.h:70
const char *(* jack_port_name_t)(const jack_port_t *port) JACK_OPTIONAL_WEAK_EXPORT
Definition jack_common.h:88
int(* jack_set_sample_rate_callback_t)(jack_client_t *client, JackSampleRateCallback srate_callback, void *arg) JACK_OPTIONAL_WEAK_EXPORT
Definition jack_common.h:97
void *(* jack_port_get_buffer_t)(jack_port_t *port, jack_nframes_t) JACK_OPTIONAL_WEAK_EXPORT
Definition jack_common.h:87
jack_client_t *(* jack_client_open_t)(const char *client_name, jack_options_t options, jack_status_t *status,...) JACK_OPTIONAL_WEAK_EXPORT
Definition jack_common.h:71
jack_port_t *(* jack_port_register_t)(jack_client_t *client, const char *port_name, const char *port_type, unsigned long flags, unsigned long buffer_size) JACK_OPTIONAL_WEAK_EXPORT
Definition jack_common.h:89
int(* jack_set_process_callback_t)(jack_client_t *client, JackProcessCallback process_callback, void *arg) JACK_OPTIONAL_WEAK_EXPORT
Definition jack_common.h:94
#define JACK_DLSYM(sym)
jack_nframes_t(* jack_get_sample_rate_t)(jack_client_t *) JACK_OPTIONAL_WEAK_EXPORT
Definition jack_common.h:86
int(* jack_connect_t)(jack_client_t *client, const char *source_port, const char *destination_port) JACK_OPTIONAL_WEAK_EXPORT
Definition jack_common.h:74
static void close_libjack(struct libjack_connection *s)
int(* jack_disconnect_t)(jack_client_t *client, const char *source_port, const char *destination_port) JACK_OPTIONAL_WEAK_EXPORT
Definition jack_common.h:78
static struct libjack_connection * open_libjack(void)
void(* jack_free_t)(void *ptr) JACK_OPTIONAL_WEAK_EXPORT
Definition jack_common.h:81
int(* jack_deactivate_t)(jack_client_t *client) JACK_OPTIONAL_WEAK_EXPORT
Definition jack_common.h:77
const char **(* jack_get_ports_t)(jack_client_t *client, const char *port_name_pattern, const char *type_name_pattern, unsigned long flags) JACK_OPTIONAL_WEAK_EXPORT
Definition jack_common.h:82
static bool load_jack_symbols(struct libjack_connection *s)
@ STR_LEN
"standard" string length placeholder
Definition macros.h:134
const char * name
Definition settings.cpp:193
char dev[1024]
Definition types.h:383
Definition hd-rum.c:27
jack_client_close_t client_close
jack_port_register_t port_register
jack_set_sample_rate_callback_t set_sample_rate_callback
LIB_HANDLE libjack
lib connection
jack_get_sample_rate_t get_sample_rate
jack_connect_t connect
jack_client_open_t client_open
jack_port_name_t port_name
jack_deactivate_t deactivate
jack_port_get_buffer_t port_get_buffer
jack_activate_t activate
jack_get_ports_t get_ports
jack_disconnect_t disconnect
jack_set_process_callback_t set_process_callback
Definition rtp.c:253
This file contains some common data types.