Merged revisions 140566 via svnmerge from
[asterisk-bristuff.git] / apps / app_jack.c
blob4da4c9f8b19983d033fba0c47a149a23342f4614
1 /*
2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 2007 - 2008, Russell Bryant
6 * Russell Bryant <russell@digium.com>
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.
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.
19 /*!
20 * \file
21 * \brief Jack Application
23 * \author Russell Bryant <russell@digium.com>
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.
29 * \arg http://www.jackaudio.org/
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>
34 * \ingroup applications
37 /*** MODULEINFO
38 <depend>jack</depend>
39 <depend>resample</depend>
40 ***/
42 #include "asterisk.h"
44 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
46 #include <limits.h>
48 #include <jack/jack.h>
49 #include <jack/ringbuffer.h>
51 #include <libresample.h>
53 #include "asterisk/module.h"
54 #include "asterisk/channel.h"
55 #include "asterisk/strings.h"
56 #include "asterisk/lock.h"
57 #include "asterisk/app.h"
58 #include "asterisk/pbx.h"
59 #include "asterisk/audiohook.h"
61 #define RESAMPLE_QUALITY 1
63 #define RINGBUFFER_SIZE 16384
65 /*! \brief Common options between the Jack() app and JACK_HOOK() function */
66 #define COMMON_OPTIONS \
67 " s(<name>) - Connect to the specified jack server name.\n" \
68 " i(<name>) - Connect the output port that gets created to the specified\n" \
69 " jack input port.\n" \
70 " o(<name>) - Connect the input port that gets created to the specified\n" \
71 " jack output port.\n" \
72 " n - Do not automatically start the JACK server if it is not already\n" \
73 " running.\n" \
74 " c(<name>) - By default, Asterisk will use the channel name for the jack client\n" \
75 " name. Use this option to specify a custom client name.\n"
77 static char *jack_app = "JACK";
78 static char *jack_synopsis =
79 "JACK (Jack Audio Connection Kit) Application";
80 static char *jack_desc =
81 "JACK([options])\n"
82 " When this application is executed, two jack ports will be created; one input\n"
83 "and one output. Other applications can be hooked up to these ports to access\n"
84 "the audio coming from, or being sent to the channel.\n"
85 " Valid options:\n"
86 COMMON_OPTIONS
87 "";
89 struct jack_data {
90 AST_DECLARE_STRING_FIELDS(
91 AST_STRING_FIELD(server_name);
92 AST_STRING_FIELD(client_name);
93 AST_STRING_FIELD(connect_input_port);
94 AST_STRING_FIELD(connect_output_port);
96 jack_client_t *client;
97 jack_port_t *input_port;
98 jack_port_t *output_port;
99 jack_ringbuffer_t *input_rb;
100 jack_ringbuffer_t *output_rb;
101 void *output_resampler;
102 double output_resample_factor;
103 void *input_resampler;
104 double input_resample_factor;
105 unsigned int stop:1;
106 unsigned int has_audiohook:1;
107 unsigned int no_start_server:1;
108 /*! Only used with JACK_HOOK */
109 struct ast_audiohook audiohook;
112 static const struct {
113 jack_status_t status;
114 const char *str;
115 } jack_status_table[] = {
116 { JackFailure, "Failure" },
117 { JackInvalidOption, "Invalid Option" },
118 { JackNameNotUnique, "Name Not Unique" },
119 { JackServerStarted, "Server Started" },
120 { JackServerFailed, "Server Failed" },
121 { JackServerError, "Server Error" },
122 { JackNoSuchClient, "No Such Client" },
123 { JackLoadFailure, "Load Failure" },
124 { JackInitFailure, "Init Failure" },
125 { JackShmFailure, "Shared Memory Access Failure" },
126 { JackVersionError, "Version Mismatch" },
129 static const char *jack_status_to_str(jack_status_t status)
131 int i;
133 for (i = 0; i < ARRAY_LEN(jack_status_table); i++) {
134 if (jack_status_table[i].status == status)
135 return jack_status_table[i].str;
138 return "Unknown Error";
141 static void log_jack_status(const char *prefix, jack_status_t status)
143 struct ast_str *str = ast_str_alloca(512);
144 int i, first = 0;
146 for (i = 0; i < (sizeof(status) * 8); i++) {
147 if (!(status & (1 << i)))
148 continue;
150 if (!first) {
151 ast_str_set(&str, 0, "%s", jack_status_to_str((1 << i)));
152 first = 1;
153 } else
154 ast_str_append(&str, 0, ", %s", jack_status_to_str((1 << i)));
157 ast_log(LOG_NOTICE, "%s: %s\n", prefix, str->str);
160 static int alloc_resampler(struct jack_data *jack_data, int input)
162 double from_srate, to_srate, jack_srate;
163 void **resampler;
164 double *resample_factor;
166 if (input && jack_data->input_resampler)
167 return 0;
169 if (!input && jack_data->output_resampler)
170 return 0;
172 jack_srate = jack_get_sample_rate(jack_data->client);
174 /* XXX Hard coded 8 kHz */
176 to_srate = input ? 8000.0 : jack_srate;
177 from_srate = input ? jack_srate : 8000.0;
179 resample_factor = input ? &jack_data->input_resample_factor :
180 &jack_data->output_resample_factor;
182 if (from_srate == to_srate) {
183 /* Awesome! The jack sample rate is the same as ours.
184 * Resampling isn't needed. */
185 *resample_factor = 1.0;
186 return 0;
189 *resample_factor = to_srate / from_srate;
191 resampler = input ? &jack_data->input_resampler :
192 &jack_data->output_resampler;
194 if (!(*resampler = resample_open(RESAMPLE_QUALITY,
195 *resample_factor, *resample_factor))) {
196 ast_log(LOG_ERROR, "Failed to open %s resampler\n",
197 input ? "input" : "output");
198 return -1;
201 return 0;
205 * \brief Handle jack input port
207 * Read nframes number of samples from the input buffer, resample it
208 * if necessary, and write it into the appropriate ringbuffer.
210 static void handle_input(void *buf, jack_nframes_t nframes,
211 struct jack_data *jack_data)
213 short s_buf[nframes];
214 float *in_buf = buf;
215 size_t res;
216 int i;
217 size_t write_len = sizeof(s_buf);
219 if (jack_data->input_resampler) {
220 int total_in_buf_used = 0;
221 int total_out_buf_used = 0;
222 float f_buf[nframes + 1];
224 memset(f_buf, 0, sizeof(f_buf));
226 while (total_in_buf_used < nframes) {
227 int in_buf_used;
228 int out_buf_used;
230 out_buf_used = resample_process(jack_data->input_resampler,
231 jack_data->input_resample_factor,
232 &in_buf[total_in_buf_used], nframes - total_in_buf_used,
233 0, &in_buf_used,
234 &f_buf[total_out_buf_used], ARRAY_LEN(f_buf) - total_out_buf_used);
236 if (out_buf_used < 0)
237 break;
239 total_out_buf_used += out_buf_used;
240 total_in_buf_used += in_buf_used;
242 if (total_out_buf_used == ARRAY_LEN(f_buf)) {
243 ast_log(LOG_ERROR, "Output buffer filled ... need to increase its size, "
244 "nframes '%d', total_out_buf_used '%d'\n", nframes, total_out_buf_used);
245 break;
249 for (i = 0; i < total_out_buf_used; i++)
250 s_buf[i] = f_buf[i] * (SHRT_MAX / 1.0);
252 write_len = total_out_buf_used * sizeof(int16_t);
253 } else {
254 /* No resampling needed */
256 for (i = 0; i < nframes; i++)
257 s_buf[i] = in_buf[i] * (SHRT_MAX / 1.0);
260 res = jack_ringbuffer_write(jack_data->input_rb, (const char *) s_buf, write_len);
261 if (res != write_len) {
262 ast_debug(2, "Tried to write %d bytes to the ringbuffer, but only wrote %d\n",
263 (int) sizeof(s_buf), (int) res);
268 * \brief Handle jack output port
270 * Read nframes number of samples from the ringbuffer and write it out to the
271 * output port buffer.
273 static void handle_output(void *buf, jack_nframes_t nframes,
274 struct jack_data *jack_data)
276 size_t res, len;
278 len = nframes * sizeof(float);
280 res = jack_ringbuffer_read(jack_data->output_rb, buf, len);
282 if (len != res) {
283 ast_debug(2, "Wanted %d bytes to send to the output port, "
284 "but only got %d\n", (int) len, (int) res);
288 static int jack_process(jack_nframes_t nframes, void *arg)
290 struct jack_data *jack_data = arg;
291 void *input_port_buf, *output_port_buf;
293 if (!jack_data->input_resample_factor)
294 alloc_resampler(jack_data, 1);
296 input_port_buf = jack_port_get_buffer(jack_data->input_port, nframes);
297 handle_input(input_port_buf, nframes, jack_data);
299 output_port_buf = jack_port_get_buffer(jack_data->output_port, nframes);
300 handle_output(output_port_buf, nframes, jack_data);
302 return 0;
305 static void jack_shutdown(void *arg)
307 struct jack_data *jack_data = arg;
309 jack_data->stop = 1;
312 static struct jack_data *destroy_jack_data(struct jack_data *jack_data)
314 if (jack_data->input_port) {
315 jack_port_unregister(jack_data->client, jack_data->input_port);
316 jack_data->input_port = NULL;
319 if (jack_data->output_port) {
320 jack_port_unregister(jack_data->client, jack_data->output_port);
321 jack_data->output_port = NULL;
324 if (jack_data->client) {
325 jack_client_close(jack_data->client);
326 jack_data->client = NULL;
329 if (jack_data->input_rb) {
330 jack_ringbuffer_free(jack_data->input_rb);
331 jack_data->input_rb = NULL;
334 if (jack_data->output_rb) {
335 jack_ringbuffer_free(jack_data->output_rb);
336 jack_data->output_rb = NULL;
339 if (jack_data->output_resampler) {
340 resample_close(jack_data->output_resampler);
341 jack_data->output_resampler = NULL;
344 if (jack_data->input_resampler) {
345 resample_close(jack_data->input_resampler);
346 jack_data->input_resampler = NULL;
349 if (jack_data->has_audiohook)
350 ast_audiohook_destroy(&jack_data->audiohook);
352 ast_string_field_free_memory(jack_data);
354 ast_free(jack_data);
356 return NULL;
359 static int init_jack_data(struct ast_channel *chan, struct jack_data *jack_data)
361 const char *client_name;
362 jack_status_t status = 0;
363 jack_options_t jack_options = JackNullOption;
365 if (!ast_strlen_zero(jack_data->client_name)) {
366 client_name = jack_data->client_name;
367 } else {
368 ast_channel_lock(chan);
369 client_name = ast_strdupa(chan->name);
370 ast_channel_unlock(chan);
373 if (!(jack_data->output_rb = jack_ringbuffer_create(RINGBUFFER_SIZE)))
374 return -1;
376 if (!(jack_data->input_rb = jack_ringbuffer_create(RINGBUFFER_SIZE)))
377 return -1;
379 if (jack_data->no_start_server)
380 jack_options |= JackNoStartServer;
382 if (!ast_strlen_zero(jack_data->server_name)) {
383 jack_options |= JackServerName;
384 jack_data->client = jack_client_open(client_name, jack_options, &status,
385 jack_data->server_name);
386 } else {
387 jack_data->client = jack_client_open(client_name, jack_options, &status);
390 if (status)
391 log_jack_status("Client Open Status", status);
393 if (!jack_data->client)
394 return -1;
396 jack_data->input_port = jack_port_register(jack_data->client, "input",
397 JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput | JackPortIsTerminal, 0);
398 if (!jack_data->input_port) {
399 ast_log(LOG_ERROR, "Failed to create input port for jack port\n");
400 return -1;
403 jack_data->output_port = jack_port_register(jack_data->client, "output",
404 JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput | JackPortIsTerminal, 0);
405 if (!jack_data->output_port) {
406 ast_log(LOG_ERROR, "Failed to create output port for jack port\n");
407 return -1;
410 if (jack_set_process_callback(jack_data->client, jack_process, jack_data)) {
411 ast_log(LOG_ERROR, "Failed to register process callback with jack client\n");
412 return -1;
415 jack_on_shutdown(jack_data->client, jack_shutdown, jack_data);
417 if (jack_activate(jack_data->client)) {
418 ast_log(LOG_ERROR, "Unable to activate jack client\n");
419 return -1;
422 while (!ast_strlen_zero(jack_data->connect_input_port)) {
423 const char **ports;
424 int i;
426 ports = jack_get_ports(jack_data->client, jack_data->connect_input_port,
427 NULL, JackPortIsInput);
429 if (!ports) {
430 ast_log(LOG_ERROR, "No input port matching '%s' was found\n",
431 jack_data->connect_input_port);
432 break;
435 for (i = 0; ports[i]; i++) {
436 ast_debug(1, "Found port '%s' that matched specified input port '%s'\n",
437 ports[i], jack_data->connect_input_port);
440 if (jack_connect(jack_data->client, jack_port_name(jack_data->output_port), ports[0])) {
441 ast_log(LOG_ERROR, "Failed to connect '%s' to '%s'\n", ports[0],
442 jack_port_name(jack_data->output_port));
443 } else {
444 ast_debug(1, "Connected '%s' to '%s'\n", ports[0],
445 jack_port_name(jack_data->output_port));
448 free((void *) ports);
450 break;
453 while (!ast_strlen_zero(jack_data->connect_output_port)) {
454 const char **ports;
455 int i;
457 ports = jack_get_ports(jack_data->client, jack_data->connect_output_port,
458 NULL, JackPortIsOutput);
460 if (!ports) {
461 ast_log(LOG_ERROR, "No output port matching '%s' was found\n",
462 jack_data->connect_output_port);
463 break;
466 for (i = 0; ports[i]; i++) {
467 ast_debug(1, "Found port '%s' that matched specified output port '%s'\n",
468 ports[i], jack_data->connect_output_port);
471 if (jack_connect(jack_data->client, ports[0], jack_port_name(jack_data->input_port))) {
472 ast_log(LOG_ERROR, "Failed to connect '%s' to '%s'\n", ports[0],
473 jack_port_name(jack_data->input_port));
474 } else {
475 ast_debug(1, "Connected '%s' to '%s'\n", ports[0],
476 jack_port_name(jack_data->input_port));
479 free((void *) ports);
481 break;
484 return 0;
487 static int queue_voice_frame(struct jack_data *jack_data, struct ast_frame *f)
489 float f_buf[f->samples * 8];
490 size_t f_buf_used = 0;
491 int i;
492 int16_t *s_buf = f->data.ptr;
493 size_t res;
495 memset(f_buf, 0, sizeof(f_buf));
497 if (!jack_data->output_resample_factor)
498 alloc_resampler(jack_data, 0);
500 if (jack_data->output_resampler) {
501 float in_buf[f->samples];
502 int total_in_buf_used = 0;
503 int total_out_buf_used = 0;
505 memset(in_buf, 0, sizeof(in_buf));
507 for (i = 0; i < f->samples; i++)
508 in_buf[i] = s_buf[i] * (1.0 / SHRT_MAX);
510 while (total_in_buf_used < ARRAY_LEN(in_buf)) {
511 int in_buf_used;
512 int out_buf_used;
514 out_buf_used = resample_process(jack_data->output_resampler,
515 jack_data->output_resample_factor,
516 &in_buf[total_in_buf_used], ARRAY_LEN(in_buf) - total_in_buf_used,
517 0, &in_buf_used,
518 &f_buf[total_out_buf_used], ARRAY_LEN(f_buf) - total_out_buf_used);
520 if (out_buf_used < 0)
521 break;
523 total_out_buf_used += out_buf_used;
524 total_in_buf_used += in_buf_used;
526 if (total_out_buf_used == ARRAY_LEN(f_buf)) {
527 ast_log(LOG_ERROR, "Output buffer filled ... need to increase its size\n");
528 break;
532 f_buf_used = total_out_buf_used;
533 if (f_buf_used > ARRAY_LEN(f_buf))
534 f_buf_used = ARRAY_LEN(f_buf);
535 } else {
536 /* No resampling needed */
538 for (i = 0; i < f->samples; i++)
539 f_buf[i] = s_buf[i] * (1.0 / SHRT_MAX);
541 f_buf_used = f->samples;
544 res = jack_ringbuffer_write(jack_data->output_rb, (const char *) f_buf, f_buf_used * sizeof(float));
545 if (res != (f_buf_used * sizeof(float))) {
546 ast_debug(2, "Tried to write %d bytes to the ringbuffer, but only wrote %d\n",
547 (int) (f_buf_used * sizeof(float)), (int) res);
550 return 0;
554 * \brief handle jack audio
556 * \param[in] chan The Asterisk channel to write the frames to if no output frame
557 * is provided.
558 * \param[in] jack_data This is the jack_data struct that contains the input
559 * ringbuffer that audio will be read from.
560 * \param[out] out_frame If this argument is non-NULL, then assuming there is
561 * enough data avilable in the ringbuffer, the audio in this frame
562 * will get replaced with audio from the input buffer. If there is
563 * not enough data available to read at this time, then the frame
564 * data gets zeroed out.
566 * Read data from the input ringbuffer, which is the properly resampled audio
567 * that was read from the jack input port. Write it to the channel in 20 ms frames,
568 * or fill up an output frame instead if one is provided.
570 * \return Nothing.
572 static void handle_jack_audio(struct ast_channel *chan, struct jack_data *jack_data,
573 struct ast_frame *out_frame)
575 short buf[160];
576 struct ast_frame f = {
577 .frametype = AST_FRAME_VOICE,
578 .subclass = AST_FORMAT_SLINEAR,
579 .src = "JACK",
580 .data.ptr = buf,
581 .datalen = sizeof(buf),
582 .samples = ARRAY_LEN(buf),
585 for (;;) {
586 size_t res, read_len;
587 char *read_buf;
589 read_len = out_frame ? out_frame->datalen : sizeof(buf);
590 read_buf = out_frame ? out_frame->data.ptr : buf;
592 res = jack_ringbuffer_read_space(jack_data->input_rb);
594 if (res < read_len) {
595 /* Not enough data ready for another frame, move on ... */
596 if (out_frame) {
597 ast_debug(1, "Sending an empty frame for the JACK_HOOK\n");
598 memset(out_frame->data.ptr, 0, out_frame->datalen);
600 break;
603 res = jack_ringbuffer_read(jack_data->input_rb, (char *) read_buf, read_len);
605 if (res < read_len) {
606 ast_log(LOG_ERROR, "Error reading from ringbuffer, even though it said there was enough data\n");
607 break;
610 if (out_frame) {
611 /* If an output frame was provided, then we just want to fill up the
612 * buffer in that frame and return. */
613 break;
616 ast_write(chan, &f);
620 enum {
621 OPT_SERVER_NAME = (1 << 0),
622 OPT_INPUT_PORT = (1 << 1),
623 OPT_OUTPUT_PORT = (1 << 2),
624 OPT_NOSTART_SERVER = (1 << 3),
625 OPT_CLIENT_NAME = (1 << 4),
628 enum {
629 OPT_ARG_SERVER_NAME,
630 OPT_ARG_INPUT_PORT,
631 OPT_ARG_OUTPUT_PORT,
632 OPT_ARG_CLIENT_NAME,
634 /* Must be the last element */
635 OPT_ARG_ARRAY_SIZE,
638 AST_APP_OPTIONS(jack_exec_options, BEGIN_OPTIONS
639 AST_APP_OPTION_ARG('s', OPT_SERVER_NAME, OPT_ARG_SERVER_NAME),
640 AST_APP_OPTION_ARG('i', OPT_INPUT_PORT, OPT_ARG_INPUT_PORT),
641 AST_APP_OPTION_ARG('o', OPT_OUTPUT_PORT, OPT_ARG_OUTPUT_PORT),
642 AST_APP_OPTION('n', OPT_NOSTART_SERVER),
643 AST_APP_OPTION_ARG('c', OPT_CLIENT_NAME, OPT_ARG_CLIENT_NAME),
644 END_OPTIONS );
646 static struct jack_data *jack_data_alloc(void)
648 struct jack_data *jack_data;
650 if (!(jack_data = ast_calloc(1, sizeof(*jack_data))))
651 return NULL;
653 if (ast_string_field_init(jack_data, 32)) {
654 ast_free(jack_data);
655 return NULL;
658 return jack_data;
662 * \note This must be done before calling init_jack_data().
664 static int handle_options(struct jack_data *jack_data, const char *__options_str)
666 struct ast_flags options = { 0, };
667 char *option_args[OPT_ARG_ARRAY_SIZE];
668 char *options_str;
670 options_str = ast_strdupa(__options_str);
672 ast_app_parse_options(jack_exec_options, &options, option_args, options_str);
674 if (ast_test_flag(&options, OPT_SERVER_NAME)) {
675 if (!ast_strlen_zero(option_args[OPT_ARG_SERVER_NAME]))
676 ast_string_field_set(jack_data, server_name, option_args[OPT_ARG_SERVER_NAME]);
677 else {
678 ast_log(LOG_ERROR, "A server name must be provided with the s() option\n");
679 return -1;
683 if (ast_test_flag(&options, OPT_CLIENT_NAME)) {
684 if (!ast_strlen_zero(option_args[OPT_ARG_CLIENT_NAME]))
685 ast_string_field_set(jack_data, client_name, option_args[OPT_ARG_CLIENT_NAME]);
686 else {
687 ast_log(LOG_ERROR, "A client name must be provided with the c() option\n");
688 return -1;
692 if (ast_test_flag(&options, OPT_INPUT_PORT)) {
693 if (!ast_strlen_zero(option_args[OPT_ARG_INPUT_PORT]))
694 ast_string_field_set(jack_data, connect_input_port, option_args[OPT_ARG_INPUT_PORT]);
695 else {
696 ast_log(LOG_ERROR, "A name must be provided with the i() option\n");
697 return -1;
701 if (ast_test_flag(&options, OPT_OUTPUT_PORT)) {
702 if (!ast_strlen_zero(option_args[OPT_ARG_OUTPUT_PORT]))
703 ast_string_field_set(jack_data, connect_output_port, option_args[OPT_ARG_OUTPUT_PORT]);
704 else {
705 ast_log(LOG_ERROR, "A name must be provided with the o() option\n");
706 return -1;
710 jack_data->no_start_server = ast_test_flag(&options, OPT_NOSTART_SERVER) ? 1 : 0;
712 return 0;
715 static int jack_exec(struct ast_channel *chan, void *data)
717 struct jack_data *jack_data;
718 AST_DECLARE_APP_ARGS(args,
719 AST_APP_ARG(options);
722 if (!(jack_data = jack_data_alloc()))
723 return -1;
725 args.options = data;
727 if (!ast_strlen_zero(args.options) && handle_options(jack_data, args.options)) {
728 destroy_jack_data(jack_data);
729 return -1;
732 if (init_jack_data(chan, jack_data)) {
733 destroy_jack_data(jack_data);
734 return -1;
737 if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
738 destroy_jack_data(jack_data);
739 return -1;
742 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
743 destroy_jack_data(jack_data);
744 return -1;
747 while (!jack_data->stop) {
748 struct ast_frame *f;
750 ast_waitfor(chan, -1);
752 f = ast_read(chan);
753 if (!f) {
754 jack_data->stop = 1;
755 continue;
758 switch (f->frametype) {
759 case AST_FRAME_CONTROL:
760 if (f->subclass == AST_CONTROL_HANGUP)
761 jack_data->stop = 1;
762 break;
763 case AST_FRAME_VOICE:
764 queue_voice_frame(jack_data, f);
765 default:
766 break;
769 ast_frfree(f);
771 handle_jack_audio(chan, jack_data, NULL);
774 jack_data = destroy_jack_data(jack_data);
776 return 0;
779 static void jack_hook_ds_destroy(void *data)
781 struct jack_data *jack_data = data;
783 destroy_jack_data(jack_data);
786 static const struct ast_datastore_info jack_hook_ds_info = {
787 .type = "JACK_HOOK",
788 .destroy = jack_hook_ds_destroy,
791 static int jack_hook_callback(struct ast_audiohook *audiohook, struct ast_channel *chan,
792 struct ast_frame *frame, enum ast_audiohook_direction direction)
794 struct ast_datastore *datastore;
795 struct jack_data *jack_data;
797 if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE)
798 return 0;
800 if (direction != AST_AUDIOHOOK_DIRECTION_READ)
801 return 0;
803 if (frame->frametype != AST_FRAME_VOICE)
804 return 0;
806 if (frame->subclass != AST_FORMAT_SLINEAR) {
807 ast_log(LOG_WARNING, "Expected frame in SLINEAR for the audiohook, but got format %d\n",
808 frame->subclass);
809 return 0;
812 ast_channel_lock(chan);
814 if (!(datastore = ast_channel_datastore_find(chan, &jack_hook_ds_info, NULL))) {
815 ast_log(LOG_ERROR, "JACK_HOOK datastore not found for '%s'\n", chan->name);
816 ast_channel_unlock(chan);
817 return -1;
820 jack_data = datastore->data;
822 queue_voice_frame(jack_data, frame);
824 handle_jack_audio(chan, jack_data, frame);
826 ast_channel_unlock(chan);
828 return 0;
831 static int enable_jack_hook(struct ast_channel *chan, char *data)
833 struct ast_datastore *datastore;
834 struct jack_data *jack_data = NULL;
835 AST_DECLARE_APP_ARGS(args,
836 AST_APP_ARG(mode);
837 AST_APP_ARG(options);
840 AST_STANDARD_APP_ARGS(args, data);
842 ast_channel_lock(chan);
844 if ((datastore = ast_channel_datastore_find(chan, &jack_hook_ds_info, NULL))) {
845 ast_log(LOG_ERROR, "JACK_HOOK already enabled for '%s'\n", chan->name);
846 goto return_error;
849 if (ast_strlen_zero(args.mode) || strcasecmp(args.mode, "manipulate")) {
850 ast_log(LOG_ERROR, "'%s' is not a supported mode. Only manipulate is supported.\n",
851 S_OR(args.mode, "<none>"));
852 goto return_error;
855 if (!(jack_data = jack_data_alloc()))
856 goto return_error;
858 if (!ast_strlen_zero(args.options) && handle_options(jack_data, args.options))
859 goto return_error;
861 if (init_jack_data(chan, jack_data))
862 goto return_error;
864 if (!(datastore = ast_datastore_alloc(&jack_hook_ds_info, NULL)))
865 goto return_error;
867 jack_data->has_audiohook = 1;
868 ast_audiohook_init(&jack_data->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "JACK_HOOK");
869 jack_data->audiohook.manipulate_callback = jack_hook_callback;
871 datastore->data = jack_data;
873 if (ast_audiohook_attach(chan, &jack_data->audiohook))
874 goto return_error;
876 if (ast_channel_datastore_add(chan, datastore))
877 goto return_error;
879 ast_channel_unlock(chan);
881 return 0;
883 return_error:
884 ast_channel_unlock(chan);
886 if (jack_data)
887 destroy_jack_data(jack_data);
889 return -1;
892 static int disable_jack_hook(struct ast_channel *chan)
894 struct ast_datastore *datastore;
895 struct jack_data *jack_data;
897 ast_channel_lock(chan);
899 if (!(datastore = ast_channel_datastore_find(chan, &jack_hook_ds_info, NULL))) {
900 ast_channel_unlock(chan);
901 ast_log(LOG_WARNING, "No JACK_HOOK found to disable\n");
902 return -1;
905 ast_channel_datastore_remove(chan, datastore);
907 jack_data = datastore->data;
908 ast_audiohook_detach(&jack_data->audiohook);
910 /* Keep the channel locked while we destroy the datastore, so that we can
911 * ensure that all of the jack stuff is stopped just in case another frame
912 * tries to come through the audiohook callback. */
913 ast_datastore_free(datastore);
915 ast_channel_unlock(chan);
917 return 0;
920 static int jack_hook_write(struct ast_channel *chan, const char *cmd, char *data,
921 const char *value)
923 int res;
925 if (!strcasecmp(value, "on"))
926 res = enable_jack_hook(chan, data);
927 else if (!strcasecmp(value, "off"))
928 res = disable_jack_hook(chan);
929 else {
930 ast_log(LOG_ERROR, "'%s' is not a valid value for JACK_HOOK()\n", value);
931 res = -1;
934 return res;
937 static struct ast_custom_function jack_hook_function = {
938 .name = "JACK_HOOK",
939 .synopsis = "Enable a jack hook on a channel",
940 .syntax = "JACK_HOOK(<mode>,[options])",
941 .desc =
942 " The JACK_HOOK allows turning on or off jack connectivity to this channel.\n"
943 "When the JACK_HOOK is turned on, jack ports will get created that allow\n"
944 "access to the audio stream for this channel. The mode specifies which mode\n"
945 "this hook should run in. A mode must be specified when turning the JACK_HOOK.\n"
946 "on. However, all arguments are optional when turning it off.\n"
947 "\n"
948 " Valid modes are:\n"
949 #if 0
950 /* XXX TODO */
951 " spy - Create a read-only audio hook. Only an output jack port will\n"
952 " get created.\n"
953 " whisper - Create a write-only audio hook. Only an input jack port will\n"
954 " get created.\n"
955 #endif
956 " manipulate - Create a read/write audio hook. Both an input and an output\n"
957 " jack port will get created. Audio from the channel will be\n"
958 " sent out the output port and will be replaced by the audio\n"
959 " coming in on the input port as it gets passed on.\n"
960 "\n"
961 " Valid options are:\n"
962 COMMON_OPTIONS
963 "\n"
964 " Examples:\n"
965 " To turn on the JACK_HOOK,\n"
966 " Set(JACK_HOOK(manipulate,i(pure_data_0:input0)o(pure_data_0:output0))=on)\n"
967 " To turn off the JACK_HOOK,\n"
968 " Set(JACK_HOOK()=off)\n"
970 .write = jack_hook_write,
973 static int unload_module(void)
975 int res;
977 res = ast_unregister_application(jack_app);
978 res |= ast_custom_function_unregister(&jack_hook_function);
980 return res;
983 static int load_module(void)
985 if (ast_register_application(jack_app, jack_exec, jack_synopsis, jack_desc)) {
986 return AST_MODULE_LOAD_DECLINE;
989 if (ast_custom_function_register(&jack_hook_function)) {
990 ast_unregister_application(jack_app);
991 return AST_MODULE_LOAD_DECLINE;
994 return AST_MODULE_LOAD_SUCCESS;
997 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "JACK Interface");