Asterisk - The Open Source Telephony Project GIT-master-a63eec2
Loading...
Searching...
No Matches
Data Structures | Macros | Enumerations | Functions | Variables
app_jack.c File Reference

Jack Application. More...

#include "asterisk.h"
#include <limits.h>
#include <jack/jack.h>
#include <jack/ringbuffer.h>
#include <libresample.h>
#include "asterisk/module.h"
#include "asterisk/channel.h"
#include "asterisk/strings.h"
#include "asterisk/lock.h"
#include "asterisk/app.h"
#include "asterisk/pbx.h"
#include "asterisk/audiohook.h"
#include "asterisk/format_cache.h"
Include dependency graph for app_jack.c:

Go to the source code of this file.

Data Structures

struct  jack_data
 

Macros

#define COMMON_OPTIONS
 Common options between the Jack() app and JACK_HOOK() function.
 
#define RESAMPLE_QUALITY   1
 
#define RINGBUFFER_FRAME_CAPACITY   100
 

Enumerations

enum  {
  OPT_SERVER_NAME = (1 << 0) , OPT_INPUT_PORT = (1 << 1) , OPT_OUTPUT_PORT = (1 << 2) , OPT_NOSTART_SERVER = (1 << 3) ,
  OPT_CLIENT_NAME = (1 << 4)
}
 
enum  {
  OPT_ARG_SERVER_NAME , OPT_ARG_INPUT_PORT , OPT_ARG_OUTPUT_PORT , OPT_ARG_CLIENT_NAME ,
  OPT_ARG_ARRAY_SIZE
}
 

Functions

static int alloc_resampler (struct jack_data *jack_data, int input)
 
 AST_MODULE_INFO_STANDARD_EXTENDED (ASTERISK_GPL_KEY, "JACK Interface")
 
static struct jack_datadestroy_jack_data (struct jack_data *jack_data)
 
static int disable_jack_hook (struct ast_channel *chan)
 
static int enable_jack_hook (struct ast_channel *chan, char *data)
 
static void handle_input (void *buf, jack_nframes_t nframes, struct jack_data *jack_data)
 Handle jack input port.
 
static void handle_jack_audio (struct ast_channel *chan, struct jack_data *jack_data, struct ast_frame *out_frame)
 handle jack audio
 
static int handle_options (struct jack_data *jack_data, const char *__options_str)
 
static void handle_output (void *buf, jack_nframes_t nframes, struct jack_data *jack_data)
 Handle jack output port.
 
static int init_jack_data (struct ast_channel *chan, struct jack_data *jack_data)
 
static struct jack_datajack_data_alloc (void)
 
static int jack_exec (struct ast_channel *chan, const char *data)
 
static int jack_hook_callback (struct ast_audiohook *audiohook, struct ast_channel *chan, struct ast_frame *frame, enum ast_audiohook_direction direction)
 
static void jack_hook_ds_destroy (void *data)
 
static int jack_hook_write (struct ast_channel *chan, const char *cmd, char *data, const char *value)
 
static int jack_process (jack_nframes_t nframes, void *arg)
 
static void jack_shutdown (void *arg)
 
static const char * jack_status_to_str (jack_status_t status)
 
static int load_module (void)
 
static void log_jack_status (const char *prefix, jack_status_t status)
 
static int queue_voice_frame (struct jack_data *jack_data, struct ast_frame *f)
 
static int unload_module (void)
 

Variables

static const char jack_app [] = "JACK"
 
static const struct ast_app_option jack_exec_options [128] = { [ 's' ] = { .flag = OPT_SERVER_NAME , .arg_index = OPT_ARG_SERVER_NAME + 1 }, [ 'i' ] = { .flag = OPT_INPUT_PORT , .arg_index = OPT_ARG_INPUT_PORT + 1 }, [ 'o' ] = { .flag = OPT_OUTPUT_PORT , .arg_index = OPT_ARG_OUTPUT_PORT + 1 }, [ 'n' ] = { .flag = OPT_NOSTART_SERVER }, [ 'c' ] = { .flag = OPT_CLIENT_NAME , .arg_index = OPT_ARG_CLIENT_NAME + 1 }, }
 
static const struct ast_datastore_info jack_hook_ds_info
 
static struct ast_custom_function jack_hook_function
 
struct { 
 
   jack_status_t   status 
 
   const char *   str 
 
jack_status_table [] 
 

Detailed Description

Jack Application.

Author
Russell Bryant russe.nosp@m.ll@d.nosp@m.igium.nosp@m..com

This is an application to connect an Asterisk channel to an input and output jack port so that the audio can be processed through another application, or to play audio from another application.

ExtRef:
http://www.jackaudio.org/
Note
To install libresample, check it out of the following repository: $ svn co http://svn.digium.com/svn/thirdparty/libresample/trunk

Definition in file app_jack.c.

Macro Definition Documentation

◆ COMMON_OPTIONS

#define COMMON_OPTIONS

Common options between the Jack() app and JACK_HOOK() function.

Definition at line 67 of file app_jack.c.

122 {
124 AST_STRING_FIELD(server_name);
125 AST_STRING_FIELD(client_name);
126 AST_STRING_FIELD(connect_input_port);
127 AST_STRING_FIELD(connect_output_port);
128 );
129 jack_client_t *client;
130 jack_port_t *input_port;
131 jack_port_t *output_port;
132 jack_ringbuffer_t *input_rb;
133 jack_ringbuffer_t *output_rb;
134 struct ast_format *audiohook_format;
135 unsigned int audiohook_rate;
136 unsigned int frame_datalen;
137 void *output_resampler;
138 double output_resample_factor;
139 void *input_resampler;
140 double input_resample_factor;
141 unsigned int stop:1;
142 unsigned int has_audiohook:1;
143 unsigned int no_start_server:1;
144 /*! Only used with JACK_HOOK */
145 struct ast_audiohook audiohook;
146};
147
148static const struct {
149 jack_status_t status;
150 const char *str;
151} jack_status_table[] = {
152 { JackFailure, "Failure" },
153 { JackInvalidOption, "Invalid Option" },
154 { JackNameNotUnique, "Name Not Unique" },
155 { JackServerStarted, "Server Started" },
156 { JackServerFailed, "Server Failed" },
157 { JackServerError, "Server Error" },
158 { JackNoSuchClient, "No Such Client" },
159 { JackLoadFailure, "Load Failure" },
160 { JackInitFailure, "Init Failure" },
161 { JackShmFailure, "Shared Memory Access Failure" },
162 { JackVersionError, "Version Mismatch" },
163};
164
165static const char *jack_status_to_str(jack_status_t status)
166{
167 int i;
168
169 for (i = 0; i < ARRAY_LEN(jack_status_table); i++) {
171 return jack_status_table[i].str;
172 }
173
174 return "Unknown Error";
175}
176
177static void log_jack_status(const char *prefix, jack_status_t status)
178{
179 struct ast_str *str = ast_str_alloca(512);
180 int i, first = 0;
181
182 for (i = 0; i < (sizeof(status) * 8); i++) {
183 if (!(status & (1 << i)))
184 continue;
185
186 if (!first) {
187 ast_str_set(&str, 0, "%s", jack_status_to_str((1 << i)));
188 first = 1;
189 } else
190 ast_str_append(&str, 0, ", %s", jack_status_to_str((1 << i)));
191 }
192
194}
195
196static int alloc_resampler(struct jack_data *jack_data, int input)
197{
198 double from_srate, to_srate, jack_srate;
199 void **resampler;
200 double *resample_factor;
201
202 if (input && jack_data->input_resampler)
203 return 0;
204
205 if (!input && jack_data->output_resampler)
206 return 0;
207
208 jack_srate = jack_get_sample_rate(jack_data->client);
209
210 to_srate = input ? jack_data->audiohook_rate : jack_srate;
211 from_srate = input ? jack_srate : jack_data->audiohook_rate;
212
213 resample_factor = input ? &jack_data->input_resample_factor :
215
216 if (from_srate == to_srate) {
217 /* Awesome! The jack sample rate is the same as ours.
218 * Resampling isn't needed. */
219 *resample_factor = 1.0;
220 return 0;
221 }
222
223 *resample_factor = to_srate / from_srate;
224
225 resampler = input ? &jack_data->input_resampler :
227
228 if (!(*resampler = resample_open(RESAMPLE_QUALITY,
229 *resample_factor, *resample_factor))) {
230 ast_log(LOG_ERROR, "Failed to open %s resampler\n",
231 input ? "input" : "output");
232 return -1;
233 }
234
235 return 0;
236}
237
238/*!
239 * \brief Handle jack input port
240 *
241 * Read nframes number of samples from the input buffer, resample it
242 * if necessary, and write it into the appropriate ringbuffer.
243 */
244static void handle_input(void *buf, jack_nframes_t nframes,
245 struct jack_data *jack_data)
246{
247 short s_buf[nframes];
248 float *in_buf = buf;
249 size_t res;
250 int i;
251 size_t write_len = sizeof(s_buf);
252
254 int total_in_buf_used = 0;
255 int total_out_buf_used = 0;
256 float f_buf[nframes + 1];
257
258 memset(f_buf, 0, sizeof(f_buf));
259
260 while (total_in_buf_used < nframes) {
261 int in_buf_used;
262 int out_buf_used;
263
264 out_buf_used = resample_process(jack_data->input_resampler,
266 &in_buf[total_in_buf_used], nframes - total_in_buf_used,
267 0, &in_buf_used,
268 &f_buf[total_out_buf_used], ARRAY_LEN(f_buf) - total_out_buf_used);
269
270 if (out_buf_used < 0)
271 break;
272
273 total_out_buf_used += out_buf_used;
274 total_in_buf_used += in_buf_used;
275
276 if (total_out_buf_used == ARRAY_LEN(f_buf)) {
277 ast_log(LOG_ERROR, "Output buffer filled ... need to increase its size, "
278 "nframes '%d', total_out_buf_used '%d'\n", nframes, total_out_buf_used);
279 break;
280 }
281 }
282
283 for (i = 0; i < total_out_buf_used; i++)
284 s_buf[i] = f_buf[i] * (SHRT_MAX / 1.0);
285
286 write_len = total_out_buf_used * sizeof(int16_t);
287 } else {
288 /* No resampling needed */
289
290 for (i = 0; i < nframes; i++)
291 s_buf[i] = in_buf[i] * (SHRT_MAX / 1.0);
292 }
293
294 res = jack_ringbuffer_write(jack_data->input_rb, (const char *) s_buf, write_len);
295 if (res != write_len) {
296 ast_log(LOG_WARNING, "Tried to write %d bytes to the ringbuffer, but only wrote %d\n",
297 (int) sizeof(s_buf), (int) res);
298 }
299}
300
301/*!
302 * \brief Handle jack output port
303 *
304 * Read nframes number of samples from the ringbuffer and write it out to the
305 * output port buffer.
306 */
307static void handle_output(void *buf, jack_nframes_t nframes,
308 struct jack_data *jack_data)
309{
310 size_t res, len;
311
312 len = nframes * sizeof(float);
313
314 res = jack_ringbuffer_read(jack_data->output_rb, buf, len);
315
316 if (len != res) {
317 ast_debug(2, "Wanted %d bytes to send to the output port, "
318 "but only got %d\n", (int) len, (int) res);
319 }
320}
321
322static int jack_process(jack_nframes_t nframes, void *arg)
323{
324 struct jack_data *jack_data = arg;
325 void *input_port_buf, *output_port_buf;
326
329
330 input_port_buf = jack_port_get_buffer(jack_data->input_port, nframes);
331 handle_input(input_port_buf, nframes, jack_data);
332
333 output_port_buf = jack_port_get_buffer(jack_data->output_port, nframes);
334 handle_output(output_port_buf, nframes, jack_data);
335
336 return 0;
337}
338
339static void jack_shutdown(void *arg)
340{
341 struct jack_data *jack_data = arg;
342
343 jack_data->stop = 1;
344}
345
346static struct jack_data *destroy_jack_data(struct jack_data *jack_data)
347{
348 if (jack_data->input_port) {
349 jack_port_unregister(jack_data->client, jack_data->input_port);
351 }
352
353 if (jack_data->output_port) {
354 jack_port_unregister(jack_data->client, jack_data->output_port);
356 }
357
358 if (jack_data->client) {
359 jack_client_close(jack_data->client);
361 }
362
363 if (jack_data->input_rb) {
364 jack_ringbuffer_free(jack_data->input_rb);
366 }
367
368 if (jack_data->output_rb) {
369 jack_ringbuffer_free(jack_data->output_rb);
371 }
372
374 resample_close(jack_data->output_resampler);
376 }
377
379 resample_close(jack_data->input_resampler);
381 }
382
385
387
389
390 return NULL;
391}
392
393static int init_jack_data(struct ast_channel *chan, struct jack_data *jack_data)
394{
395 const char *client_name;
396 jack_status_t status = 0;
397 jack_options_t jack_options = JackNullOption;
398
399 unsigned int channel_rate;
400
401 unsigned int ringbuffer_size;
402
403 /* Deducing audiohook sample rate from channel format
404 ATTENTION: Might be problematic, if channel has different sampling than used by audiohook!
405 */
409
410 /* Guessing frame->datalen assuming a ptime of 20ms */
412
414
415 ast_debug(1, "Audiohook parameters: slin-format:%s, rate:%d, frame-len:%d, ringbuffer_size: %d\n",
417
420 } else {
421 ast_channel_lock(chan);
423 ast_channel_unlock(chan);
424 }
425
426 if (!(jack_data->output_rb = jack_ringbuffer_create(ringbuffer_size)))
427 return -1;
428
429 if (!(jack_data->input_rb = jack_ringbuffer_create(ringbuffer_size)))
430 return -1;
431
433 jack_options |= JackNoStartServer;
434
436 jack_options |= JackServerName;
437 jack_data->client = jack_client_open(client_name, jack_options, &status,
439 } else {
440 jack_data->client = jack_client_open(client_name, jack_options, &status);
441 }
442
443 if (status)
444 log_jack_status("Client Open Status", status);
445
446 if (!jack_data->client)
447 return -1;
448
449 jack_data->input_port = jack_port_register(jack_data->client, "input",
450 JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput | JackPortIsTerminal, 0);
451 if (!jack_data->input_port) {
452 ast_log(LOG_ERROR, "Failed to create input port for jack port\n");
453 return -1;
454 }
455
456 jack_data->output_port = jack_port_register(jack_data->client, "output",
457 JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput | JackPortIsTerminal, 0);
458 if (!jack_data->output_port) {
459 ast_log(LOG_ERROR, "Failed to create output port for jack port\n");
460 return -1;
461 }
462
463 if (jack_set_process_callback(jack_data->client, jack_process, jack_data)) {
464 ast_log(LOG_ERROR, "Failed to register process callback with jack client\n");
465 return -1;
466 }
467
468 jack_on_shutdown(jack_data->client, jack_shutdown, jack_data);
469
470 if (jack_activate(jack_data->client)) {
471 ast_log(LOG_ERROR, "Unable to activate jack client\n");
472 return -1;
473 }
474
476 const char **ports;
477 int i;
478
479 ports = jack_get_ports(jack_data->client, jack_data->connect_input_port,
480 NULL, JackPortIsInput);
481
482 if (!ports) {
483 ast_log(LOG_ERROR, "No input port matching '%s' was found\n",
485 break;
486 }
487
488 for (i = 0; ports[i]; i++) {
489 ast_debug(1, "Found port '%s' that matched specified input port '%s'\n",
490 ports[i], jack_data->connect_input_port);
491 }
492
493 if (jack_connect(jack_data->client, jack_port_name(jack_data->output_port), ports[0])) {
494 ast_log(LOG_ERROR, "Failed to connect '%s' to '%s'\n", ports[0],
495 jack_port_name(jack_data->output_port));
496 } else {
497 ast_debug(1, "Connected '%s' to '%s'\n", ports[0],
498 jack_port_name(jack_data->output_port));
499 }
500
501 jack_free(ports);
502
503 break;
504 }
505
507 const char **ports;
508 int i;
509
510 ports = jack_get_ports(jack_data->client, jack_data->connect_output_port,
511 NULL, JackPortIsOutput);
512
513 if (!ports) {
514 ast_log(LOG_ERROR, "No output port matching '%s' was found\n",
516 break;
517 }
518
519 for (i = 0; ports[i]; i++) {
520 ast_debug(1, "Found port '%s' that matched specified output port '%s'\n",
521 ports[i], jack_data->connect_output_port);
522 }
523
524 if (jack_connect(jack_data->client, ports[0], jack_port_name(jack_data->input_port))) {
525 ast_log(LOG_ERROR, "Failed to connect '%s' to '%s'\n", ports[0],
526 jack_port_name(jack_data->input_port));
527 } else {
528 ast_debug(1, "Connected '%s' to '%s'\n", ports[0],
529 jack_port_name(jack_data->input_port));
530 }
531
532 jack_free(ports);
533
534 break;
535 }
536
537 return 0;
538}
539
540static int queue_voice_frame(struct jack_data *jack_data, struct ast_frame *f)
541{
542 float f_buf[f->samples * 8];
543 size_t f_buf_used = 0;
544 int i;
545 int16_t *s_buf = f->data.ptr;
546 size_t res;
547
548 memset(f_buf, 0, sizeof(f_buf));
549
552
554 float in_buf[f->samples];
555 int total_in_buf_used = 0;
556 int total_out_buf_used = 0;
557
558 memset(in_buf, 0, sizeof(in_buf));
559
560 for (i = 0; i < f->samples; i++)
561 in_buf[i] = s_buf[i] * (1.0 / SHRT_MAX);
562
563 while (total_in_buf_used < ARRAY_LEN(in_buf)) {
564 int in_buf_used;
565 int out_buf_used;
566
567 out_buf_used = resample_process(jack_data->output_resampler,
569 &in_buf[total_in_buf_used], ARRAY_LEN(in_buf) - total_in_buf_used,
570 0, &in_buf_used,
571 &f_buf[total_out_buf_used], ARRAY_LEN(f_buf) - total_out_buf_used);
572
573 if (out_buf_used < 0)
574 break;
575
576 total_out_buf_used += out_buf_used;
577 total_in_buf_used += in_buf_used;
578
579 if (total_out_buf_used == ARRAY_LEN(f_buf)) {
580 ast_log(LOG_ERROR, "Output buffer filled ... need to increase its size\n");
581 break;
582 }
583 }
584
585 f_buf_used = total_out_buf_used;
586 if (f_buf_used > ARRAY_LEN(f_buf))
587 f_buf_used = ARRAY_LEN(f_buf);
588 } else {
589 /* No resampling needed */
590
591 for (i = 0; i < f->samples; i++)
592 f_buf[i] = s_buf[i] * (1.0 / SHRT_MAX);
593
594 f_buf_used = f->samples;
595 }
596
597 res = jack_ringbuffer_write(jack_data->output_rb, (const char *) f_buf, f_buf_used * sizeof(float));
598 if (res != (f_buf_used * sizeof(float))) {
599 ast_log(LOG_WARNING, "Tried to write %d bytes to the ringbuffer, but only wrote %d\n",
600 (int) (f_buf_used * sizeof(float)), (int) res);
601 }
602 return 0;
603}
604
605/*!
606 * \brief handle jack audio
607 *
608 * \param[in] chan The Asterisk channel to write the frames to if no output frame
609 * is provided.
610 * \param[in] jack_data This is the jack_data struct that contains the input
611 * ringbuffer that audio will be read from.
612 * \param[out] out_frame If this argument is non-NULL, then assuming there is
613 * enough data available in the ringbuffer, the audio in this frame
614 * will get replaced with audio from the input buffer. If there is
615 * not enough data available to read at this time, then the frame
616 * data gets zeroed out.
617 *
618 * Read data from the input ringbuffer, which is the properly resampled audio
619 * that was read from the jack input port. Write it to the channel in 20 ms frames,
620 * or fill up an output frame instead if one is provided.
621 */
622static void handle_jack_audio(struct ast_channel *chan, struct jack_data *jack_data,
623 struct ast_frame *out_frame)
624{
626 struct ast_frame f = {
628 .subclass.format = jack_data->audiohook_format,
629 .src = "JACK",
630 .data.ptr = buf,
631 .datalen = sizeof(buf),
633 };
634
635 for (;;) {
636 size_t res, read_len;
637 char *read_buf;
638
639 read_len = out_frame ? out_frame->datalen : sizeof(buf);
640 read_buf = out_frame ? out_frame->data.ptr : buf;
641
642 res = jack_ringbuffer_read_space(jack_data->input_rb);
643
644 if (res < read_len) {
645 /* Not enough data ready for another frame, move on ... */
646 if (out_frame) {
647 ast_debug(1, "Sending an empty frame for the JACK_HOOK\n");
648 memset(out_frame->data.ptr, 0, out_frame->datalen);
649 }
650 break;
651 }
652
653 res = jack_ringbuffer_read(jack_data->input_rb, (char *) read_buf, read_len);
654
655 if (res < read_len) {
656 ast_log(LOG_ERROR, "Error reading from ringbuffer, even though it said there was enough data\n");
657 break;
658 }
659
660 if (out_frame) {
661 /* If an output frame was provided, then we just want to fill up the
662 * buffer in that frame and return. */
663 break;
664 }
665
666 ast_write(chan, &f);
667 }
668}
669
670enum {
671 OPT_SERVER_NAME = (1 << 0),
672 OPT_INPUT_PORT = (1 << 1),
673 OPT_OUTPUT_PORT = (1 << 2),
674 OPT_NOSTART_SERVER = (1 << 3),
675 OPT_CLIENT_NAME = (1 << 4),
676};
677
678enum {
683
684 /* Must be the last element */
686};
687
695
696static struct jack_data *jack_data_alloc(void)
697{
698 struct jack_data *jack_data;
699
700 if (!(jack_data = ast_calloc_with_stringfields(1, struct jack_data, 32))) {
701 return NULL;
702 }
703
704 return jack_data;
705}
706
707/*!
708 * \note This must be done before calling init_jack_data().
709 */
710static int handle_options(struct jack_data *jack_data, const char *__options_str)
711{
712 struct ast_flags options = { 0, };
714 char *options_str;
715
716 options_str = ast_strdupa(__options_str);
717
719
723 else {
724 ast_log(LOG_ERROR, "A server name must be provided with the s() option\n");
725 return -1;
726 }
727 }
728
732 else {
733 ast_log(LOG_ERROR, "A client name must be provided with the c() option\n");
734 return -1;
735 }
736 }
737
741 else {
742 ast_log(LOG_ERROR, "A name must be provided with the i() option\n");
743 return -1;
744 }
745 }
746
750 else {
751 ast_log(LOG_ERROR, "A name must be provided with the o() option\n");
752 return -1;
753 }
754 }
755
757
758 return 0;
759}
760
761static int jack_exec(struct ast_channel *chan, const char *data)
762{
763 struct jack_data *jack_data;
764
765 if (!(jack_data = jack_data_alloc()))
766 return -1;
767
768 if (!ast_strlen_zero(data) && handle_options(jack_data, data)) {
770 return -1;
771 }
772
773 if (init_jack_data(chan, jack_data)) {
775 return -1;
776 }
777
780 return -1;
781 }
782
785 return -1;
786 }
787
788 while (!jack_data->stop) {
789 struct ast_frame *f;
790
791 if (ast_waitfor(chan, -1) < 0) {
792 break;
793 }
794
795 f = ast_read(chan);
796 if (!f) {
797 jack_data->stop = 1;
798 continue;
799 }
800
801 switch (f->frametype) {
804 jack_data->stop = 1;
805 break;
806 case AST_FRAME_VOICE:
808 default:
809 break;
810 }
811
812 ast_frfree(f);
813
815 }
816
818
819 return 0;
820}
821
822static void jack_hook_ds_destroy(void *data)
823{
824 struct jack_data *jack_data = data;
825
827}
828
829static const struct ast_datastore_info jack_hook_ds_info = {
830 .type = "JACK_HOOK",
831 .destroy = jack_hook_ds_destroy,
832};
833
834static int jack_hook_callback(struct ast_audiohook *audiohook, struct ast_channel *chan,
835 struct ast_frame *frame, enum ast_audiohook_direction direction)
836{
837 struct ast_datastore *datastore;
838 struct jack_data *jack_data;
839
841 return 0;
842
844 return 0;
845
846 if (frame->frametype != AST_FRAME_VOICE)
847 return 0;
848
849 ast_channel_lock(chan);
850
851 if (!(datastore = ast_channel_datastore_find(chan, &jack_hook_ds_info, NULL))) {
852 ast_log(LOG_ERROR, "JACK_HOOK datastore not found for '%s'\n", ast_channel_name(chan));
853 ast_channel_unlock(chan);
854 return -1;
855 }
856
857 jack_data = datastore->data;
858
860 ast_log(LOG_WARNING, "Expected frame in %s for the audiohook, but got format %s\n",
863 ast_channel_unlock(chan);
864 return 0;
865 }
866
868
869 handle_jack_audio(chan, jack_data, frame);
870
871 ast_channel_unlock(chan);
872
873 return 0;
874}
875
876static int enable_jack_hook(struct ast_channel *chan, char *data)
877{
878 struct ast_datastore *datastore;
879 struct jack_data *jack_data = NULL;
881 AST_APP_ARG(mode);
883 );
884
886
887 ast_channel_lock(chan);
888
889 if ((datastore = ast_channel_datastore_find(chan, &jack_hook_ds_info, NULL))) {
890 ast_log(LOG_ERROR, "JACK_HOOK already enabled for '%s'\n", ast_channel_name(chan));
891 goto return_error;
892 }
893
894 if (ast_strlen_zero(args.mode) || strcasecmp(args.mode, "manipulate")) {
895 ast_log(LOG_ERROR, "'%s' is not a supported mode. Only manipulate is supported.\n",
896 S_OR(args.mode, "<none>"));
897 goto return_error;
898 }
899
900 if (!(jack_data = jack_data_alloc()))
901 goto return_error;
902
903 if (!ast_strlen_zero(args.options) && handle_options(jack_data, args.options))
904 goto return_error;
905
906 if (init_jack_data(chan, jack_data))
907 goto return_error;
908
909 if (!(datastore = ast_datastore_alloc(&jack_hook_ds_info, NULL)))
910 goto return_error;
911
915
916 datastore->data = jack_data;
917
919 goto return_error;
920
921 if (ast_channel_datastore_add(chan, datastore))
922 goto return_error;
923
924 ast_channel_unlock(chan);
925
926 return 0;
927
928return_error:
929 ast_channel_unlock(chan);
930
931 if (jack_data) {
933 }
934
935 if (datastore) {
936 datastore->data = NULL;
937 ast_datastore_free(datastore);
938 }
939
940 return -1;
941}
942
943static int disable_jack_hook(struct ast_channel *chan)
944{
945 struct ast_datastore *datastore;
946 struct jack_data *jack_data;
947
948 ast_channel_lock(chan);
949
950 if (!(datastore = ast_channel_datastore_find(chan, &jack_hook_ds_info, NULL))) {
951 ast_channel_unlock(chan);
952 ast_log(LOG_WARNING, "No JACK_HOOK found to disable\n");
953 return -1;
954 }
955
956 ast_channel_datastore_remove(chan, datastore);
957
958 jack_data = datastore->data;
960
961 /* Keep the channel locked while we destroy the datastore, so that we can
962 * ensure that all of the jack stuff is stopped just in case another frame
963 * tries to come through the audiohook callback. */
964 ast_datastore_free(datastore);
965
966 ast_channel_unlock(chan);
967
968 return 0;
969}
970
971static int jack_hook_write(struct ast_channel *chan, const char *cmd, char *data,
972 const char *value)
973{
974 int res;
975
976 if (!chan) {
977 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
978 return -1;
979 }
980
981 if (!strcasecmp(value, "on"))
982 res = enable_jack_hook(chan, data);
983 else if (!strcasecmp(value, "off"))
984 res = disable_jack_hook(chan);
985 else {
986 ast_log(LOG_ERROR, "'%s' is not a valid value for JACK_HOOK()\n", value);
987 res = -1;
988 }
989
990 return res;
991}
992
994 .name = "JACK_HOOK",
995 .synopsis = "Enable a jack hook on a channel",
996 .syntax = "JACK_HOOK(<mode>,[options])",
997 .desc =
998 " The JACK_HOOK allows turning on or off jack connectivity to this channel.\n"
999 "When the JACK_HOOK is turned on, jack ports will get created that allow\n"
1000 "access to the audio stream for this channel. The mode specifies which mode\n"
1001 "this hook should run in. A mode must be specified when turning the JACK_HOOK.\n"
1002 "on. However, all arguments are optional when turning it off.\n"
1003 "\n"
1004 " Valid modes are:\n"
1005#if 0
1006 /* XXX TODO */
1007 " spy - Create a read-only audio hook. Only an output jack port will\n"
1008 " get created.\n"
1009 " whisper - Create a write-only audio hook. Only an input jack port will\n"
1010 " get created.\n"
1011#endif
1012 " manipulate - Create a read/write audio hook. Both an input and an output\n"
1013 " jack port will get created. Audio from the channel will be\n"
1014 " sent out the output port and will be replaced by the audio\n"
1015 " coming in on the input port as it gets passed on.\n"
1016 "\n"
1017 " Valid options are:\n"
1019 "\n"
1020 " Examples:\n"
1021 " To turn on the JACK_HOOK,\n"
1022 " Set(JACK_HOOK(manipulate,i(pure_data_0:input0)o(pure_data_0:output0))=on)\n"
1023 " To turn off the JACK_HOOK,\n"
1024 " Set(JACK_HOOK()=off)\n"
1025 "",
1026 .write = jack_hook_write,
1027};
1028
1029static int unload_module(void)
1030{
1031 int res;
1032
1035
1036 return res;
1037}
1038
1039static int load_module(void)
1040{
1043 }
1044
1048 }
1049
1051}
1052
static struct jack_data * destroy_jack_data(struct jack_data *jack_data)
Definition app_jack.c:346
static int queue_voice_frame(struct jack_data *jack_data, struct ast_frame *f)
Definition app_jack.c:540
@ OPT_ARG_CLIENT_NAME
Definition app_jack.c:682
@ OPT_ARG_SERVER_NAME
Definition app_jack.c:679
@ OPT_ARG_OUTPUT_PORT
Definition app_jack.c:681
@ OPT_ARG_INPUT_PORT
Definition app_jack.c:680
@ OPT_ARG_ARRAY_SIZE
Definition app_jack.c:685
static int jack_process(jack_nframes_t nframes, void *arg)
Definition app_jack.c:322
static void handle_output(void *buf, jack_nframes_t nframes, struct jack_data *jack_data)
Handle jack output port.
Definition app_jack.c:307
#define COMMON_OPTIONS
Common options between the Jack() app and JACK_HOOK() function.
Definition app_jack.c:67
static const struct ast_datastore_info jack_hook_ds_info
Definition app_jack.c:829
static const char * jack_status_to_str(jack_status_t status)
Definition app_jack.c:165
static int disable_jack_hook(struct ast_channel *chan)
Definition app_jack.c:943
static void handle_input(void *buf, jack_nframes_t nframes, struct jack_data *jack_data)
Handle jack input port.
Definition app_jack.c:244
static int enable_jack_hook(struct ast_channel *chan, char *data)
Definition app_jack.c:876
static void jack_hook_ds_destroy(void *data)
Definition app_jack.c:822
static int handle_options(struct jack_data *jack_data, const char *__options_str)
Definition app_jack.c:710
static struct ast_custom_function jack_hook_function
Definition app_jack.c:993
static int init_jack_data(struct ast_channel *chan, struct jack_data *jack_data)
Definition app_jack.c:393
static struct jack_data * jack_data_alloc(void)
Definition app_jack.c:696
static int jack_exec(struct ast_channel *chan, const char *data)
Definition app_jack.c:761
static int jack_hook_callback(struct ast_audiohook *audiohook, struct ast_channel *chan, struct ast_frame *frame, enum ast_audiohook_direction direction)
Definition app_jack.c:834
#define RINGBUFFER_FRAME_CAPACITY
Definition app_jack.c:64
static int jack_hook_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
Definition app_jack.c:971
static void handle_jack_audio(struct ast_channel *chan, struct jack_data *jack_data, struct ast_frame *out_frame)
handle jack audio
Definition app_jack.c:622
#define RESAMPLE_QUALITY
Definition app_jack.c:61
static void jack_shutdown(void *arg)
Definition app_jack.c:339
@ OPT_CLIENT_NAME
Definition app_jack.c:675
@ OPT_SERVER_NAME
Definition app_jack.c:671
@ OPT_INPUT_PORT
Definition app_jack.c:672
@ OPT_OUTPUT_PORT
Definition app_jack.c:673
@ OPT_NOSTART_SERVER
Definition app_jack.c:674
static void log_jack_status(const char *prefix, jack_status_t status)
Definition app_jack.c:177
jack_status_t status
Definition app_jack.c:149
static int load_module(void)
Definition app_jack.c:1039
static const struct ast_app_option jack_exec_options[128]
Definition app_jack.c:694
static int unload_module(void)
Definition app_jack.c:1029
static const char jack_app[]
Definition app_jack.c:120
static const struct @28 jack_status_table[]
static int alloc_resampler(struct jack_data *jack_data, int input)
Definition app_jack.c:196
const char * str
Definition app_jack.c:150
option_args
Definition app_skel.c:184
unsigned int stop
Definition app_sla.c:342
struct sla_ringing_trunk * first
Definition app_sla.c:338
#define ast_free(a)
Definition astmm.h:180
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition astmm.h:298
#define ast_log
Definition astobj2.c:42
@ AST_AUDIOHOOK_MANIPULATE_ALL_RATES
Definition audiohook.h:75
int ast_audiohook_init(struct ast_audiohook *audiohook, enum ast_audiohook_type type, const char *source, enum ast_audiohook_init_flags flags)
Initialize an audiohook structure.
Definition audiohook.c:100
ast_audiohook_direction
Definition audiohook.h:48
@ AST_AUDIOHOOK_DIRECTION_READ
Definition audiohook.h:49
int ast_audiohook_detach(struct ast_audiohook *audiohook)
Detach audiohook from channel.
Definition audiohook.c:587
int ast_audiohook_attach(struct ast_channel *chan, struct ast_audiohook *audiohook)
Attach audiohook to channel.
Definition audiohook.c:521
int ast_audiohook_destroy(struct ast_audiohook *audiohook)
Destroys an audiohook structure.
Definition audiohook.c:124
@ AST_AUDIOHOOK_TYPE_MANIPULATE
Definition audiohook.h:38
@ AST_AUDIOHOOK_STATUS_DONE
Definition audiohook.h:45
const char * ast_channel_name(const struct ast_channel *chan)
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition channel.c:2355
int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore)
Remove a datastore from a channel.
Definition channel.c:2364
#define ast_channel_lock(chan)
Definition channel.h:2972
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition channel.c:3132
int ast_write(struct ast_channel *chan, struct ast_frame *frame)
Write a frame to a channel This function writes the given frame to the indicated channel.
Definition channel.c:5112
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition channel.c:4223
int ast_set_read_format(struct ast_channel *chan, struct ast_format *format)
Sets read format on channel chan.
Definition channel.c:5730
int ast_set_write_format(struct ast_channel *chan, struct ast_format *format)
Sets write format on channel chan.
Definition channel.c:5771
#define ast_channel_unlock(chan)
Definition channel.h:2973
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
Definition channel.c:2369
struct ast_format * ast_channel_readformat(struct ast_channel *chan)
#define ast_datastore_alloc(info, uid)
Definition datastore.h:85
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition datastore.c:68
char buf[BUFSIZE]
Definition eagi_proxy.c:66
unsigned int ast_format_get_sample_rate(const struct ast_format *format)
Get the sample rate of a media format.
Definition format.c:379
enum ast_format_cmp_res ast_format_cmp(const struct ast_format *format1, const struct ast_format *format2)
Compare two formats.
Definition format.c:201
@ AST_FORMAT_CMP_NOT_EQUAL
Definition format.h:38
const char * ast_format_get_name(const struct ast_format *format)
Get the name associated with a format.
Definition format.c:334
struct ast_format * ast_format_cache_get_slin_by_rate(unsigned int rate)
Retrieve the best signed linear format given a sample rate.
direction
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
static char prefix[MAX_PREFIX]
Definition http.c:144
#define AST_APP_ARG(name)
Define an application argument.
#define END_OPTIONS
#define AST_APP_OPTIONS(holder, options...)
Declares an array of options for an application.
#define AST_APP_OPTION_ARG(option, flagno, argno)
Declares an application option that accepts an argument.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define BEGIN_OPTIONS
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
#define AST_APP_OPTION(option, flagno)
Declares an application option that does not accept an argument.
int ast_app_parse_options(const struct ast_app_option *options, struct ast_flags *flags, char **args, char *optstr)
Parses a string containing application options and sets flags/arguments.
Definition main/app.c:3066
#define ast_frfree(fr)
@ AST_FRAME_CONTROL
@ AST_CONTROL_HANGUP
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define LOG_NOTICE
#define LOG_WARNING
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition module.h:46
int ast_unregister_application(const char *app)
Unregister an application.
Definition pbx_app.c:392
#define AST_MODULE_INFO_STANDARD_EXTENDED(keystr, desc)
Definition module.h:589
@ AST_MODULE_LOAD_SUCCESS
Definition module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition module.h:78
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition module.h:640
#define ast_custom_function_register(acf)
Register a custom function.
Definition pbx.h:1562
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
static struct @519 args
#define NULL
Definition resample.c:96
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
#define ast_calloc_with_stringfields(n, type, size)
Allocate a structure with embedded stringfields in a single allocation.
#define AST_STRING_FIELD(name)
Declare a string field.
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition strings.h:1139
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition strings.h:80
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition strings.h:65
#define ast_str_alloca(init_len)
Definition strings.h:848
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition strings.h:1113
char *attribute_pure ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition strings.h:761
ast_audiohook_manipulate_callback manipulate_callback
Definition audiohook.h:118
enum ast_audiohook_status status
Definition audiohook.h:108
Main Channel structure associated with a channel.
Data structure associated with a custom dialplan function.
Definition pbx.h:118
const char * name
Definition pbx.h:119
Structure for a data store type.
Definition datastore.h:31
const char * type
Definition datastore.h:32
Structure for a data store object.
Definition datastore.h:64
void * data
Definition datastore.h:66
Structure used to handle boolean flags.
Definition utils.h:217
Definition of a media format.
Definition format.c:43
struct ast_format * format
Data structure associated with a single frame of data.
struct ast_frame_subclass subclass
enum ast_frame_type frametype
union ast_frame::@239 data
Support for dynamic strings.
Definition strings.h:623
jack_ringbuffer_t * input_rb
Definition app_jack.c:132
unsigned int stop
Definition app_jack.c:141
jack_port_t * output_port
Definition app_jack.c:131
double output_resample_factor
Definition app_jack.c:138
struct ast_format * audiohook_format
Definition app_jack.c:134
const ast_string_field client_name
Definition app_jack.c:128
void * input_resampler
Definition app_jack.c:139
const ast_string_field connect_input_port
Definition app_jack.c:128
double input_resample_factor
Definition app_jack.c:140
jack_ringbuffer_t * output_rb
Definition app_jack.c:133
void * output_resampler
Definition app_jack.c:137
unsigned int frame_datalen
Definition app_jack.c:136
const ast_string_field connect_output_port
Definition app_jack.c:128
unsigned int no_start_server
Definition app_jack.c:143
struct ast_audiohook audiohook
Definition app_jack.c:145
const ast_string_field server_name
Definition app_jack.c:128
unsigned int has_audiohook
Definition app_jack.c:142
unsigned int audiohook_rate
Definition app_jack.c:135
jack_port_t * input_port
Definition app_jack.c:130
jack_client_t * client
Definition app_jack.c:129
int value
Definition syslog.c:37
static struct test_options options
#define ast_test_flag(p, flag)
Definition utils.h:63
#define ARRAY_LEN(a)
Definition utils.h:703

◆ RESAMPLE_QUALITY

#define RESAMPLE_QUALITY   1

Definition at line 61 of file app_jack.c.

◆ RINGBUFFER_FRAME_CAPACITY

#define RINGBUFFER_FRAME_CAPACITY   100

Definition at line 64 of file app_jack.c.

Enumeration Type Documentation

◆ anonymous enum

anonymous enum
Enumerator
OPT_SERVER_NAME 
OPT_INPUT_PORT 
OPT_OUTPUT_PORT 
OPT_NOSTART_SERVER 
OPT_CLIENT_NAME 

Definition at line 670 of file app_jack.c.

670 {
671 OPT_SERVER_NAME = (1 << 0),
672 OPT_INPUT_PORT = (1 << 1),
673 OPT_OUTPUT_PORT = (1 << 2),
674 OPT_NOSTART_SERVER = (1 << 3),
675 OPT_CLIENT_NAME = (1 << 4),
676};

◆ anonymous enum

anonymous enum
Enumerator
OPT_ARG_SERVER_NAME 
OPT_ARG_INPUT_PORT 
OPT_ARG_OUTPUT_PORT 
OPT_ARG_CLIENT_NAME 
OPT_ARG_ARRAY_SIZE 

Definition at line 678 of file app_jack.c.

678 {
683
684 /* Must be the last element */
686};

Function Documentation

◆ alloc_resampler()

static int alloc_resampler ( struct jack_data jack_data,
int  input 
)
static

Definition at line 196 of file app_jack.c.

197{
198 double from_srate, to_srate, jack_srate;
199 void **resampler;
200 double *resample_factor;
201
202 if (input && jack_data->input_resampler)
203 return 0;
204
205 if (!input && jack_data->output_resampler)
206 return 0;
207
208 jack_srate = jack_get_sample_rate(jack_data->client);
209
210 to_srate = input ? jack_data->audiohook_rate : jack_srate;
211 from_srate = input ? jack_srate : jack_data->audiohook_rate;
212
213 resample_factor = input ? &jack_data->input_resample_factor :
215
216 if (from_srate == to_srate) {
217 /* Awesome! The jack sample rate is the same as ours.
218 * Resampling isn't needed. */
219 *resample_factor = 1.0;
220 return 0;
221 }
222
223 *resample_factor = to_srate / from_srate;
224
225 resampler = input ? &jack_data->input_resampler :
227
228 if (!(*resampler = resample_open(RESAMPLE_QUALITY,
229 *resample_factor, *resample_factor))) {
230 ast_log(LOG_ERROR, "Failed to open %s resampler\n",
231 input ? "input" : "output");
232 return -1;
233 }
234
235 return 0;
236}

References ast_log, jack_data::audiohook_rate, jack_data::client, jack_data::input_resample_factor, jack_data::input_resampler, LOG_ERROR, jack_data::output_resample_factor, jack_data::output_resampler, and RESAMPLE_QUALITY.

Referenced by jack_process(), and queue_voice_frame().

◆ AST_MODULE_INFO_STANDARD_EXTENDED()

AST_MODULE_INFO_STANDARD_EXTENDED ( ASTERISK_GPL_KEY  ,
"JACK Interface"   
)

◆ destroy_jack_data()

static struct jack_data * destroy_jack_data ( struct jack_data jack_data)
static

Definition at line 346 of file app_jack.c.

347{
348 if (jack_data->input_port) {
349 jack_port_unregister(jack_data->client, jack_data->input_port);
351 }
352
353 if (jack_data->output_port) {
354 jack_port_unregister(jack_data->client, jack_data->output_port);
356 }
357
358 if (jack_data->client) {
359 jack_client_close(jack_data->client);
361 }
362
363 if (jack_data->input_rb) {
364 jack_ringbuffer_free(jack_data->input_rb);
366 }
367
368 if (jack_data->output_rb) {
369 jack_ringbuffer_free(jack_data->output_rb);
371 }
372
374 resample_close(jack_data->output_resampler);
376 }
377
379 resample_close(jack_data->input_resampler);
381 }
382
385
387
389
390 return NULL;
391}

References ast_audiohook_destroy(), ast_free, ast_string_field_free_memory, jack_data::audiohook, jack_data::client, jack_data::has_audiohook, jack_data::input_port, jack_data::input_rb, jack_data::input_resampler, NULL, jack_data::output_port, jack_data::output_rb, and jack_data::output_resampler.

Referenced by enable_jack_hook(), jack_exec(), and jack_hook_ds_destroy().

◆ disable_jack_hook()

static int disable_jack_hook ( struct ast_channel chan)
static

Definition at line 943 of file app_jack.c.

944{
945 struct ast_datastore *datastore;
946 struct jack_data *jack_data;
947
948 ast_channel_lock(chan);
949
950 if (!(datastore = ast_channel_datastore_find(chan, &jack_hook_ds_info, NULL))) {
951 ast_channel_unlock(chan);
952 ast_log(LOG_WARNING, "No JACK_HOOK found to disable\n");
953 return -1;
954 }
955
956 ast_channel_datastore_remove(chan, datastore);
957
958 jack_data = datastore->data;
960
961 /* Keep the channel locked while we destroy the datastore, so that we can
962 * ensure that all of the jack stuff is stopped just in case another frame
963 * tries to come through the audiohook callback. */
964 ast_datastore_free(datastore);
965
966 ast_channel_unlock(chan);
967
968 return 0;
969}

References ast_audiohook_detach(), ast_channel_datastore_find(), ast_channel_datastore_remove(), ast_channel_lock, ast_channel_unlock, ast_datastore_free(), ast_log, jack_data::audiohook, ast_datastore::data, jack_hook_ds_info, LOG_WARNING, and NULL.

Referenced by jack_hook_write().

◆ enable_jack_hook()

static int enable_jack_hook ( struct ast_channel chan,
char *  data 
)
static

Definition at line 876 of file app_jack.c.

877{
878 struct ast_datastore *datastore;
879 struct jack_data *jack_data = NULL;
881 AST_APP_ARG(mode);
883 );
884
886
887 ast_channel_lock(chan);
888
889 if ((datastore = ast_channel_datastore_find(chan, &jack_hook_ds_info, NULL))) {
890 ast_log(LOG_ERROR, "JACK_HOOK already enabled for '%s'\n", ast_channel_name(chan));
891 goto return_error;
892 }
893
894 if (ast_strlen_zero(args.mode) || strcasecmp(args.mode, "manipulate")) {
895 ast_log(LOG_ERROR, "'%s' is not a supported mode. Only manipulate is supported.\n",
896 S_OR(args.mode, "<none>"));
897 goto return_error;
898 }
899
900 if (!(jack_data = jack_data_alloc()))
901 goto return_error;
902
903 if (!ast_strlen_zero(args.options) && handle_options(jack_data, args.options))
904 goto return_error;
905
906 if (init_jack_data(chan, jack_data))
907 goto return_error;
908
909 if (!(datastore = ast_datastore_alloc(&jack_hook_ds_info, NULL)))
910 goto return_error;
911
915
916 datastore->data = jack_data;
917
919 goto return_error;
920
921 if (ast_channel_datastore_add(chan, datastore))
922 goto return_error;
923
924 ast_channel_unlock(chan);
925
926 return 0;
927
928return_error:
929 ast_channel_unlock(chan);
930
931 if (jack_data) {
933 }
934
935 if (datastore) {
936 datastore->data = NULL;
937 ast_datastore_free(datastore);
938 }
939
940 return -1;
941}

References args, AST_APP_ARG, ast_audiohook_attach(), ast_audiohook_init(), AST_AUDIOHOOK_MANIPULATE_ALL_RATES, AST_AUDIOHOOK_TYPE_MANIPULATE, ast_channel_datastore_add(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_name(), ast_channel_unlock, ast_datastore_alloc, ast_datastore_free(), AST_DECLARE_APP_ARGS, ast_log, AST_STANDARD_APP_ARGS, ast_strlen_zero(), jack_data::audiohook, ast_datastore::data, destroy_jack_data(), handle_options(), jack_data::has_audiohook, init_jack_data(), jack_data_alloc(), jack_hook_callback(), jack_hook_ds_info, LOG_ERROR, ast_audiohook::manipulate_callback, NULL, options, and S_OR.

Referenced by jack_hook_write().

◆ handle_input()

static void handle_input ( void *  buf,
jack_nframes_t  nframes,
struct jack_data jack_data 
)
static

Handle jack input port.

Read nframes number of samples from the input buffer, resample it if necessary, and write it into the appropriate ringbuffer.

Definition at line 244 of file app_jack.c.

246{
247 short s_buf[nframes];
248 float *in_buf = buf;
249 size_t res;
250 int i;
251 size_t write_len = sizeof(s_buf);
252
254 int total_in_buf_used = 0;
255 int total_out_buf_used = 0;
256 float f_buf[nframes + 1];
257
258 memset(f_buf, 0, sizeof(f_buf));
259
260 while (total_in_buf_used < nframes) {
261 int in_buf_used;
262 int out_buf_used;
263
264 out_buf_used = resample_process(jack_data->input_resampler,
266 &in_buf[total_in_buf_used], nframes - total_in_buf_used,
267 0, &in_buf_used,
268 &f_buf[total_out_buf_used], ARRAY_LEN(f_buf) - total_out_buf_used);
269
270 if (out_buf_used < 0)
271 break;
272
273 total_out_buf_used += out_buf_used;
274 total_in_buf_used += in_buf_used;
275
276 if (total_out_buf_used == ARRAY_LEN(f_buf)) {
277 ast_log(LOG_ERROR, "Output buffer filled ... need to increase its size, "
278 "nframes '%d', total_out_buf_used '%d'\n", nframes, total_out_buf_used);
279 break;
280 }
281 }
282
283 for (i = 0; i < total_out_buf_used; i++)
284 s_buf[i] = f_buf[i] * (SHRT_MAX / 1.0);
285
286 write_len = total_out_buf_used * sizeof(int16_t);
287 } else {
288 /* No resampling needed */
289
290 for (i = 0; i < nframes; i++)
291 s_buf[i] = in_buf[i] * (SHRT_MAX / 1.0);
292 }
293
294 res = jack_ringbuffer_write(jack_data->input_rb, (const char *) s_buf, write_len);
295 if (res != write_len) {
296 ast_log(LOG_WARNING, "Tried to write %d bytes to the ringbuffer, but only wrote %d\n",
297 (int) sizeof(s_buf), (int) res);
298 }
299}

References ARRAY_LEN, ast_log, buf, jack_data::input_rb, jack_data::input_resample_factor, jack_data::input_resampler, LOG_ERROR, and LOG_WARNING.

Referenced by jack_process().

◆ handle_jack_audio()

static void handle_jack_audio ( struct ast_channel chan,
struct jack_data jack_data,
struct ast_frame out_frame 
)
static

handle jack audio

Parameters
[in]chanThe Asterisk channel to write the frames to if no output frame is provided.
[in]jack_dataThis is the jack_data struct that contains the input ringbuffer that audio will be read from.
[out]out_frameIf this argument is non-NULL, then assuming there is enough data available in the ringbuffer, the audio in this frame will get replaced with audio from the input buffer. If there is not enough data available to read at this time, then the frame data gets zeroed out.

Read data from the input ringbuffer, which is the properly resampled audio that was read from the jack input port. Write it to the channel in 20 ms frames, or fill up an output frame instead if one is provided.

Definition at line 622 of file app_jack.c.

624{
626 struct ast_frame f = {
628 .subclass.format = jack_data->audiohook_format,
629 .src = "JACK",
630 .data.ptr = buf,
631 .datalen = sizeof(buf),
633 };
634
635 for (;;) {
636 size_t res, read_len;
637 char *read_buf;
638
639 read_len = out_frame ? out_frame->datalen : sizeof(buf);
640 read_buf = out_frame ? out_frame->data.ptr : buf;
641
642 res = jack_ringbuffer_read_space(jack_data->input_rb);
643
644 if (res < read_len) {
645 /* Not enough data ready for another frame, move on ... */
646 if (out_frame) {
647 ast_debug(1, "Sending an empty frame for the JACK_HOOK\n");
648 memset(out_frame->data.ptr, 0, out_frame->datalen);
649 }
650 break;
651 }
652
653 res = jack_ringbuffer_read(jack_data->input_rb, (char *) read_buf, read_len);
654
655 if (res < read_len) {
656 ast_log(LOG_ERROR, "Error reading from ringbuffer, even though it said there was enough data\n");
657 break;
658 }
659
660 if (out_frame) {
661 /* If an output frame was provided, then we just want to fill up the
662 * buffer in that frame and return. */
663 break;
664 }
665
666 ast_write(chan, &f);
667 }
668}

References ARRAY_LEN, ast_debug, AST_FRAME_VOICE, ast_log, ast_write(), jack_data::audiohook_format, buf, ast_frame::data, ast_frame::datalen, jack_data::frame_datalen, ast_frame::frametype, jack_data::input_rb, LOG_ERROR, ast_frame::ptr, and ast_frame::samples.

Referenced by jack_exec(), and jack_hook_callback().

◆ handle_options()

static int handle_options ( struct jack_data jack_data,
const char *  __options_str 
)
static
Note
This must be done before calling init_jack_data().

Definition at line 710 of file app_jack.c.

711{
712 struct ast_flags options = { 0, };
714 char *options_str;
715
716 options_str = ast_strdupa(__options_str);
717
719
723 else {
724 ast_log(LOG_ERROR, "A server name must be provided with the s() option\n");
725 return -1;
726 }
727 }
728
732 else {
733 ast_log(LOG_ERROR, "A client name must be provided with the c() option\n");
734 return -1;
735 }
736 }
737
741 else {
742 ast_log(LOG_ERROR, "A name must be provided with the i() option\n");
743 return -1;
744 }
745 }
746
750 else {
751 ast_log(LOG_ERROR, "A name must be provided with the o() option\n");
752 return -1;
753 }
754 }
755
757
758 return 0;
759}

References ast_app_parse_options(), ast_log, ast_strdupa, ast_string_field_set, ast_strlen_zero(), ast_test_flag, jack_exec_options, LOG_ERROR, jack_data::no_start_server, OPT_ARG_ARRAY_SIZE, OPT_ARG_CLIENT_NAME, OPT_ARG_INPUT_PORT, OPT_ARG_OUTPUT_PORT, OPT_ARG_SERVER_NAME, OPT_CLIENT_NAME, OPT_INPUT_PORT, OPT_NOSTART_SERVER, OPT_OUTPUT_PORT, OPT_SERVER_NAME, and options.

Referenced by enable_jack_hook(), and jack_exec().

◆ handle_output()

static void handle_output ( void *  buf,
jack_nframes_t  nframes,
struct jack_data jack_data 
)
static

Handle jack output port.

Read nframes number of samples from the ringbuffer and write it out to the output port buffer.

Definition at line 307 of file app_jack.c.

309{
310 size_t res, len;
311
312 len = nframes * sizeof(float);
313
314 res = jack_ringbuffer_read(jack_data->output_rb, buf, len);
315
316 if (len != res) {
317 ast_debug(2, "Wanted %d bytes to send to the output port, "
318 "but only got %d\n", (int) len, (int) res);
319 }
320}

References ast_debug, buf, len(), and jack_data::output_rb.

Referenced by jack_process().

◆ init_jack_data()

static int init_jack_data ( struct ast_channel chan,
struct jack_data jack_data 
)
static

Definition at line 393 of file app_jack.c.

394{
395 const char *client_name;
396 jack_status_t status = 0;
397 jack_options_t jack_options = JackNullOption;
398
399 unsigned int channel_rate;
400
401 unsigned int ringbuffer_size;
402
403 /* Deducing audiohook sample rate from channel format
404 ATTENTION: Might be problematic, if channel has different sampling than used by audiohook!
405 */
409
410 /* Guessing frame->datalen assuming a ptime of 20ms */
412
414
415 ast_debug(1, "Audiohook parameters: slin-format:%s, rate:%d, frame-len:%d, ringbuffer_size: %d\n",
417
419 client_name = jack_data->client_name;
420 } else {
421 ast_channel_lock(chan);
422 client_name = ast_strdupa(ast_channel_name(chan));
423 ast_channel_unlock(chan);
424 }
425
426 if (!(jack_data->output_rb = jack_ringbuffer_create(ringbuffer_size)))
427 return -1;
428
429 if (!(jack_data->input_rb = jack_ringbuffer_create(ringbuffer_size)))
430 return -1;
431
433 jack_options |= JackNoStartServer;
434
436 jack_options |= JackServerName;
437 jack_data->client = jack_client_open(client_name, jack_options, &status,
439 } else {
440 jack_data->client = jack_client_open(client_name, jack_options, &status);
441 }
442
443 if (status)
444 log_jack_status("Client Open Status", status);
445
446 if (!jack_data->client)
447 return -1;
448
449 jack_data->input_port = jack_port_register(jack_data->client, "input",
450 JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput | JackPortIsTerminal, 0);
451 if (!jack_data->input_port) {
452 ast_log(LOG_ERROR, "Failed to create input port for jack port\n");
453 return -1;
454 }
455
456 jack_data->output_port = jack_port_register(jack_data->client, "output",
457 JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput | JackPortIsTerminal, 0);
458 if (!jack_data->output_port) {
459 ast_log(LOG_ERROR, "Failed to create output port for jack port\n");
460 return -1;
461 }
462
463 if (jack_set_process_callback(jack_data->client, jack_process, jack_data)) {
464 ast_log(LOG_ERROR, "Failed to register process callback with jack client\n");
465 return -1;
466 }
467
468 jack_on_shutdown(jack_data->client, jack_shutdown, jack_data);
469
470 if (jack_activate(jack_data->client)) {
471 ast_log(LOG_ERROR, "Unable to activate jack client\n");
472 return -1;
473 }
474
476 const char **ports;
477 int i;
478
479 ports = jack_get_ports(jack_data->client, jack_data->connect_input_port,
480 NULL, JackPortIsInput);
481
482 if (!ports) {
483 ast_log(LOG_ERROR, "No input port matching '%s' was found\n",
485 break;
486 }
487
488 for (i = 0; ports[i]; i++) {
489 ast_debug(1, "Found port '%s' that matched specified input port '%s'\n",
490 ports[i], jack_data->connect_input_port);
491 }
492
493 if (jack_connect(jack_data->client, jack_port_name(jack_data->output_port), ports[0])) {
494 ast_log(LOG_ERROR, "Failed to connect '%s' to '%s'\n", ports[0],
495 jack_port_name(jack_data->output_port));
496 } else {
497 ast_debug(1, "Connected '%s' to '%s'\n", ports[0],
498 jack_port_name(jack_data->output_port));
499 }
500
501 jack_free(ports);
502
503 break;
504 }
505
507 const char **ports;
508 int i;
509
510 ports = jack_get_ports(jack_data->client, jack_data->connect_output_port,
511 NULL, JackPortIsOutput);
512
513 if (!ports) {
514 ast_log(LOG_ERROR, "No output port matching '%s' was found\n",
516 break;
517 }
518
519 for (i = 0; ports[i]; i++) {
520 ast_debug(1, "Found port '%s' that matched specified output port '%s'\n",
521 ports[i], jack_data->connect_output_port);
522 }
523
524 if (jack_connect(jack_data->client, ports[0], jack_port_name(jack_data->input_port))) {
525 ast_log(LOG_ERROR, "Failed to connect '%s' to '%s'\n", ports[0],
526 jack_port_name(jack_data->input_port));
527 } else {
528 ast_debug(1, "Connected '%s' to '%s'\n", ports[0],
529 jack_port_name(jack_data->input_port));
530 }
531
532 jack_free(ports);
533
534 break;
535 }
536
537 return 0;
538}

References ast_channel_lock, ast_channel_name(), ast_channel_readformat(), ast_channel_unlock, ast_debug, ast_format_cache_get_slin_by_rate(), ast_format_get_name(), ast_format_get_sample_rate(), ast_log, ast_strdupa, ast_strlen_zero(), jack_data::audiohook_format, jack_data::audiohook_rate, jack_data::client, jack_data::client_name, jack_data::connect_input_port, jack_data::connect_output_port, jack_data::frame_datalen, jack_data::input_port, jack_data::input_rb, jack_process(), jack_shutdown(), LOG_ERROR, log_jack_status(), jack_data::no_start_server, NULL, jack_data::output_port, jack_data::output_rb, RINGBUFFER_FRAME_CAPACITY, jack_data::server_name, and status.

Referenced by enable_jack_hook(), and jack_exec().

◆ jack_data_alloc()

static struct jack_data * jack_data_alloc ( void  )
static

Definition at line 696 of file app_jack.c.

697{
698 struct jack_data *jack_data;
699
700 if (!(jack_data = ast_calloc_with_stringfields(1, struct jack_data, 32))) {
701 return NULL;
702 }
703
704 return jack_data;
705}

References ast_calloc_with_stringfields, and NULL.

Referenced by enable_jack_hook(), and jack_exec().

◆ jack_exec()

static int jack_exec ( struct ast_channel chan,
const char *  data 
)
static

Definition at line 761 of file app_jack.c.

762{
763 struct jack_data *jack_data;
764
765 if (!(jack_data = jack_data_alloc()))
766 return -1;
767
768 if (!ast_strlen_zero(data) && handle_options(jack_data, data)) {
770 return -1;
771 }
772
773 if (init_jack_data(chan, jack_data)) {
775 return -1;
776 }
777
780 return -1;
781 }
782
785 return -1;
786 }
787
788 while (!jack_data->stop) {
789 struct ast_frame *f;
790
791 if (ast_waitfor(chan, -1) < 0) {
792 break;
793 }
794
795 f = ast_read(chan);
796 if (!f) {
797 jack_data->stop = 1;
798 continue;
799 }
800
801 switch (f->frametype) {
804 jack_data->stop = 1;
805 break;
806 case AST_FRAME_VOICE:
808 default:
809 break;
810 }
811
812 ast_frfree(f);
813
815 }
816
818
819 return 0;
820}

References AST_CONTROL_HANGUP, AST_FRAME_CONTROL, AST_FRAME_VOICE, ast_frfree, ast_read(), ast_set_read_format(), ast_set_write_format(), ast_strlen_zero(), ast_waitfor(), jack_data::audiohook_format, destroy_jack_data(), ast_frame::frametype, handle_jack_audio(), handle_options(), init_jack_data(), ast_frame_subclass::integer, jack_data_alloc(), NULL, queue_voice_frame(), jack_data::stop, and ast_frame::subclass.

Referenced by load_module().

◆ jack_hook_callback()

static int jack_hook_callback ( struct ast_audiohook audiohook,
struct ast_channel chan,
struct ast_frame frame,
enum ast_audiohook_direction  direction 
)
static

Definition at line 834 of file app_jack.c.

836{
837 struct ast_datastore *datastore;
838 struct jack_data *jack_data;
839
841 return 0;
842
844 return 0;
845
846 if (frame->frametype != AST_FRAME_VOICE)
847 return 0;
848
849 ast_channel_lock(chan);
850
851 if (!(datastore = ast_channel_datastore_find(chan, &jack_hook_ds_info, NULL))) {
852 ast_log(LOG_ERROR, "JACK_HOOK datastore not found for '%s'\n", ast_channel_name(chan));
853 ast_channel_unlock(chan);
854 return -1;
855 }
856
857 jack_data = datastore->data;
858
860 ast_log(LOG_WARNING, "Expected frame in %s for the audiohook, but got format %s\n",
863 ast_channel_unlock(chan);
864 return 0;
865 }
866
868
869 handle_jack_audio(chan, jack_data, frame);
870
871 ast_channel_unlock(chan);
872
873 return 0;
874}

References AST_AUDIOHOOK_DIRECTION_READ, AST_AUDIOHOOK_STATUS_DONE, ast_channel_datastore_find(), ast_channel_lock, ast_channel_name(), ast_channel_unlock, ast_format_cmp(), AST_FORMAT_CMP_NOT_EQUAL, ast_format_get_name(), AST_FRAME_VOICE, ast_log, jack_data::audiohook, jack_data::audiohook_format, ast_datastore::data, ast_frame_subclass::format, ast_frame::frametype, handle_jack_audio(), jack_hook_ds_info, LOG_ERROR, LOG_WARNING, NULL, queue_voice_frame(), ast_audiohook::status, and ast_frame::subclass.

Referenced by enable_jack_hook().

◆ jack_hook_ds_destroy()

static void jack_hook_ds_destroy ( void *  data)
static

Definition at line 822 of file app_jack.c.

823{
824 struct jack_data *jack_data = data;
825
827}

References destroy_jack_data().

◆ jack_hook_write()

static int jack_hook_write ( struct ast_channel chan,
const char *  cmd,
char *  data,
const char *  value 
)
static

Definition at line 971 of file app_jack.c.

973{
974 int res;
975
976 if (!chan) {
977 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
978 return -1;
979 }
980
981 if (!strcasecmp(value, "on"))
982 res = enable_jack_hook(chan, data);
983 else if (!strcasecmp(value, "off"))
984 res = disable_jack_hook(chan);
985 else {
986 ast_log(LOG_ERROR, "'%s' is not a valid value for JACK_HOOK()\n", value);
987 res = -1;
988 }
989
990 return res;
991}

References ast_log, disable_jack_hook(), enable_jack_hook(), LOG_ERROR, LOG_WARNING, and value.

◆ jack_process()

static int jack_process ( jack_nframes_t  nframes,
void *  arg 
)
static

Definition at line 322 of file app_jack.c.

323{
324 struct jack_data *jack_data = arg;
325 void *input_port_buf, *output_port_buf;
326
329
330 input_port_buf = jack_port_get_buffer(jack_data->input_port, nframes);
331 handle_input(input_port_buf, nframes, jack_data);
332
333 output_port_buf = jack_port_get_buffer(jack_data->output_port, nframes);
334 handle_output(output_port_buf, nframes, jack_data);
335
336 return 0;
337}

References alloc_resampler(), handle_input(), handle_output(), jack_data::input_port, jack_data::input_resample_factor, and jack_data::output_port.

Referenced by init_jack_data().

◆ jack_shutdown()

static void jack_shutdown ( void *  arg)
static

Definition at line 339 of file app_jack.c.

340{
341 struct jack_data *jack_data = arg;
342
343 jack_data->stop = 1;
344}

References jack_data::stop.

Referenced by init_jack_data().

◆ jack_status_to_str()

static const char * jack_status_to_str ( jack_status_t  status)
static

Definition at line 165 of file app_jack.c.

166{
167 int i;
168
169 for (i = 0; i < ARRAY_LEN(jack_status_table); i++) {
171 return jack_status_table[i].str;
172 }
173
174 return "Unknown Error";
175}

References ARRAY_LEN, jack_status_table, and status.

Referenced by log_jack_status().

◆ load_module()

static int load_module ( void  )
static

◆ log_jack_status()

static void log_jack_status ( const char *  prefix,
jack_status_t  status 
)
static

Definition at line 177 of file app_jack.c.

178{
179 struct ast_str *str = ast_str_alloca(512);
180 int i, first = 0;
181
182 for (i = 0; i < (sizeof(status) * 8); i++) {
183 if (!(status & (1 << i)))
184 continue;
185
186 if (!first) {
187 ast_str_set(&str, 0, "%s", jack_status_to_str((1 << i)));
188 first = 1;
189 } else
190 ast_str_append(&str, 0, ", %s", jack_status_to_str((1 << i)));
191 }
192
194}

References ast_log, ast_str_alloca, ast_str_append(), ast_str_buffer(), ast_str_set(), first, jack_status_to_str(), LOG_NOTICE, prefix, status, and str.

Referenced by init_jack_data().

◆ queue_voice_frame()

static int queue_voice_frame ( struct jack_data jack_data,
struct ast_frame f 
)
static

Definition at line 540 of file app_jack.c.

541{
542 float f_buf[f->samples * 8];
543 size_t f_buf_used = 0;
544 int i;
545 int16_t *s_buf = f->data.ptr;
546 size_t res;
547
548 memset(f_buf, 0, sizeof(f_buf));
549
552
554 float in_buf[f->samples];
555 int total_in_buf_used = 0;
556 int total_out_buf_used = 0;
557
558 memset(in_buf, 0, sizeof(in_buf));
559
560 for (i = 0; i < f->samples; i++)
561 in_buf[i] = s_buf[i] * (1.0 / SHRT_MAX);
562
563 while (total_in_buf_used < ARRAY_LEN(in_buf)) {
564 int in_buf_used;
565 int out_buf_used;
566
567 out_buf_used = resample_process(jack_data->output_resampler,
569 &in_buf[total_in_buf_used], ARRAY_LEN(in_buf) - total_in_buf_used,
570 0, &in_buf_used,
571 &f_buf[total_out_buf_used], ARRAY_LEN(f_buf) - total_out_buf_used);
572
573 if (out_buf_used < 0)
574 break;
575
576 total_out_buf_used += out_buf_used;
577 total_in_buf_used += in_buf_used;
578
579 if (total_out_buf_used == ARRAY_LEN(f_buf)) {
580 ast_log(LOG_ERROR, "Output buffer filled ... need to increase its size\n");
581 break;
582 }
583 }
584
585 f_buf_used = total_out_buf_used;
586 if (f_buf_used > ARRAY_LEN(f_buf))
587 f_buf_used = ARRAY_LEN(f_buf);
588 } else {
589 /* No resampling needed */
590
591 for (i = 0; i < f->samples; i++)
592 f_buf[i] = s_buf[i] * (1.0 / SHRT_MAX);
593
594 f_buf_used = f->samples;
595 }
596
597 res = jack_ringbuffer_write(jack_data->output_rb, (const char *) f_buf, f_buf_used * sizeof(float));
598 if (res != (f_buf_used * sizeof(float))) {
599 ast_log(LOG_WARNING, "Tried to write %d bytes to the ringbuffer, but only wrote %d\n",
600 (int) (f_buf_used * sizeof(float)), (int) res);
601 }
602 return 0;
603}

References alloc_resampler(), ARRAY_LEN, ast_log, ast_frame::data, LOG_ERROR, LOG_WARNING, jack_data::output_rb, jack_data::output_resample_factor, jack_data::output_resampler, ast_frame::ptr, and ast_frame::samples.

Referenced by jack_exec(), and jack_hook_callback().

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 1029 of file app_jack.c.

1030{
1031 int res;
1032
1035
1036 return res;
1037}

References ast_custom_function_unregister(), ast_unregister_application(), jack_app, and jack_hook_function.

Variable Documentation

◆ jack_app

const char jack_app[] = "JACK"
static

Definition at line 120 of file app_jack.c.

Referenced by load_module(), and unload_module().

◆ jack_exec_options

const struct ast_app_option jack_exec_options[128] = { [ 's' ] = { .flag = OPT_SERVER_NAME , .arg_index = OPT_ARG_SERVER_NAME + 1 }, [ 'i' ] = { .flag = OPT_INPUT_PORT , .arg_index = OPT_ARG_INPUT_PORT + 1 }, [ 'o' ] = { .flag = OPT_OUTPUT_PORT , .arg_index = OPT_ARG_OUTPUT_PORT + 1 }, [ 'n' ] = { .flag = OPT_NOSTART_SERVER }, [ 'c' ] = { .flag = OPT_CLIENT_NAME , .arg_index = OPT_ARG_CLIENT_NAME + 1 }, }
static

Definition at line 694 of file app_jack.c.

Referenced by handle_options().

◆ jack_hook_ds_info

const struct ast_datastore_info jack_hook_ds_info
static
Initial value:
= {
.type = "JACK_HOOK",
}

Definition at line 829 of file app_jack.c.

829 {
830 .type = "JACK_HOOK",
831 .destroy = jack_hook_ds_destroy,
832};

Referenced by disable_jack_hook(), enable_jack_hook(), and jack_hook_callback().

◆ jack_hook_function

struct ast_custom_function jack_hook_function
static

Definition at line 993 of file app_jack.c.

993 {
994 .name = "JACK_HOOK",
995 .synopsis = "Enable a jack hook on a channel",
996 .syntax = "JACK_HOOK(<mode>,[options])",
997 .desc =
998 " The JACK_HOOK allows turning on or off jack connectivity to this channel.\n"
999 "When the JACK_HOOK is turned on, jack ports will get created that allow\n"
1000 "access to the audio stream for this channel. The mode specifies which mode\n"
1001 "this hook should run in. A mode must be specified when turning the JACK_HOOK.\n"
1002 "on. However, all arguments are optional when turning it off.\n"
1003 "\n"
1004 " Valid modes are:\n"
1005#if 0
1006 /* XXX TODO */
1007 " spy - Create a read-only audio hook. Only an output jack port will\n"
1008 " get created.\n"
1009 " whisper - Create a write-only audio hook. Only an input jack port will\n"
1010 " get created.\n"
1011#endif
1012 " manipulate - Create a read/write audio hook. Both an input and an output\n"
1013 " jack port will get created. Audio from the channel will be\n"
1014 " sent out the output port and will be replaced by the audio\n"
1015 " coming in on the input port as it gets passed on.\n"
1016 "\n"
1017 " Valid options are:\n"
1019 "\n"
1020 " Examples:\n"
1021 " To turn on the JACK_HOOK,\n"
1022 " Set(JACK_HOOK(manipulate,i(pure_data_0:input0)o(pure_data_0:output0))=on)\n"
1023 " To turn off the JACK_HOOK,\n"
1024 " Set(JACK_HOOK()=off)\n"
1025 "",
1026 .write = jack_hook_write,
1027};

Referenced by load_module(), and unload_module().

◆ [struct]

const struct { ... } jack_status_table[]

Referenced by jack_status_to_str().

◆ status

jack_status_t status

Definition at line 149 of file app_jack.c.

Referenced by __ast_pbx_run(), __rtp_recvfrom(), __rtp_sendto(), _child_handler(), _iax2_show_peers_one(), _stun_show_status(), acf_odbc_read(), acf_odbc_write(), action_extensionstate(), agent_function_read(), agi_exec_full(), analog_publish_dnd_state(), answer(), ast_audiohook_update_status(), ast_privacy_set(), ast_safe_system(), ast_sip_create_dialog_uas(), ast_sip_create_dialog_uas_locked(), ast_sip_format_contact_ami(), ast_sip_get_contact_short_status_label(), ast_sip_get_contact_status_label(), ast_sip_send_response(), ast_sip_session_terminate(), ast_srtp_change_source(), ast_srtp_create(), ast_system_publish_registry(), AST_TEST_DEFINE(), AST_TEST_DEFINE(), AST_TEST_DEFINE(), AST_TEST_DEFINE(), AST_TEST_DEFINE(), ast_unreal_hangup(), callerid_read(), callerid_write(), canary_exit(), chan_pjsip_incoming_response(), chan_pjsip_incoming_response_update_cause(), chanavail_exec(), change_favorite_icon(), channel_fax_cb(), channel_set_intercept_mode(), cli_contact_print_body(), complete_dpreply(), connectedline_read(), connectedline_write(), contact_apply_handler(), contact_remove_unreachable(), create_dialog_uas(), digest_create_request_with_auth(), diversion_incoming_response(), diversion_outgoing_response(), dundi_show_peers(), filestream_destructor(), format_ami_contactlist_handler(), func_channel_read(), get_buddy_status(), handle_cdr_pgsql_status(), handle_cli_iax2_show_peer(), handle_cli_realtime_mysql_status(), handle_include_exec(), handle_incoming_response(), handle_outgoing_response(), handle_outgoing_response(), hfp_send_clip(), hfp_send_cmer(), iax2_publish_registry(), identify_module(), incoming_response(), init_jack_data(), jack_status_to_str(), join_queue(), load_pjsip(), log_jack_status(), mbl_status_exec(), meetme_stasis_cb(), member_status_available(), modlist_modentry(), options_incoming_request(), party_id_read(), party_id_write(), party_name_read(), party_name_write(), party_number_read(), party_number_write(), party_subaddress_read(), party_subaddress_write(), path_outgoing_response(), peer_status(), permanent_uri_handler(), process_log_list(), process_module_list(), process_text_message(), publish_dial_end_event(), publish_dial_end_event(), publish_dial_end_event(), publish_dnd_state(), publish_load_message(), publish_load_message_type(), publish_unload_message(), qualify_contact_cb(), queue_exec(), qupd_exec(), read_exec(), readexten_exec(), reason_header_outgoing_response(), redirecting_read(), redirecting_write(), refer_client_on_evsub_state(), refresh_all_favorite(), registrar_add_unreachable(), registration_client_send(), reload_module(), remove_from_queue(), report_fax_status(), rfc3326_incoming_response(), rfc3326_outgoing_response(), ring_entry(), rtp_transport_wide_cc_feedback_status_append(), rtp_transport_wide_cc_feedback_status_vector_append(), run_agi(), safe_exec_wait(), sdp_search(), send_expansion_icon(), send_expansion_short(), send_favorite(), send_favorite_selected(), send_favorite_short(), send_icon(), send_options_response(), send_response(), sendtext_exec(), session_inv_on_media_update(), session_on_rx_response(), setup_outbound_invite_auth(), shaun_of_the_dead(), show_entry_history(), sip_options_notify_endpoint_state_compositors(), sip_options_set_contact_status(), sip_options_update_endpoint_state_compositor_aor(), sip_publisher_service_queue(), sms_log(), system_create_resolver_and_set_nameservers(), system_registry_to_ami(), t38_reinvite_response_cb(), transfer_exec(), transport_create(), update_client_state_status(), update_status(), verify_log_result(), wait_for_answer(), wait_our_turn(), xfer_client_on_evsub_state(), xmpp_pak_presence(), xmpp_pak_s10n(), and xpidf_generate_body_content().

◆ str

const char* str

Definition at line 150 of file app_jack.c.

Referenced by acf_cut_exec(), active_channels_to_str(), add_hintdevice(), add_refer_param(), add_user_extension(), analog_my_getsigstr(), anti_injection(), anti_injection(), aoc_charge_type_str(), aoc_charged_item_str(), aoc_rate_type_str(), aoc_scale_str(), aoc_time_scale_str(), aoc_type_of_totaling_str(), aoc_volume_unit_str(), aocmessage_get_unit_entry(), append_event(), append_json(), append_json_single(), ari_websocket_process_request(), ast_ari_callback(), ast_ari_validate_date(), ast_begins_with(), ast_category_get_templates(), ast_cc_agent_set_interfaces_chanvar(), ast_copy_string(), ast_ends_with(), ast_event_append_ie_str(), ast_format_generate_sdp_fmtp(), ast_func_read(), ast_func_read2(), ast_get_character_str(), ast_get_digit_str(), ast_get_money_en_dollars_str(), ast_get_money_str(), ast_get_phonetic_str(), ast_hashtab_hash_string(), ast_hashtab_hash_string_nocase(), ast_hashtab_hash_string_sax(), ast_include_rename(), ast_json_utf8_check(), ast_json_utf8_check_len(), ast_json_vstringf(), ast_parse_digest(), ast_say_character_str(), ast_say_digit_str(), ast_say_money_str(), ast_say_phonetic_str(), ast_set_cc_interfaces_chanvar(), ast_sip_auth_digest_algorithms_vector_to_str(), ast_sip_global_default_outbound_endpoint(), ast_sip_pubsub_generate_body_content(), ast_sip_rdata_get_header_value(), ast_sip_security_mechanisms_to_str(), ast_skip_blanks(), ast_sockaddr_parse(), ast_sockaddr_resolve(), ast_sockaddr_split_hostport(), ast_sockaddr_stringify_fmt(), ast_str_case_hash(), ast_str_expr(), ast_str_get_encoded_str(), ast_str_hash(), ast_str_hash_add(), ast_str_retrieve_variable(), ast_str_to_imax(), ast_str_to_int(), ast_str_to_long(), ast_str_to_lower(), ast_str_to_uint(), ast_str_to_ulong(), ast_str_to_umax(), ast_str_to_upper(), ast_str_to_uuid(), ast_stream_str2state(), ast_string_to_time_t(), ast_tcptls_server_start(), ast_term_color_code(), AST_TEST_DEFINE(), AST_TEST_DEFINE(), AST_TEST_DEFINE(), AST_TEST_DEFINE(), AST_TEST_DEFINE(), AST_TEST_DEFINE(), AST_TEST_DEFINE(), AST_TEST_DEFINE(), AST_TEST_DEFINE(), AST_TEST_DEFINE(), AST_TEST_DEFINE(), AST_TEST_DEFINE(), AST_TEST_DEFINE(), AST_TEST_DEFINE(), AST_TEST_DEFINE(), AST_TEST_DEFINE(), AST_TEST_DEFINE(), AST_TEST_DEFINE(), AST_TEST_DEFINE(), AST_TEST_DEFINE(), ast_translate_path_to_str(), ast_trim_blanks(), ast_variable_list_join(), astman_append_json(), base64_helper(), blacklist_read2(), build_cc_interfaces_chanvar(), build_nonce(), build_user_routes(), candidate_exten_advance(), CB_ADD(), CB_ADD(), CB_ADD_LEN(), CB_ADD_LEN(), cc_extension_monitor_init(), cc_generic_agent_start_monitoring(), cc_unique_append(), celt_generate_sdp_fmtp(), check_event(), check_expr2_input(), check_mime(), check_mime(), cli_print_body(), collect_names_cb(), contacts_to_str(), copy_string(), coreshowchannelmap_add_to_map(), count_linefeeds(), custom_log(), custom_log(), dbl_list_expect_reverse(), delayed_method2str(), dial_handle_playtones(), dialog_info_to_string(), do_print(), dundi_ie_append_str(), ext_cmp_exten_strlen(), file_extension_from_string(), filter_leading_space_from_exprs(), filter_newlines(), find_realtime(), format_log_json(), format_str_append_auth(), function_fieldnum_helper(), function_fieldqty_helper(), g729_generate_sdp_fmtp(), geoloc_config_list_locations(), sip_to_pjsip::get_bind(), get_ipaddress(), h263_generate_sdp_fmtp(), h264_generate_sdp_fmtp(), handle_getvariablefull(), handle_playtones(), handle_show_translation_path(), handle_tcptls_connection(), hash_string(), iax_frame_subclass2str(), iax_ie_append_str(), iax_parse_ies(), ilbc_generate_sdp_fmtp(), import_helper(), import_read2(), init_appendbuf(), internalerror(), internalerror(), internaloutput(), internaloutput(), is_really_num(), jack_str(), jingle_new(), json_decode_read(), json_utf8_check_full(), list_item_to_str(), LLB_ADD(), load_modules(), localnet_to_str(), localnet_to_vl_append(), log_jack_status(), mansession_cmp_fn(), match_count(), match_to_str(), match_to_var_list_append(), mwi_subscription_mailboxes_str(), mwi_to_string(), my_getsigstr(), named_callgroups_to_str(), named_pickupgroups_to_str(), new_find_extension(), ParsingContext::next_stack(), opus_generate_sdp_fmtp(), parse_cdata(), password_digest_to_str(), pbx_retrieve_variable(), pidf_to_string(), pjsip_enable_logger_method(), pjstr_hash(), pjstr_hash_add(), pl_append(), pp_each_extension_helper(), pp_each_user_helper(), process_text_line(), pvalWordSetString(), pvt_cause_cmp_fn(), SqlConfigParser::read(), read_mf_digits(), read_sf_digits(), readwavheader(), regex(), remove_dialstatus_cb(), remove_spaces_before_equals(), replace(), res_sdp_crypto_parse_offer(), rtcp_payload_type2str(), say_character_str_full(), say_digit_str_full(), say_money_str_full(), say_phonetic_str_full(), security_event_stasis_cb(), security_mechanism_to_str(), sendtext_exec(), session_send_or_queue(), session_write(), set2(), set_var_to_str(), silk_generate_sdp_fmtp(), sip_endpoint_identifier_str2type(), sip_endpoint_identifier_type2str(), sip_is_token(), sip_outbound_registration_status_str(), sip_subscription_to_ami(), siren14_generate_sdp_fmtp(), siren7_generate_sdp_fmtp(), smdi_ifaces_cmp_fn(), smdi_mwi_q_cmp_fn(), stackpeek_read(), stasis_app_recording_if_exists_parse(), stasis_app_recording_termination_parse(), str2tech(), str_is_negative(), strbetween(), strreplace(), substitute_escapes(), tdd_generate(), test_2way_function(), test_chan_function(), test_chan_integer(), test_chan_integer_accessor(), test_chan_string(), test_chan_variable(), test_core_format_generate_sdp_fmtp(), test_expected_result(), transform::unicode(), ustmtext(), validate_location_info(), variable_count_cmp_fn(), vp8_generate_sdp_fmtp(), astconfigparser::write_dicts(), write_html_escaped(), xpidf_to_string(), and yyparse().