Asterisk - The Open Source Telephony Project GIT-master-0644429
app_jack.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2007 - 2008, Russell Bryant
5 *
6 * Russell Bryant <russell@digium.com>
7 *
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
13 *
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
17 */
18
19/*!
20 * \file
21 * \brief Jack Application
22 *
23 * \author Russell Bryant <russell@digium.com>
24 *
25 * This is an application to connect an Asterisk channel to an input
26 * and output jack port so that the audio can be processed through
27 * another application, or to play audio from another application.
28 *
29 * \extref http://www.jackaudio.org/
30 *
31 * \note To install libresample, check it out of the following repository:
32 * <code>$ svn co http://svn.digium.com/svn/thirdparty/libresample/trunk</code>
33 *
34 * \ingroup applications
35 */
36
37/*** MODULEINFO
38 <depend>jack</depend>
39 <depend>resample</depend>
40 <support_level>extended</support_level>
41 ***/
42
43#include "asterisk.h"
44
45#include <limits.h>
46
47#include <jack/jack.h>
48#include <jack/ringbuffer.h>
49
50#include <libresample.h>
51
52#include "asterisk/module.h"
53#include "asterisk/channel.h"
54#include "asterisk/strings.h"
55#include "asterisk/lock.h"
56#include "asterisk/app.h"
57#include "asterisk/pbx.h"
58#include "asterisk/audiohook.h"
60
61#define RESAMPLE_QUALITY 1
62
63/* The number of frames the ringbuffers can store. The actual size is RINGBUFFER_FRAME_CAPACITY * jack_data->frame_datalen */
64#define RINGBUFFER_FRAME_CAPACITY 100
65
66/*! \brief Common options between the Jack() app and JACK_HOOK() function */
67#define COMMON_OPTIONS \
68" s(<name>) - Connect to the specified jack server name.\n" \
69" i(<name>) - Connect the output port that gets created to the specified\n" \
70" jack input port.\n" \
71" o(<name>) - Connect the input port that gets created to the specified\n" \
72" jack output port.\n" \
73" n - Do not automatically start the JACK server if it is not already\n" \
74" running.\n" \
75" c(<name>) - By default, Asterisk will use the channel name for the jack client\n" \
76" name. Use this option to specify a custom client name.\n"
77/*** DOCUMENTATION
78 <application name="JACK" language="en_US">
79 <synopsis>
80 Jack Audio Connection Kit
81 </synopsis>
82 <syntax>
83 <parameter name="options" required="false">
84 <optionlist>
85 <option name="s">
86 <argument name="name" required="true">
87 <para>Connect to the specified jack server name</para>
88 </argument>
89 </option>
90 <option name="i">
91 <argument name="name" required="true">
92 <para>Connect the output port that gets created to the specified jack input port</para>
93 </argument>
94 </option>
95 <option name="o">
96 <argument name="name" required="true">
97 <para>Connect the input port that gets created to the specified jack output port</para>
98 </argument>
99 </option>
100 <option name="c">
101 <argument name="name" required="true">
102 <para>By default, Asterisk will use the channel name for the jack client name.</para>
103 <para>Use this option to specify a custom client name.</para>
104 </argument>
105 </option>
106 </optionlist>
107 </parameter>
108 </syntax>
109 <description>
110 <para>When executing this application, two jack ports will be created;
111 one input and one output. Other applications can be hooked up to
112 these ports to access audio coming from, or being send to the channel.</para>
113 </description>
114 </application>
115 ***/
116
117static const char jack_app[] = "JACK";
118
119struct jack_data {
125 );
126 jack_client_t *client;
127 jack_port_t *input_port;
128 jack_port_t *output_port;
129 jack_ringbuffer_t *input_rb;
130 jack_ringbuffer_t *output_rb;
132 unsigned int audiohook_rate;
133 unsigned int frame_datalen;
138 unsigned int stop:1;
139 unsigned int has_audiohook:1;
140 unsigned int no_start_server:1;
141 /*! Only used with JACK_HOOK */
143};
144
145static const struct {
146 jack_status_t status;
147 const char *str;
148} jack_status_table[] = {
149 { JackFailure, "Failure" },
150 { JackInvalidOption, "Invalid Option" },
151 { JackNameNotUnique, "Name Not Unique" },
152 { JackServerStarted, "Server Started" },
153 { JackServerFailed, "Server Failed" },
154 { JackServerError, "Server Error" },
155 { JackNoSuchClient, "No Such Client" },
156 { JackLoadFailure, "Load Failure" },
157 { JackInitFailure, "Init Failure" },
158 { JackShmFailure, "Shared Memory Access Failure" },
159 { JackVersionError, "Version Mismatch" },
161
162static const char *jack_status_to_str(jack_status_t status)
163{
164 int i;
165
166 for (i = 0; i < ARRAY_LEN(jack_status_table); i++) {
168 return jack_status_table[i].str;
169 }
170
171 return "Unknown Error";
172}
173
174static void log_jack_status(const char *prefix, jack_status_t status)
175{
176 struct ast_str *str = ast_str_alloca(512);
177 int i, first = 0;
178
179 for (i = 0; i < (sizeof(status) * 8); i++) {
180 if (!(status & (1 << i)))
181 continue;
182
183 if (!first) {
184 ast_str_set(&str, 0, "%s", jack_status_to_str((1 << i)));
185 first = 1;
186 } else
187 ast_str_append(&str, 0, ", %s", jack_status_to_str((1 << i)));
188 }
189
191}
192
193static int alloc_resampler(struct jack_data *jack_data, int input)
194{
195 double from_srate, to_srate, jack_srate;
196 void **resampler;
197 double *resample_factor;
198
200 return 0;
201
203 return 0;
204
205 jack_srate = jack_get_sample_rate(jack_data->client);
206
207 to_srate = input ? jack_data->audiohook_rate : jack_srate;
208 from_srate = input ? jack_srate : jack_data->audiohook_rate;
209
210 resample_factor = input ? &jack_data->input_resample_factor :
212
213 if (from_srate == to_srate) {
214 /* Awesome! The jack sample rate is the same as ours.
215 * Resampling isn't needed. */
216 *resample_factor = 1.0;
217 return 0;
218 }
219
220 *resample_factor = to_srate / from_srate;
221
222 resampler = input ? &jack_data->input_resampler :
224
225 if (!(*resampler = resample_open(RESAMPLE_QUALITY,
226 *resample_factor, *resample_factor))) {
227 ast_log(LOG_ERROR, "Failed to open %s resampler\n",
228 input ? "input" : "output");
229 return -1;
230 }
231
232 return 0;
233}
234
235/*!
236 * \brief Handle jack input port
237 *
238 * Read nframes number of samples from the input buffer, resample it
239 * if necessary, and write it into the appropriate ringbuffer.
240 */
241static void handle_input(void *buf, jack_nframes_t nframes,
242 struct jack_data *jack_data)
243{
244 short s_buf[nframes];
245 float *in_buf = buf;
246 size_t res;
247 int i;
248 size_t write_len = sizeof(s_buf);
249
251 int total_in_buf_used = 0;
252 int total_out_buf_used = 0;
253 float f_buf[nframes + 1];
254
255 memset(f_buf, 0, sizeof(f_buf));
256
257 while (total_in_buf_used < nframes) {
258 int in_buf_used;
259 int out_buf_used;
260
261 out_buf_used = resample_process(jack_data->input_resampler,
263 &in_buf[total_in_buf_used], nframes - total_in_buf_used,
264 0, &in_buf_used,
265 &f_buf[total_out_buf_used], ARRAY_LEN(f_buf) - total_out_buf_used);
266
267 if (out_buf_used < 0)
268 break;
269
270 total_out_buf_used += out_buf_used;
271 total_in_buf_used += in_buf_used;
272
273 if (total_out_buf_used == ARRAY_LEN(f_buf)) {
274 ast_log(LOG_ERROR, "Output buffer filled ... need to increase its size, "
275 "nframes '%d', total_out_buf_used '%d'\n", nframes, total_out_buf_used);
276 break;
277 }
278 }
279
280 for (i = 0; i < total_out_buf_used; i++)
281 s_buf[i] = f_buf[i] * (SHRT_MAX / 1.0);
282
283 write_len = total_out_buf_used * sizeof(int16_t);
284 } else {
285 /* No resampling needed */
286
287 for (i = 0; i < nframes; i++)
288 s_buf[i] = in_buf[i] * (SHRT_MAX / 1.0);
289 }
290
291 res = jack_ringbuffer_write(jack_data->input_rb, (const char *) s_buf, write_len);
292 if (res != write_len) {
293 ast_log(LOG_WARNING, "Tried to write %d bytes to the ringbuffer, but only wrote %d\n",
294 (int) sizeof(s_buf), (int) res);
295 }
296}
297
298/*!
299 * \brief Handle jack output port
300 *
301 * Read nframes number of samples from the ringbuffer and write it out to the
302 * output port buffer.
303 */
304static void handle_output(void *buf, jack_nframes_t nframes,
305 struct jack_data *jack_data)
306{
307 size_t res, len;
308
309 len = nframes * sizeof(float);
310
311 res = jack_ringbuffer_read(jack_data->output_rb, buf, len);
312
313 if (len != res) {
314 ast_debug(2, "Wanted %d bytes to send to the output port, "
315 "but only got %d\n", (int) len, (int) res);
316 }
317}
318
319static int jack_process(jack_nframes_t nframes, void *arg)
320{
321 struct jack_data *jack_data = arg;
322 void *input_port_buf, *output_port_buf;
323
326
327 input_port_buf = jack_port_get_buffer(jack_data->input_port, nframes);
328 handle_input(input_port_buf, nframes, jack_data);
329
330 output_port_buf = jack_port_get_buffer(jack_data->output_port, nframes);
331 handle_output(output_port_buf, nframes, jack_data);
332
333 return 0;
334}
335
336static void jack_shutdown(void *arg)
337{
338 struct jack_data *jack_data = arg;
339
340 jack_data->stop = 1;
341}
342
344{
345 if (jack_data->input_port) {
346 jack_port_unregister(jack_data->client, jack_data->input_port);
348 }
349
350 if (jack_data->output_port) {
351 jack_port_unregister(jack_data->client, jack_data->output_port);
353 }
354
355 if (jack_data->client) {
356 jack_client_close(jack_data->client);
358 }
359
360 if (jack_data->input_rb) {
361 jack_ringbuffer_free(jack_data->input_rb);
363 }
364
365 if (jack_data->output_rb) {
366 jack_ringbuffer_free(jack_data->output_rb);
368 }
369
371 resample_close(jack_data->output_resampler);
373 }
374
376 resample_close(jack_data->input_resampler);
378 }
379
382
384
386
387 return NULL;
388}
389
390static int init_jack_data(struct ast_channel *chan, struct jack_data *jack_data)
391{
392 const char *client_name;
393 jack_status_t status = 0;
394 jack_options_t jack_options = JackNullOption;
395
396 unsigned int channel_rate;
397
398 unsigned int ringbuffer_size;
399
400 /* Deducing audiohook sample rate from channel format
401 ATTENTION: Might be problematic, if channel has different sampling than used by audiohook!
402 */
406
407 /* Guessing frame->datalen assuming a ptime of 20ms */
409
411
412 ast_debug(1, "Audiohook parameters: slin-format:%s, rate:%d, frame-len:%d, ringbuffer_size: %d\n",
414
417 } else {
418 ast_channel_lock(chan);
420 ast_channel_unlock(chan);
421 }
422
423 if (!(jack_data->output_rb = jack_ringbuffer_create(ringbuffer_size)))
424 return -1;
425
426 if (!(jack_data->input_rb = jack_ringbuffer_create(ringbuffer_size)))
427 return -1;
428
430 jack_options |= JackNoStartServer;
431
433 jack_options |= JackServerName;
434 jack_data->client = jack_client_open(client_name, jack_options, &status,
436 } else {
437 jack_data->client = jack_client_open(client_name, jack_options, &status);
438 }
439
440 if (status)
441 log_jack_status("Client Open Status", status);
442
443 if (!jack_data->client)
444 return -1;
445
446 jack_data->input_port = jack_port_register(jack_data->client, "input",
447 JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput | JackPortIsTerminal, 0);
448 if (!jack_data->input_port) {
449 ast_log(LOG_ERROR, "Failed to create input port for jack port\n");
450 return -1;
451 }
452
453 jack_data->output_port = jack_port_register(jack_data->client, "output",
454 JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput | JackPortIsTerminal, 0);
455 if (!jack_data->output_port) {
456 ast_log(LOG_ERROR, "Failed to create output port for jack port\n");
457 return -1;
458 }
459
460 if (jack_set_process_callback(jack_data->client, jack_process, jack_data)) {
461 ast_log(LOG_ERROR, "Failed to register process callback with jack client\n");
462 return -1;
463 }
464
465 jack_on_shutdown(jack_data->client, jack_shutdown, jack_data);
466
467 if (jack_activate(jack_data->client)) {
468 ast_log(LOG_ERROR, "Unable to activate jack client\n");
469 return -1;
470 }
471
473 const char **ports;
474 int i;
475
476 ports = jack_get_ports(jack_data->client, jack_data->connect_input_port,
477 NULL, JackPortIsInput);
478
479 if (!ports) {
480 ast_log(LOG_ERROR, "No input port matching '%s' was found\n",
482 break;
483 }
484
485 for (i = 0; ports[i]; i++) {
486 ast_debug(1, "Found port '%s' that matched specified input port '%s'\n",
487 ports[i], jack_data->connect_input_port);
488 }
489
490 if (jack_connect(jack_data->client, jack_port_name(jack_data->output_port), ports[0])) {
491 ast_log(LOG_ERROR, "Failed to connect '%s' to '%s'\n", ports[0],
492 jack_port_name(jack_data->output_port));
493 } else {
494 ast_debug(1, "Connected '%s' to '%s'\n", ports[0],
495 jack_port_name(jack_data->output_port));
496 }
497
498 jack_free(ports);
499
500 break;
501 }
502
504 const char **ports;
505 int i;
506
507 ports = jack_get_ports(jack_data->client, jack_data->connect_output_port,
508 NULL, JackPortIsOutput);
509
510 if (!ports) {
511 ast_log(LOG_ERROR, "No output port matching '%s' was found\n",
513 break;
514 }
515
516 for (i = 0; ports[i]; i++) {
517 ast_debug(1, "Found port '%s' that matched specified output port '%s'\n",
518 ports[i], jack_data->connect_output_port);
519 }
520
521 if (jack_connect(jack_data->client, ports[0], jack_port_name(jack_data->input_port))) {
522 ast_log(LOG_ERROR, "Failed to connect '%s' to '%s'\n", ports[0],
523 jack_port_name(jack_data->input_port));
524 } else {
525 ast_debug(1, "Connected '%s' to '%s'\n", ports[0],
526 jack_port_name(jack_data->input_port));
527 }
528
529 jack_free(ports);
530
531 break;
532 }
533
534 return 0;
535}
536
537static int queue_voice_frame(struct jack_data *jack_data, struct ast_frame *f)
538{
539 float f_buf[f->samples * 8];
540 size_t f_buf_used = 0;
541 int i;
542 int16_t *s_buf = f->data.ptr;
543 size_t res;
544
545 memset(f_buf, 0, sizeof(f_buf));
546
549
551 float in_buf[f->samples];
552 int total_in_buf_used = 0;
553 int total_out_buf_used = 0;
554
555 memset(in_buf, 0, sizeof(in_buf));
556
557 for (i = 0; i < f->samples; i++)
558 in_buf[i] = s_buf[i] * (1.0 / SHRT_MAX);
559
560 while (total_in_buf_used < ARRAY_LEN(in_buf)) {
561 int in_buf_used;
562 int out_buf_used;
563
564 out_buf_used = resample_process(jack_data->output_resampler,
566 &in_buf[total_in_buf_used], ARRAY_LEN(in_buf) - total_in_buf_used,
567 0, &in_buf_used,
568 &f_buf[total_out_buf_used], ARRAY_LEN(f_buf) - total_out_buf_used);
569
570 if (out_buf_used < 0)
571 break;
572
573 total_out_buf_used += out_buf_used;
574 total_in_buf_used += in_buf_used;
575
576 if (total_out_buf_used == ARRAY_LEN(f_buf)) {
577 ast_log(LOG_ERROR, "Output buffer filled ... need to increase its size\n");
578 break;
579 }
580 }
581
582 f_buf_used = total_out_buf_used;
583 if (f_buf_used > ARRAY_LEN(f_buf))
584 f_buf_used = ARRAY_LEN(f_buf);
585 } else {
586 /* No resampling needed */
587
588 for (i = 0; i < f->samples; i++)
589 f_buf[i] = s_buf[i] * (1.0 / SHRT_MAX);
590
591 f_buf_used = f->samples;
592 }
593
594 res = jack_ringbuffer_write(jack_data->output_rb, (const char *) f_buf, f_buf_used * sizeof(float));
595 if (res != (f_buf_used * sizeof(float))) {
596 ast_log(LOG_WARNING, "Tried to write %d bytes to the ringbuffer, but only wrote %d\n",
597 (int) (f_buf_used * sizeof(float)), (int) res);
598 }
599 return 0;
600}
601
602/*!
603 * \brief handle jack audio
604 *
605 * \param[in] chan The Asterisk channel to write the frames to if no output frame
606 * is provided.
607 * \param[in] jack_data This is the jack_data struct that contains the input
608 * ringbuffer that audio will be read from.
609 * \param[out] out_frame If this argument is non-NULL, then assuming there is
610 * enough data avilable in the ringbuffer, the audio in this frame
611 * will get replaced with audio from the input buffer. If there is
612 * not enough data available to read at this time, then the frame
613 * data gets zeroed out.
614 *
615 * Read data from the input ringbuffer, which is the properly resampled audio
616 * that was read from the jack input port. Write it to the channel in 20 ms frames,
617 * or fill up an output frame instead if one is provided.
618 */
619static void handle_jack_audio(struct ast_channel *chan, struct jack_data *jack_data,
620 struct ast_frame *out_frame)
621{
623 struct ast_frame f = {
625 .subclass.format = jack_data->audiohook_format,
626 .src = "JACK",
627 .data.ptr = buf,
628 .datalen = sizeof(buf),
630 };
631
632 for (;;) {
633 size_t res, read_len;
634 char *read_buf;
635
636 read_len = out_frame ? out_frame->datalen : sizeof(buf);
637 read_buf = out_frame ? out_frame->data.ptr : buf;
638
639 res = jack_ringbuffer_read_space(jack_data->input_rb);
640
641 if (res < read_len) {
642 /* Not enough data ready for another frame, move on ... */
643 if (out_frame) {
644 ast_debug(1, "Sending an empty frame for the JACK_HOOK\n");
645 memset(out_frame->data.ptr, 0, out_frame->datalen);
646 }
647 break;
648 }
649
650 res = jack_ringbuffer_read(jack_data->input_rb, (char *) read_buf, read_len);
651
652 if (res < read_len) {
653 ast_log(LOG_ERROR, "Error reading from ringbuffer, even though it said there was enough data\n");
654 break;
655 }
656
657 if (out_frame) {
658 /* If an output frame was provided, then we just want to fill up the
659 * buffer in that frame and return. */
660 break;
661 }
662
663 ast_write(chan, &f);
664 }
665}
666
667enum {
668 OPT_SERVER_NAME = (1 << 0),
669 OPT_INPUT_PORT = (1 << 1),
670 OPT_OUTPUT_PORT = (1 << 2),
672 OPT_CLIENT_NAME = (1 << 4),
673};
674
675enum {
680
681 /* Must be the last element */
683};
684
692
693static struct jack_data *jack_data_alloc(void)
694{
695 struct jack_data *jack_data;
696
697 if (!(jack_data = ast_calloc_with_stringfields(1, struct jack_data, 32))) {
698 return NULL;
699 }
700
701 return jack_data;
702}
703
704/*!
705 * \note This must be done before calling init_jack_data().
706 */
707static int handle_options(struct jack_data *jack_data, const char *__options_str)
708{
709 struct ast_flags options = { 0, };
711 char *options_str;
712
713 options_str = ast_strdupa(__options_str);
714
716
720 else {
721 ast_log(LOG_ERROR, "A server name must be provided with the s() option\n");
722 return -1;
723 }
724 }
725
729 else {
730 ast_log(LOG_ERROR, "A client name must be provided with the c() option\n");
731 return -1;
732 }
733 }
734
738 else {
739 ast_log(LOG_ERROR, "A name must be provided with the i() option\n");
740 return -1;
741 }
742 }
743
747 else {
748 ast_log(LOG_ERROR, "A name must be provided with the o() option\n");
749 return -1;
750 }
751 }
752
754
755 return 0;
756}
757
758static int jack_exec(struct ast_channel *chan, const char *data)
759{
760 struct jack_data *jack_data;
761
762 if (!(jack_data = jack_data_alloc()))
763 return -1;
764
765 if (!ast_strlen_zero(data) && handle_options(jack_data, data)) {
767 return -1;
768 }
769
770 if (init_jack_data(chan, jack_data)) {
772 return -1;
773 }
774
777 return -1;
778 }
779
782 return -1;
783 }
784
785 while (!jack_data->stop) {
786 struct ast_frame *f;
787
788 if (ast_waitfor(chan, -1) < 0) {
789 break;
790 }
791
792 f = ast_read(chan);
793 if (!f) {
794 jack_data->stop = 1;
795 continue;
796 }
797
798 switch (f->frametype) {
801 jack_data->stop = 1;
802 break;
803 case AST_FRAME_VOICE:
805 default:
806 break;
807 }
808
809 ast_frfree(f);
810
812 }
813
815
816 return 0;
817}
818
819static void jack_hook_ds_destroy(void *data)
820{
821 struct jack_data *jack_data = data;
822
824}
825
827 .type = "JACK_HOOK",
828 .destroy = jack_hook_ds_destroy,
829};
830
831static int jack_hook_callback(struct ast_audiohook *audiohook, struct ast_channel *chan,
832 struct ast_frame *frame, enum ast_audiohook_direction direction)
833{
834 struct ast_datastore *datastore;
835 struct jack_data *jack_data;
836
838 return 0;
839
841 return 0;
842
843 if (frame->frametype != AST_FRAME_VOICE)
844 return 0;
845
846 ast_channel_lock(chan);
847
848 if (!(datastore = ast_channel_datastore_find(chan, &jack_hook_ds_info, NULL))) {
849 ast_log(LOG_ERROR, "JACK_HOOK datastore not found for '%s'\n", ast_channel_name(chan));
850 ast_channel_unlock(chan);
851 return -1;
852 }
853
854 jack_data = datastore->data;
855
857 ast_log(LOG_WARNING, "Expected frame in %s for the audiohook, but got format %s\n",
860 ast_channel_unlock(chan);
861 return 0;
862 }
863
865
866 handle_jack_audio(chan, jack_data, frame);
867
868 ast_channel_unlock(chan);
869
870 return 0;
871}
872
873static int enable_jack_hook(struct ast_channel *chan, char *data)
874{
875 struct ast_datastore *datastore;
876 struct jack_data *jack_data = NULL;
878 AST_APP_ARG(mode);
880 );
881
883
884 ast_channel_lock(chan);
885
886 if ((datastore = ast_channel_datastore_find(chan, &jack_hook_ds_info, NULL))) {
887 ast_log(LOG_ERROR, "JACK_HOOK already enabled for '%s'\n", ast_channel_name(chan));
888 goto return_error;
889 }
890
891 if (ast_strlen_zero(args.mode) || strcasecmp(args.mode, "manipulate")) {
892 ast_log(LOG_ERROR, "'%s' is not a supported mode. Only manipulate is supported.\n",
893 S_OR(args.mode, "<none>"));
894 goto return_error;
895 }
896
897 if (!(jack_data = jack_data_alloc()))
898 goto return_error;
899
900 if (!ast_strlen_zero(args.options) && handle_options(jack_data, args.options))
901 goto return_error;
902
903 if (init_jack_data(chan, jack_data))
904 goto return_error;
905
906 if (!(datastore = ast_datastore_alloc(&jack_hook_ds_info, NULL)))
907 goto return_error;
908
912
913 datastore->data = jack_data;
914
916 goto return_error;
917
918 if (ast_channel_datastore_add(chan, datastore))
919 goto return_error;
920
921 ast_channel_unlock(chan);
922
923 return 0;
924
925return_error:
926 ast_channel_unlock(chan);
927
928 if (jack_data) {
930 }
931
932 if (datastore) {
933 datastore->data = NULL;
934 ast_datastore_free(datastore);
935 }
936
937 return -1;
938}
939
940static int disable_jack_hook(struct ast_channel *chan)
941{
942 struct ast_datastore *datastore;
943 struct jack_data *jack_data;
944
945 ast_channel_lock(chan);
946
947 if (!(datastore = ast_channel_datastore_find(chan, &jack_hook_ds_info, NULL))) {
948 ast_channel_unlock(chan);
949 ast_log(LOG_WARNING, "No JACK_HOOK found to disable\n");
950 return -1;
951 }
952
953 ast_channel_datastore_remove(chan, datastore);
954
955 jack_data = datastore->data;
957
958 /* Keep the channel locked while we destroy the datastore, so that we can
959 * ensure that all of the jack stuff is stopped just in case another frame
960 * tries to come through the audiohook callback. */
961 ast_datastore_free(datastore);
962
963 ast_channel_unlock(chan);
964
965 return 0;
966}
967
968static int jack_hook_write(struct ast_channel *chan, const char *cmd, char *data,
969 const char *value)
970{
971 int res;
972
973 if (!chan) {
974 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
975 return -1;
976 }
977
978 if (!strcasecmp(value, "on"))
979 res = enable_jack_hook(chan, data);
980 else if (!strcasecmp(value, "off"))
981 res = disable_jack_hook(chan);
982 else {
983 ast_log(LOG_ERROR, "'%s' is not a valid value for JACK_HOOK()\n", value);
984 res = -1;
985 }
986
987 return res;
988}
989
991 .name = "JACK_HOOK",
992 .synopsis = "Enable a jack hook on a channel",
993 .syntax = "JACK_HOOK(<mode>,[options])",
994 .desc =
995 " The JACK_HOOK allows turning on or off jack connectivity to this channel.\n"
996 "When the JACK_HOOK is turned on, jack ports will get created that allow\n"
997 "access to the audio stream for this channel. The mode specifies which mode\n"
998 "this hook should run in. A mode must be specified when turning the JACK_HOOK.\n"
999 "on. However, all arguments are optional when turning it off.\n"
1000 "\n"
1001 " Valid modes are:\n"
1002#if 0
1003 /* XXX TODO */
1004 " spy - Create a read-only audio hook. Only an output jack port will\n"
1005 " get created.\n"
1006 " whisper - Create a write-only audio hook. Only an input jack port will\n"
1007 " get created.\n"
1008#endif
1009 " manipulate - Create a read/write audio hook. Both an input and an output\n"
1010 " jack port will get created. Audio from the channel will be\n"
1011 " sent out the output port and will be replaced by the audio\n"
1012 " coming in on the input port as it gets passed on.\n"
1013 "\n"
1014 " Valid options are:\n"
1016 "\n"
1017 " Examples:\n"
1018 " To turn on the JACK_HOOK,\n"
1019 " Set(JACK_HOOK(manipulate,i(pure_data_0:input0)o(pure_data_0:output0))=on)\n"
1020 " To turn off the JACK_HOOK,\n"
1021 " Set(JACK_HOOK()=off)\n"
1022 "",
1023 .write = jack_hook_write,
1024};
1025
1026static int unload_module(void)
1027{
1028 int res;
1029
1032
1033 return res;
1034}
1035
1036static int load_module(void)
1037{
1040 }
1041
1045 }
1046
1048}
1049
static struct jack_data * destroy_jack_data(struct jack_data *jack_data)
Definition: app_jack.c:343
static int queue_voice_frame(struct jack_data *jack_data, struct ast_frame *f)
Definition: app_jack.c:537
static int jack_process(jack_nframes_t nframes, void *arg)
Definition: app_jack.c:319
static const struct @27 jack_status_table[]
static void handle_output(void *buf, jack_nframes_t nframes, struct jack_data *jack_data)
Handle jack output port.
Definition: app_jack.c:304
AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "JACK Interface")
#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:826
static const char * jack_status_to_str(jack_status_t status)
Definition: app_jack.c:162
static int disable_jack_hook(struct ast_channel *chan)
Definition: app_jack.c:940
static void handle_input(void *buf, jack_nframes_t nframes, struct jack_data *jack_data)
Handle jack input port.
Definition: app_jack.c:241
@ OPT_CLIENT_NAME
Definition: app_jack.c:672
@ OPT_SERVER_NAME
Definition: app_jack.c:668
@ OPT_INPUT_PORT
Definition: app_jack.c:669
@ OPT_OUTPUT_PORT
Definition: app_jack.c:670
@ OPT_NOSTART_SERVER
Definition: app_jack.c:671
static int enable_jack_hook(struct ast_channel *chan, char *data)
Definition: app_jack.c:873
static void jack_hook_ds_destroy(void *data)
Definition: app_jack.c:819
static int handle_options(struct jack_data *jack_data, const char *__options_str)
Definition: app_jack.c:707
static struct ast_custom_function jack_hook_function
Definition: app_jack.c:990
static int init_jack_data(struct ast_channel *chan, struct jack_data *jack_data)
Definition: app_jack.c:390
static struct jack_data * jack_data_alloc(void)
Definition: app_jack.c:693
static int jack_exec(struct ast_channel *chan, const char *data)
Definition: app_jack.c:758
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:831
#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:968
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:619
#define RESAMPLE_QUALITY
Definition: app_jack.c:61
static void jack_shutdown(void *arg)
Definition: app_jack.c:336
@ OPT_ARG_CLIENT_NAME
Definition: app_jack.c:679
@ OPT_ARG_SERVER_NAME
Definition: app_jack.c:676
@ OPT_ARG_OUTPUT_PORT
Definition: app_jack.c:678
@ OPT_ARG_INPUT_PORT
Definition: app_jack.c:677
@ OPT_ARG_ARRAY_SIZE
Definition: app_jack.c:682
static void log_jack_status(const char *prefix, jack_status_t status)
Definition: app_jack.c:174
jack_status_t status
Definition: app_jack.c:146
static int load_module(void)
Definition: app_jack.c:1036
static const struct ast_app_option jack_exec_options[128]
Definition: app_jack.c:691
static int unload_module(void)
Definition: app_jack.c:1026
static const char jack_app[]
Definition: app_jack.c:117
static int alloc_resampler(struct jack_data *jack_data, int input)
Definition: app_jack.c:193
const char * str
Definition: app_jack.c:147
option_args
Definition: app_skel.c:141
struct sla_ringing_trunk * first
Definition: app_sla.c:332
static int input(yyscan_t yyscanner)
Definition: ast_expr2f.c:1570
Asterisk main include file. File version handling, generic pbx functions.
#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
Audiohooks Architecture.
@ 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:550
int ast_audiohook_attach(struct ast_channel *chan, struct ast_audiohook *audiohook)
Attach audiohook to channel.
Definition: audiohook.c:484
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
General Asterisk PBX channel definitions.
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:2404
int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore)
Remove a datastore from a channel.
Definition: channel.c:2413
#define ast_channel_lock(chan)
Definition: channel.h:2968
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition: channel.c:3181
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:5163
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4276
int ast_set_read_format(struct ast_channel *chan, struct ast_format *format)
Sets read format on channel chan.
Definition: channel.c:5781
int ast_set_write_format(struct ast_channel *chan, struct ast_format *format)
Sets write format on channel chan.
Definition: channel.c:5822
#define ast_channel_unlock(chan)
Definition: channel.h:2969
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:2418
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
short int16_t
Definition: db.h:59
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
Media Format Cache API.
struct ast_format * ast_format_cache_get_slin_by_rate(unsigned int rate)
Retrieve the best signed linear format given a sample rate.
Definition: format_cache.c:512
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
Application convenience functions, designed to give consistent look and feel to Asterisk apps.
#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_VOICE
@ AST_FRAME_CONTROL
@ AST_CONTROL_HANGUP
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define LOG_NOTICE
#define LOG_WARNING
Asterisk locking-related definitions:
Asterisk module definitions.
#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
@ 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
Core PBX routines and definitions.
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1558
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
#define NULL
Definition: resample.c:96
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
Definition: stringfields.h:341
#define ast_calloc_with_stringfields(n, type, size)
Allocate a structure with embedded stringfields in a single allocation.
Definition: stringfields.h:432
#define AST_STRING_FIELD(name)
Declare a string field.
Definition: stringfields.h:303
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:521
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374
String manipulation functions.
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
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
#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
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:199
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
union ast_frame::@226 data
enum ast_frame_type frametype
Support for dynamic strings.
Definition: strings.h:623
jack_ringbuffer_t * input_rb
Definition: app_jack.c:129
unsigned int stop
Definition: app_jack.c:138
jack_port_t * output_port
Definition: app_jack.c:128
double output_resample_factor
Definition: app_jack.c:135
struct ast_format * audiohook_format
Definition: app_jack.c:131
const ast_string_field client_name
Definition: app_jack.c:125
void * input_resampler
Definition: app_jack.c:136
const ast_string_field connect_input_port
Definition: app_jack.c:125
double input_resample_factor
Definition: app_jack.c:137
jack_ringbuffer_t * output_rb
Definition: app_jack.c:130
void * output_resampler
Definition: app_jack.c:134
unsigned int frame_datalen
Definition: app_jack.c:133
const ast_string_field connect_output_port
Definition: app_jack.c:125
unsigned int no_start_server
Definition: app_jack.c:140
struct ast_audiohook audiohook
Definition: app_jack.c:142
const ast_string_field server_name
Definition: app_jack.c:125
unsigned int has_audiohook
Definition: app_jack.c:139
unsigned int audiohook_rate
Definition: app_jack.c:132
jack_port_t * input_port
Definition: app_jack.c:127
jack_client_t * client
Definition: app_jack.c:126
int value
Definition: syslog.c:37
const char * args
static struct test_options options
#define ast_test_flag(p, flag)
Definition: utils.h:63
#define ARRAY_LEN(a)
Definition: utils.h:666