UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
jack.c
Go to the documentation of this file.
1
5/*
6 * Copyright (c) 2012-2024 CESNET z.s.p.o.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, is permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * 3. Neither the name of CESNET nor the names of its contributors may be
21 * used to endorse or promote products derived from this software without
22 * specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
26 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
28 * EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
29 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
30 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
34 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
35 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 */
37
38#include <jack/jack.h>
39#include <stdio.h>
40#include <stdlib.h>
41#include <string.h>
42
43#include "audio/audio_capture.h"
44#include "audio/types.h"
45#include "audio/utils.h"
47#include "debug.h"
48#include "host.h"
49#include "jack_common.h"
50#include "lib_common.h"
51#include "utils/macros.h"
52#include "utils/ring_buffer.h"
53
54#define MOD_NAME "[JACK capture] "
55
56enum {
58};
59
60static int jack_samplerate_changed_callback(jack_nframes_t nframes, void *arg);
61static int jack_process_callback(jack_nframes_t nframes, void *arg);
62
64 struct module *parent;
66
68 jack_client_t *client;
69 jack_port_t *input_ports[MAX_PORTS];
70 char *tmp;
71
72 sem_t data_sem;
76
77 long int first_channel;
78};
79
80static int jack_samplerate_changed_callback(jack_nframes_t nframes, void *arg)
81{
82 struct state_jack_capture *s = (struct state_jack_capture *) arg;
83
84 s->frame.sample_rate = nframes;
85
86 return 0;
87}
88
89static int jack_process_callback(jack_nframes_t nframes, void *arg)
90{
91 struct state_jack_capture *s = (struct state_jack_capture *) arg;
92 int i;
93 int channel_size = nframes * sizeof(int32_t);
94
95 if (!s->can_process) {
96 return 0;
97 }
98
99 for (i = 0; i < s->frame.ch_count; ++i) {
100 jack_default_audio_sample_t *in = s->libjack->port_get_buffer(s->input_ports[i], nframes);
101 mux_channel(s->tmp, (char *) in, sizeof(int32_t), channel_size, s->frame.ch_count, i, 1.0);
102 }
103
104 ring_buffer_write(s->data, s->tmp, channel_size * s->frame.ch_count);
106
107 return 0;
108}
109
110static void audio_cap_jack_probe(struct device_info **available_devices, int *count, void (**deleter)(void *))
111{
112 *deleter = free;
113 *available_devices = audio_jack_probe(PACKAGE_STRING, JackPortIsOutput, count);
114}
115
116static void audio_cap_jack_help(const char *client_name)
117{
118 int count = 0;
119 int i = 0;
120 struct device_info *available_devices = audio_jack_probe(client_name, JackPortIsOutput, &count);
121
122 printf("Usage:\n");
123 printf("\t-s jack[:first_channel=<f>][:name=<n>][:<device>]\n");
124 printf("\twhere\n");
125 printf("\t\t<f> - index of first channel to capture (default: 0)\n");
126 printf("\t\t<n> - name of the JACK client (default: %s)\n", PACKAGE_NAME);
127 printf("\n");
128
129 if(!available_devices)
130 return;
131
132 printf("Available devices:\n");
133 for(i = 0; i < count; i++){
134 printf("\t%s\n", available_devices[i].name);
135 }
136 free(available_devices);
137}
138
140{
141 struct state_jack_capture *s = state;
142 s->should_exit = true;
144}
145
146static void * audio_cap_jack_init(struct module *parent, const char *cfg)
147{
148 jack_status_t status;
149 const char **ports;
150 int i;
151 char *client_name;
152 const char *source_name = NULL;
153
154 client_name = alloca(MAX(strlen(PACKAGE_NAME), strlen(cfg)) + 1);
155 strcpy(client_name, PACKAGE_NAME);
156
157 struct state_jack_capture *s = (struct state_jack_capture *) calloc(1, sizeof(struct state_jack_capture));
158 if(!s) {
159 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Unable to allocate memory.\n");
160 return NULL;
161 }
162 s->parent = parent;
163 s->libjack = open_libjack();
164 if (s->libjack == NULL) {
165 free(s);
166 return NULL;
167 }
168
169 char *dup = strdup(cfg);
170 assert(dup != NULL);
171 char *tmp = dup, *item, *save_ptr;
172 while ((item = strtok_r(tmp, ":", &save_ptr)) != NULL) {
173 if (strcmp(item, "help") == 0) {
174 audio_cap_jack_help(client_name);
175 free(dup);
176 free(s);
177 return INIT_NOERR;
178 } else if (strstr(item, "first_channel=") == item) {
179 char *endptr;
180 char *val = item + strlen("first_channel=");
181 errno = 0;
182 s->first_channel = strtol(val, &endptr, 0);
183 if (errno == ERANGE || *endptr != '\0' || s->first_channel < 0) {
184 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Wrong value '%s'.\n", val);
185 goto error;
186 }
187 } else if (strstr(item, "name=") == item) {
188 strcpy(client_name, item + strlen("name="));
189 } else { // this is the device name
190 source_name = cfg + (item - dup);
191 break;
192 }
193
194 tmp = NULL;
195 }
196 free(dup);
197 dup = NULL;
198
199 s->client = s->libjack->client_open(client_name, JackNullOption, &status);
200 if(status & JackFailure) {
201 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Opening JACK client failed.\n");
202 goto error;
203 }
204
205 ports = s->libjack->get_ports(s->client, source_name, NULL, JackPortIsOutput);
206 if(ports == NULL) {
207 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Unable to output ports matching \"%s\".\n", source_name);
208 goto release_client;
209 }
210
211 i = 0;
212 while(ports[i]) i++;
213
215 if (i < s->frame.ch_count) {
216 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Requested channel count %d not found (matching pattern %s).\n",
217 s->frame.ch_count, cfg);
218 goto release_client;
219
220 }
221
222 s->frame.bps = 4;
224 log_msg(LOG_LEVEL_WARNING, "[JACK capture] Ignoring user specified sample rate!\n");
225 }
228 s->frame.data = malloc(s->frame.max_size);
229
230 platform_sem_init(&s->data_sem, 0, 0);
231
232 s->tmp = malloc(s->frame.max_size);
233
235
237 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Registring callback problem.\n");
238 goto release_client;
239 }
240
241 if (s->libjack->set_process_callback(s->client, jack_process_callback, (void *) s) != 0) {
242 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Process callback registration problem.\n");
243 goto release_client;
244 }
245
246 if (s->libjack->activate(s->client)) {
247 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Cannot activate client.\n");
248 goto release_client;
249 }
250
251 {
252 int port;
253 char name[32];
254
255 for(port = 0; port < s->frame.ch_count; port++) {
256 snprintf(name, 32, "capture_%02u", port);
257 s->input_ports[port] = s->libjack->port_register(s->client, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
258 /* attach ports */
259 if (s->libjack->connect(s->client, ports[port], s->libjack->port_name(s->input_ports[port]))) {
260 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Cannot connect input ports.\n");
261 }
262 }
263 }
264
265 free(ports);
267
268 s->can_process = true;
269
270 return s;
271
272release_client:
274error:
276 free(dup);
277 free(s);
278 return NULL;
279}
280
282{
283 struct state_jack_capture *s = (struct state_jack_capture *) state;
284
286
287 int read_avail = ring_get_current_size(s->data);
289 if(read_avail > s->frame.data_len){
290 /* We didn't read all available data in ring buffer, so we
291 * increment the semaphore back up, so we don't wait needlessly
292 * on the next call */
294 }
295
296 float2int((char *) s->frame.data, (char *) s->frame.data, s->frame.max_size);
297
298 if(!s->frame.data_len)
299 return NULL;
300
301 return &s->frame;
302}
303
304static void audio_cap_jack_done(void *state)
305{
306 struct state_jack_capture *s = (struct state_jack_capture *) state;
307
309 s);
310
312 free(s->tmp);
314 free(s->frame.data);
317 free(s);
318}
319
326
328
void ** state
int void * val
struct video_frame * frame
int void(** deleter)(void *))
This file contains definition of some common audio types.
#define AUDIO_CAPTURE_ABI_VERSION
static void audio_cap_jack_help(const char *client_name)
Definition jack.c:116
static int jack_process_callback(jack_nframes_t nframes, void *arg)
Definition jack.c:89
static int jack_samplerate_changed_callback(jack_nframes_t nframes, void *arg)
Definition jack.c:80
static void audio_cap_jack_should_exit(void *state)
Definition jack.c:139
static void audio_cap_jack_probe(struct device_info **available_devices, int *count, void(**deleter)(void *))
Definition jack.c:110
#define MOD_NAME
Definition jack.c:54
static void * audio_cap_jack_init(struct module *parent, const char *cfg)
Definition jack.c:146
static struct audio_frame * audio_cap_jack_read(void *state)
Definition jack.c:281
@ MAX_PORTS
Definition jack.c:57
static void audio_cap_jack_done(void *state)
Definition jack.c:304
static const struct audio_capture_info acap_jack_info
Definition jack.c:320
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_WARNING
less severe errors
Definition debug.h:60
int count
Definition hd-rum.c:44
void register_should_exit_callback(struct module *mod, void(*callback)(void *), void *udata)
Definition host.cpp:1144
void unregister_should_exit_callback(struct module *mod, void(*callback)(void *), void *udata)
Definition host.cpp:1158
unsigned int audio_capture_sample_rate
Definition host.cpp:165
unsigned int audio_capture_channels
Definition host.cpp:163
#define DEFAULT_AUDIO_CAPTURE_CHANNELS
Definition host.h:89
#define INIT_NOERR
Definition host.h:73
static struct device_info * audio_jack_probe(const char *client_name, unsigned long port_flags, int *count)
static void close_libjack(struct libjack_connection *s)
static struct libjack_connection * open_libjack(void)
@ LIBRARY_CLASS_AUDIO_CAPTURE
Definition lib_common.h:76
#define REGISTER_MODULE(name, info, lclass, abi)
Registers module to global modules' registry.
Definition lib_common.h:144
#define MAX(a, b)
Definition macros.h:65
void platform_sem_post(void *semStructure)
void platform_sem_wait(void *semStructure)
void platform_sem_init(void *semStructure, int pshared, int initialValue)
void platform_sem_destroy(void *semStructure)
int ring_get_current_size(struct ring_buffer *ring)
void ring_buffer_destroy(struct ring_buffer *ring)
struct ring_buffer * ring_buffer_init(int size)
int ring_buffer_read(struct ring_buffer *ring, char *out, int max_len)
void ring_buffer_write(struct ring_buffer *ring, const char *in, int len)
const char * parent
Definition settings.cpp:198
const char * name
Definition settings.cpp:193
struct used to comunicate with audio capture/playback device
Definition types.h:99
int sample_rate
Definition types.h:101
char * data
Definition types.h:102
int ch_count
Definition types.h:104
int data_len
Definition types.h:103
int bps
Definition types.h:100
int max_size
Definition types.h:105
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
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_port_get_buffer_t port_get_buffer
jack_activate_t activate
jack_get_ports_t get_ports
jack_set_process_callback_t set_process_callback
struct module * parent
Definition jack.c:64
jack_port_t * input_ports[MAX_PORTS]
Definition jack.c:69
jack_client_t * client
Definition jack.c:68
bool can_process
Definition jack.c:74
struct audio_frame frame
Definition jack.c:67
struct ring_buffer * data
Definition jack.c:73
struct libjack_connection * libjack
Definition jack.c:65
bool should_exit
Definition jack.c:75
long int first_channel
Definition jack.c:77
sem_t data_sem
Definition jack.c:72
void float2int(char *out, const char *in, int len)
Definition utils.cpp:482
void mux_channel(char *out, const char *in, int bps, int in_len, int out_stream_channels, int pos_in_stream, double scale)
Definition utils.cpp:371