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) 2011-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 */
43#include <jack/jack.h>
44#include <limits.h>
45#include <stdio.h>
46#include <stdlib.h>
47#include <string.h>
48
49#include "audio/jack.h"
50#include "audio/types.h"
51#include "jack_common.h"
52#include "pthread.h"
53#include "rtp/pbuf.h"
54#include "rtp/rtp.h"
55
56#define CLIENT_NAME "UltraGrid Transport"
57#define BUFF_ELEM (1<<16)
58#define BUFF_SIZE (BUFF_ELEM * sizeof(float))
59#define MAX_PORTS 8
60#define MOD_NAME "[JACK trans.] "
61
62struct state_jack {
64
65 unsigned int sender:1,
67
68 jack_client_t *client;
69
71/* TODO: consider using ring buffers abstraction instead implementing
72 * by hand (see utils/ring_buffer.h) */
77
78 jack_port_t *input_port[MAX_PORTS];
79 jack_port_t *output_port[MAX_PORTS];
80
82 int in_ch_count; /* "requested", real received count is in
83 * record.ch_count */
85 int out_channel_count; /* really obtained playback channels ( <= _req) */
86 int out_channel_count_req; /* requested playback ch. count */
87};
88
89int jack_process_callback(jack_nframes_t nframes, void *arg);
90int jack_samplerate_changed_callback(jack_nframes_t nframes, void *arg);
92static int settings_init(struct state_jack *s, char *cfg);
93
94int jack_process_callback(jack_nframes_t nframes, void *arg) {
95 struct state_jack *s = (struct state_jack *) arg;
96 int send_b;
97 int i;
98
99 send_b = s->play_buffer_end - s->play_buffer_start;
100 if(send_b < 0) send_b += BUFF_SIZE;
101 if(send_b > (int) (sizeof (jack_default_audio_sample_t) * nframes))
102 send_b = sizeof (jack_default_audio_sample_t) * nframes;
103
104 for (i = 0; i < s->out_channel_count; ++i) {
105
106 int to_end = BUFF_SIZE - s->play_buffer_start;
107 jack_default_audio_sample_t *out =
108 s->libjack->port_get_buffer (s->output_port[i], nframes);
109 if(to_end > send_b) {
110 memcpy (out, s->play_buffer[i] + s->play_buffer_start,
111 send_b);
112 } else {
113 memcpy (out, s->play_buffer[i] + s->play_buffer_start,
114 to_end);
115 memcpy (out + to_end, s->play_buffer[i],
116 send_b - to_end);
117 }
118
119 }
120 s->play_buffer_start = (s->play_buffer_start + send_b) % BUFF_SIZE;
121
122 const float int_max_flt = nexttowardf((float) INT_MAX, INT_MAX); // max int representable as float
123
124 for(i = 0; i < s->record.ch_count; ++i) {
125 int j;
126 jack_default_audio_sample_t *in =
127 s->libjack->port_get_buffer (s->input_port[i], nframes);
128 for(j = 0; j < (int) nframes; ++j) {
129 *(int *)(void *)(s->rec_buffer + ((s->rec_buffer_end + (j * s->record.ch_count + i) * sizeof(int32_t)) % BUFF_SIZE)) =
130 in[j] * int_max_flt;
131 }
132 }
133 s->rec_buffer_end = (s->rec_buffer_end + nframes * s->record.ch_count * sizeof(int32_t)) % BUFF_SIZE;
134
135 //fprintf(stderr, ".%d.", nframes);
136
137 return 0;
138}
139
140int jack_samplerate_changed_callback(jack_nframes_t nframes, void *arg) {
141 struct state_jack *s = (struct state_jack *) arg;
142
143 s->record.sample_rate = nframes;
144 return 0;
145}
146
147void reconfigure_send_ch_count(struct state_jack *s, int ch_count)
148{
149 const char **ports;
150 int i;
151
152 s->out_channel_count = s->out_channel_count_req = ch_count;
153
154 if ((ports = s->libjack->get_ports (s->client, s->out_port_pattern, NULL, JackPortIsInput)) == NULL) {
155 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Cannot find any ports matching pattern '%s'\n", s->out_port_pattern);
156 s->out_channel_count = 0;
157 return;
158 }
159 for (i = 0; i < s->record.ch_count; ++i) {
160 s->libjack->disconnect(s->client, s->libjack->port_name (s->output_port[i]), ports[i]);
161 free(s->play_buffer[i]);
162 }
163
164 i = 0;
165 while (ports[i]) ++i;
166
167 if(i < s->out_channel_count) {
168 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Not enought output ports found matching pattern '%s': "
169 "%d requested, %d found\n", s->out_port_pattern, s->record.ch_count, i);
170 log_msg(LOG_LEVEL_WARNING, MOD_NAME "Reducing port count to %d\n", i);
171 s->out_channel_count = i;
172 }
173
174 for(i = 0; i < s->out_channel_count; ++i) {
175 if (s->libjack->connect (s->client, s->libjack->port_name (s->output_port[i]), ports[i])) {
176 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Cannot connect output ports: %s\n", ports[i]);
177 }
178 s->play_buffer[i] = malloc(BUFF_SIZE);
179 }
180
181 log_msg(LOG_LEVEL_NOTICE, MOD_NAME "Sending %d output audio streams (ports).\n", s->out_channel_count);
182
183 free (ports);
184}
185
186static int settings_init(struct state_jack *s, char *cfg)
187{
188 char * save_ptr = NULL,
189 *tok;
190
191 if (!cfg || cfg[0] == '\0' || strncmp(cfg, "help", strlen("help")) == 0)
192 {
193 printf("JACK config:\n"
194 "\t--audio-protocol JACK:({tok1|tok2...tokn-1},)*{tokn}\n\n"
195 "\tTokens:\n"
196 "\t\tpi[=<name>]\t\treceive sound from JACK instead of from RTP (optionally select port)\n"
197 "\n"
198 "\t\tpo[=<name>]\t\tsend sound output via JACK with (optional) port name.\n"
199 "\t\t\t\t\tIf name not specified, let Jack select (probably system output!)\n"
200 "\n"
201 "\t\tch=<count>\t\tcount of input (!) JACK ports to listen at (matching RE above)\n"
202 "\t\t\t\t\tYou should set it for input, otherwise the count defaults to 0.\n"
203 );
204 exit(0);
205 }
206 while((tok = strtok_r(cfg, ",", &save_ptr)) != NULL)
207 {
208 switch (tok[0]) {
209 case 'p':
210 if(tok[1] != 'i' && tok[1] != 'o')
211 return -1;
212 if(tok[1] == 'i') {
213 s->receiver = TRUE;
214 if(tok[2] == '=')
215 s->in_port_pattern = strdup(&tok[3]);
216 }
217 if(tok[1] == 'o') {
218 s->sender = TRUE;
219 if(tok[2] == '=')
220 s->out_port_pattern = strdup(&tok[3]);
221 }
222 break;
223 case 'c':
224 if(strncmp(tok, "ch=", 3))
225 return -1;
226 else
227 s->in_ch_count = atoi(tok + 3);
228 break;
229 default:
230 return -1;
231 }
232 cfg = NULL;
233 }
234 return 0;
235}
236
237static int attach_input_ports(struct state_jack *s)
238{
239 int i = 0;
240 const char **ports;
241 if ((ports = s->libjack->get_ports (s->client, s->in_port_pattern, NULL, JackPortIsOutput)) == NULL) {
242 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Cannot find any ports matching pattern '%s'\n", s->in_port_pattern);
243 return FALSE;
244 }
245
246 while (ports[i]) ++i;
247 if(i < s->record.ch_count) {
248 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Not enought input ports found matching pattern '%s': "
249 "%d requested, %d found\n", s->in_port_pattern, s->record.ch_count, i);
250 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Reducing port count to %d\n", i);
251 s->record.ch_count = i;
252 }
253
254 for(i = 0; i < s->in_ch_count; ++i) {
255 if (s->libjack->connect (s->client, ports[i], s->libjack->port_name (s->input_port[i]))) {
256 fprintf (stderr, "cannot connect input ports\n");
257 }
258 }
259
260 free (ports);
261 return TRUE;
262}
263
264void * jack_start(const char *cfg)
265{
266 struct state_jack *s;
267
268 s = (struct state_jack *) malloc(sizeof(struct state_jack));
269 assert (s != NULL);
270 s->libjack = open_libjack();
271 if (s->libjack == NULL) {
272 free(s);
273 return NULL;
274 }
275
276 s->in_port_pattern = NULL;
277 s->out_port_pattern = NULL;
278 s->in_ch_count = 1;
281 s->sender = FALSE;
282 s->receiver = FALSE;
283 s->out_channel_count = 0;
284
285 char *cfg_copy = strdup(cfg);
286 int ret = settings_init(s, cfg_copy);
287 free(cfg_copy);
288 if (ret != 0) {
289 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Setting JACK failed. Check configuration ('-j' option).\n");
290 goto error;
291 }
292
293 if(!s->sender && !s->receiver) {
294 goto error;
295 }
296
297 s->client = s->libjack->client_open(CLIENT_NAME, JackNullOption, NULL);
298 if(s->libjack->set_process_callback(s->client, jack_process_callback, (void *) s) != 0) {
299 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Callback initialization problem.\n");
300 goto error;
301 }
302
305 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Sample rate callback initialization problem.\n");
306 goto error;
307 }
308
309 //jack_on_shutdown (client, jack_shutdown, 0);
310
311 if(s->sender) {
312 char name[30];
313 int i;
314
315 for(i = 0; i < MAX_PORTS; ++i) {
316 snprintf(name, 30, "out_%02u", i);
317 s->output_port[i] = s->libjack->port_register (s->client, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
318 }
319
321 }
322
323 if(s->receiver) {
324 char name[30];
325 int i;
326
327 for(i = 0; i < s->in_ch_count; ++i) {
328 snprintf(name, 30, "in_%02u", i);
329 s->input_port[i] = s->libjack->port_register (s->client, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
330 }
331
333 s->record.bps = sizeof(int32_t);
335 s->rec_buffer = s->record.data = (void *) malloc(BUFF_SIZE);
336 }
337
338 if (s->libjack->activate (s->client)) {
339 fprintf (stderr, "cannot activate client");
340 goto error;
341 }
342
343 if(s->receiver) {
344 if(!attach_input_ports(s))
345 goto error;
346 }
347
348 return s;
349error:
351 free(s);
352 return NULL;
353}
354
355void jack_send(void *state, struct audio_frame *frame)
356{
357 //float *tmp = (char *) s->play_buffer + s->play_buffer_end;
358 struct state_jack *s = (struct state_jack *) state;
359 char *in_ptr = frame->data;
360
361 int i;
362
363 if(s->out_channel_count != frame->ch_count)
364 reconfigure_send_ch_count(s, frame->ch_count);
365
366 for(i = 0; i < frame->data_len; i+= frame->bps * frame->ch_count) {
367 int channels;
368 for (channels = 0; channels < s->out_channel_count; ++channels) {
369 float *pos = (float *)(void *) &s->play_buffer[channels][(s->play_buffer_end + i * 4
370 / (frame->ch_count * frame->bps)) % BUFF_SIZE];
371 *pos = (*((int *)(void *) (in_ptr + channels * frame->bps)) << (32 - frame->bps * 8)) / (float) INT_MAX;
372 }
373
374 in_ptr += frame->bps * frame->ch_count;
375 }
376 s->play_buffer_end = (s->play_buffer_end + frame->data_len / (frame->bps * frame->ch_count) * sizeof(float)) % BUFF_SIZE;
377}
378
387bool jack_receive(void *state, void *data)
388{
389 struct state_jack *s = (struct state_jack *) state;
390 struct pbuf_audio_data *audio_data = (struct pbuf_audio_data *) data;
391 struct audio_frame *buffer = &audio_data->buffer;
392
394 while(s->rec_buffer_start == s->rec_buffer_end);
395 //fprintf(stderr, "%d ", s->record.data_len);
396 int end = s->rec_buffer_end;
397
398 buffer->ch_count = s->record.ch_count;
399 buffer->bps = s->record.bps;
400 buffer->sample_rate = s->record.sample_rate;
401
402 buffer->data_len = end - s->rec_buffer_start;
403 if (buffer->data_len < 0) buffer->data_len += BUFF_SIZE;
404 buffer->data = (char *) malloc(buffer->data_len);
405
406 if (s->rec_buffer_start < end) {
407 memcpy(buffer->data, s->rec_buffer + s->rec_buffer_start,
408 buffer->data_len);
409 } else {
410 memcpy(buffer->data, s->rec_buffer + s->rec_buffer_start,
412 memcpy(buffer->data + BUFF_SIZE - s->rec_buffer_start,
413 s->rec_buffer,
414 buffer->data_len + BUFF_SIZE - s->rec_buffer_start);
415 }
417
418 return true;
419}
420
422{
423 return ((struct state_jack *) state)->sender;
424}
425
427{
428 return ((struct state_jack *) state)->receiver;
429}
430
void ** state
int int channels
struct video_frame * frame
This file contains definition of some common audio types.
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
#define MOD_NAME
Definition jack.c:54
@ MAX_PORTS
Definition jack.c:57
#define TRUE
#define FALSE
void log_msg(int level, const char *format,...)
Definition debug.cpp:130
#define LOG_LEVEL_NOTICE
information that may be interesting
Definition debug.h:61
#define LOG_LEVEL_ERROR
general errors
Definition debug.h:59
#define LOG_LEVEL_WARNING
less severe errors
Definition debug.h:60
void * jack_start(const char *cfg)
Definition jack.c:264
#define MAX_PORTS
Definition jack.c:59
static int attach_input_ports(struct state_jack *s)
Definition jack.c:237
int is_jack_receiver(void *state)
Definition jack.c:426
#define CLIENT_NAME
Definition jack.c:56
#define BUFF_SIZE
Definition jack.c:58
void reconfigure_send_ch_count(struct state_jack *s, int ch_count)
Definition jack.c:147
void jack_send(void *state, struct audio_frame *frame)
Definition jack.c:355
bool jack_receive(void *state, void *data)
Receives data from JACK.
Definition jack.c:387
static int settings_init(struct state_jack *s, char *cfg)
Definition jack.c:186
int is_jack_sender(void *state)
Definition jack.c:421
static void close_libjack(struct libjack_connection *s)
static struct libjack_connection * open_libjack(void)
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
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_disconnect_t disconnect
jack_set_process_callback_t set_process_callback
audio_frame buffer
Definition pbuf.h:99
unsigned int sender
Definition jack.c:65
int play_buffer_start
Definition jack.c:74
jack_port_t * input_port[MAX_PORTS]
Definition jack.c:78
int out_channel_count_req
Definition jack.c:86
struct audio_frame record
Definition jack.c:70
char * play_buffer[MAX_PORTS]
Definition jack.c:73
int play_buffer_end
Definition jack.c:74
char * rec_buffer
Definition jack.c:75
int in_ch_count
Definition jack.c:82
unsigned int receiver
Definition jack.c:66
int out_channel_count
Definition jack.c:85
char * out_port_pattern
Definition jack.c:84
jack_port_t * output_port[MAX_PORTS]
Definition jack.c:79
struct libjack_connection * libjack
Definition jack.c:63
char * in_port_pattern
Definition jack.c:81
volatile int rec_buffer_end
Definition jack.c:76
jack_client_t * client
Definition jack.c:68
volatile int rec_buffer_start
Definition jack.c:76