UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
jack.c File Reference
#include <jack/jack.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "audio/jack.h"
#include "audio/types.h"
#include "jack_common.h"
#include "pthread.h"
#include "rtp/pbuf.h"
#include "rtp/rtp.h"
Include dependency graph for jack.c:

Go to the source code of this file.

Classes

struct  state_jack
 

Macros

#define BUFF_ELEM   (1<<16)
 
#define BUFF_SIZE   (BUFF_ELEM * sizeof(float))
 
#define CLIENT_NAME   "UltraGrid Transport"
 
#define MAX_PORTS   8
 
#define MOD_NAME   "[JACK trans.] "
 

Functions

static int attach_input_ports (struct state_jack *s)
 
int is_jack_receiver (void *state)
 
int is_jack_sender (void *state)
 
int jack_process_callback (jack_nframes_t nframes, void *arg)
 
bool jack_receive (void *state, void *data)
 Receives data from JACK.
 
int jack_samplerate_changed_callback (jack_nframes_t nframes, void *arg)
 
void jack_send (void *state, struct audio_frame *frame)
 
void * jack_start (const char *cfg)
 
void reconfigure_send_ch_count (struct state_jack *s, int ch_count)
 
static int settings_init (struct state_jack *s, char *cfg)
 

Detailed Description

Author
Martin Pulec pulec.nosp@m.@ces.nosp@m.net.c.nosp@m.z
Todo
It looks like there is no jack_stop()?

Definition in file jack.c.

Macro Definition Documentation

◆ BUFF_ELEM

#define BUFF_ELEM   (1<<16)

Definition at line 57 of file jack.c.

◆ BUFF_SIZE

#define BUFF_SIZE   (BUFF_ELEM * sizeof(float))

◆ CLIENT_NAME

#define CLIENT_NAME   "UltraGrid Transport"

Definition at line 56 of file jack.c.

Referenced by jack_start().

◆ MAX_PORTS

#define MAX_PORTS   8

Definition at line 59 of file jack.c.

◆ MOD_NAME

#define MOD_NAME   "[JACK trans.] "

Definition at line 60 of file jack.c.

Function Documentation

◆ attach_input_ports()

static int attach_input_ports ( struct state_jack * s)
static

Definition at line 237 of file jack.c.

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}
#define MOD_NAME
Definition jack.c:54
#define TRUE
#define FALSE
void log_msg(int level, const char *format,...)
Definition debug.cpp:130
#define LOG_LEVEL_ERROR
general errors
Definition debug.h:59
int ch_count
Definition types.h:104
jack_connect_t connect
jack_port_name_t port_name
jack_get_ports_t get_ports
jack_port_t * input_port[MAX_PORTS]
Definition jack.c:78
struct audio_frame record
Definition jack.c:70
int in_ch_count
Definition jack.c:82
struct libjack_connection * libjack
Definition jack.c:63
char * in_port_pattern
Definition jack.c:81
jack_client_t * client
Definition jack.c:68

References audio_frame::ch_count, state_jack::client, libjack_connection::connect, FALSE, libjack_connection::get_ports, state_jack::in_ch_count, state_jack::in_port_pattern, state_jack::input_port, state_jack::libjack, LOG_LEVEL_ERROR, log_msg(), MOD_NAME, libjack_connection::port_name, state_jack::record, and TRUE.

Referenced by jack_start().

Here is the call graph for this function:

◆ is_jack_receiver()

int is_jack_receiver ( void * state)

Definition at line 426 of file jack.c.

427{
428 return ((struct state_jack *) state)->receiver;
429}
void ** state

References state.

Referenced by audio_start().

◆ is_jack_sender()

int is_jack_sender ( void * state)

Definition at line 421 of file jack.c.

422{
423 return ((struct state_jack *) state)->sender;
424}

References state.

Referenced by audio_start().

◆ jack_process_callback()

static int jack_process_callback ( jack_nframes_t nframes,
void * arg )

Definition at line 94 of file jack.c.

94 {
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}
#define BUFF_SIZE
Definition jack.c:58
jack_port_get_buffer_t port_get_buffer
int play_buffer_start
Definition jack.c:74
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 out_channel_count
Definition jack.c:85
jack_port_t * output_port[MAX_PORTS]
Definition jack.c:79
volatile int rec_buffer_end
Definition jack.c:76

References BUFF_SIZE, audio_frame::ch_count, state_jack::input_port, state_jack::libjack, state_jack::out_channel_count, state_jack::output_port, state_jack::play_buffer, state_jack::play_buffer_end, state_jack::play_buffer_start, libjack_connection::port_get_buffer, state_jack::rec_buffer, state_jack::rec_buffer_end, and state_jack::record.

◆ jack_receive()

bool jack_receive ( void * state,
void * data )

Receives data from JACK.

Parameters
[in]statestate returned by jack_init()
[out]datapbuf_audio_data
Return values
trueif some data are receied
falseif no data were receied
Todo
repair this

Definition at line 387 of file jack.c.

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}
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 data_len
Definition types.h:103
int bps
Definition types.h:100
audio_frame buffer
Definition pbuf.h:99
volatile int rec_buffer_start
Definition jack.c:76

References audio_frame::bps, BUFF_SIZE, pbuf_audio_data::buffer, audio_frame::ch_count, audio_frame::data, audio_frame::data_len, state_jack::rec_buffer, state_jack::rec_buffer_end, state_jack::rec_buffer_start, state_jack::record, audio_frame::sample_rate, and state.

Referenced by audio_receiver_thread().

◆ jack_samplerate_changed_callback()

static int jack_samplerate_changed_callback ( jack_nframes_t nframes,
void * arg )

Definition at line 140 of file jack.c.

140 {
141 struct state_jack *s = (struct state_jack *) arg;
142
143 s->record.sample_rate = nframes;
144 return 0;
145}

References state_jack::record, and audio_frame::sample_rate.

◆ jack_send()

void jack_send ( void * state,
struct audio_frame * frame )

Definition at line 355 of file jack.c.

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}
int int channels
struct video_frame * frame
void reconfigure_send_ch_count(struct state_jack *s, int ch_count)
Definition jack.c:147

References BUFF_SIZE, channels, frame, state_jack::out_channel_count, state_jack::play_buffer, state_jack::play_buffer_end, reconfigure_send_ch_count(), and state.

Referenced by audio_sender_thread().

Here is the call graph for this function:

◆ jack_start()

void * jack_start ( const char * cfg)

Definition at line 264 of file jack.c.

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
303 if(s->libjack->set_sample_rate_callback(s->client,
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
320 s->out_channel_count = s->out_channel_count_req = 0;
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
332 s->record.sample_rate = s->libjack->get_sample_rate (s->client);
333 s->record.bps = sizeof(int32_t);
334 s->record.ch_count = s->in_ch_count;
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:
350 close_libjack(s->libjack);
351 free(s);
352 return NULL;
353}
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
@ MAX_PORTS
Definition jack.c:57
static int attach_input_ports(struct state_jack *s)
Definition jack.c:237
#define CLIENT_NAME
Definition jack.c:56
static int settings_init(struct state_jack *s, char *cfg)
Definition jack.c:186
static void close_libjack(struct libjack_connection *s)
static struct libjack_connection * open_libjack(void)
const char * name
Definition settings.cpp:193
jack_client_open_t client_open
jack_set_process_callback_t set_process_callback
unsigned int sender
Definition jack.c:65
unsigned int receiver
Definition jack.c:66
char * out_port_pattern
Definition jack.c:84

References libjack_connection::activate, attach_input_ports(), audio_frame::bps, BUFF_SIZE, audio_frame::ch_count, state_jack::client, CLIENT_NAME, libjack_connection::client_open, close_libjack(), audio_frame::data, FALSE, libjack_connection::get_sample_rate, state_jack::in_ch_count, state_jack::in_port_pattern, state_jack::input_port, jack_process_callback(), jack_samplerate_changed_callback(), state_jack::libjack, LOG_LEVEL_ERROR, log_msg(), MAX_PORTS, MOD_NAME, name, open_libjack(), state_jack::out_channel_count, state_jack::out_channel_count_req, state_jack::out_port_pattern, state_jack::output_port, state_jack::play_buffer_end, state_jack::play_buffer_start, libjack_connection::port_register, state_jack::rec_buffer, state_jack::rec_buffer_end, state_jack::rec_buffer_start, state_jack::receiver, state_jack::record, audio_frame::sample_rate, state_jack::sender, libjack_connection::set_process_callback, libjack_connection::set_sample_rate_callback, and settings_init().

Referenced by audio_start().

Here is the call graph for this function:

◆ reconfigure_send_ch_count()

void reconfigure_send_ch_count ( struct state_jack * s,
int ch_count )

Definition at line 147 of file jack.c.

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}
#define LOG_LEVEL_NOTICE
information that may be interesting
Definition debug.h:61
#define LOG_LEVEL_WARNING
less severe errors
Definition debug.h:60
jack_disconnect_t disconnect
int out_channel_count_req
Definition jack.c:86

References BUFF_SIZE, audio_frame::ch_count, state_jack::client, libjack_connection::connect, libjack_connection::disconnect, libjack_connection::get_ports, state_jack::libjack, LOG_LEVEL_ERROR, LOG_LEVEL_NOTICE, LOG_LEVEL_WARNING, log_msg(), MOD_NAME, state_jack::out_channel_count, state_jack::out_channel_count_req, state_jack::out_port_pattern, state_jack::output_port, state_jack::play_buffer, libjack_connection::port_name, and state_jack::record.

Referenced by jack_send().

Here is the call graph for this function:

◆ settings_init()

static int settings_init ( struct state_jack * s,
char * cfg )
static

Definition at line 186 of file jack.c.

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}

References state_jack::in_ch_count, state_jack::in_port_pattern, state_jack::out_port_pattern, state_jack::receiver, state_jack::sender, and TRUE.

Referenced by display_decklink_init(), and jack_start().