Blocked revisions 117809 via svnmerge
[asterisk-bristuff.git] / apps / app_jack.c
blob1b5f4e73825c6162f54204d2882d2e170e18a361
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 * \ingroup applications
34 /*** MODULEINFO
35 <depend>jack</depend>
36 ***/
38 #include "asterisk.h"
40 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
42 #include <limits.h>
44 #include <jack/jack.h>
45 #include <jack/ringbuffer.h>
47 #include "asterisk/module.h"
48 #include "asterisk/channel.h"
49 #include "asterisk/strings.h"
50 #include "asterisk/lock.h"
51 #include "asterisk/libresample.h"
52 #include "asterisk/app.h"
53 #include "asterisk/pbx.h"
54 #include "asterisk/audiohook.h"
56 #define RESAMPLE_QUALITY 0
58 #define RINGBUFFER_SIZE 16384
60 /*! \brief Common options between the Jack() app and JACK_HOOK() function */
61 #define COMMON_OPTIONS \
62 " s(<name>) - Connect to the specified jack server name.\n" \
63 " i(<name>) - Connect the output port that gets created to the specified\n" \
64 " jack input port.\n" \
65 " o(<name>) - Connect the input port that gets created to the specified\n" \
66 " jack output port.\n" \
67 " n - Do not automatically start the JACK server if it is not already\n" \
68 " running.\n" \
69 " c(<name>) - By default, Asterisk will use the channel name for the jack client\n" \
70 " name. Use this option to specify a custom client name.\n"
72 static char *jack_app = "JACK";
73 static char *jack_synopsis =
74 "JACK (Jack Audio Connection Kit) Application";
75 static char *jack_desc =
76 "JACK([options])\n"
77 " When this application is executed, two jack ports will be created; one input\n"
78 "and one output. Other applications can be hooked up to these ports to access\n"
79 "the audio coming from, or being sent to the channel.\n"
80 " Valid options:\n"
81 COMMON_OPTIONS
82 "";
84 struct jack_data {
85 AST_DECLARE_STRING_FIELDS(
86 AST_STRING_FIELD(server_name);
87 AST_STRING_FIELD(client_name);
88 AST_STRING_FIELD(connect_input_port);
89 AST_STRING_FIELD(connect_output_port);
91 jack_client_t *client;
92 jack_port_t *input_port;
93 jack_port_t *output_port;
94 jack_ringbuffer_t *input_rb;
95 jack_ringbuffer_t *output_rb;
96 void *output_resampler;
97 double output_resample_factor;
98 void *input_resampler;
99 double input_resample_factor;
100 unsigned int stop:1;
101 unsigned int has_audiohook:1;
102 unsigned int no_start_server:1;
103 /*! Only used with JACK_HOOK */
104 struct ast_audiohook audiohook;
107 static const struct {
108 jack_status_t status;
109 const char *str;
110 } jack_status_table[] = {
111 { JackFailure, "Failure" },
112 { JackInvalidOption, "Invalid Option" },
113 { JackNameNotUnique, "Name Not Unique" },
114 { JackServerStarted, "Server Started" },
115 { JackServerFailed, "Server Failed" },
116 { JackServerError, "Server Error" },
117 { JackNoSuchClient, "No Such Client" },
118 { JackLoadFailure, "Load Failure" },
119 { JackInitFailure, "Init Failure" },
120 { JackShmFailure, "Shared Memory Access Failure" },
121 { JackVersionError, "Version Mismatch" },
124 static const char *jack_status_to_str(jack_status_t status)
126 int i;
128 for (i = 0; i < ARRAY_LEN(jack_status_table); i++) {
129 if (jack_status_table[i].status == status)
130 return jack_status_table[i].str;
133 return "Unknown Error";
136 static void log_jack_status(const char *prefix, jack_status_t status)
138 struct ast_str *str = ast_str_alloca(512);
139 int i, first = 0;
141 for (i = 0; i < (sizeof(status) * 8); i++) {
142 if (!(status & (1 << i)))
143 continue;
145 if (!first) {
146 ast_str_set(&str, 0, "%s", jack_status_to_str((1 << i)));
147 first = 1;
148 } else
149 ast_str_append(&str, 0, ", %s", jack_status_to_str((1 << i)));
152 ast_log(LOG_NOTICE, "%s: %s\n", prefix, str->str);
155 static int alloc_resampler(struct jack_data *jack_data, int input)
157 double from_srate, to_srate, jack_srate;
158 void **resampler;
159 double *resample_factor;
161 if (input && jack_data->input_resampler)
162 return 0;
164 if (!input && jack_data->output_resampler)
165 return 0;
167 jack_srate = jack_get_sample_rate(jack_data->client);
169 /* XXX Hard coded 8 kHz */
171 to_srate = input ? 8000.0 : jack_srate;
172 from_srate = input ? jack_srate : 8000.0;
174 resample_factor = input ? &jack_data->input_resample_factor :
175 &jack_data->output_resample_factor;
177 if (from_srate == to_srate) {
178 /* Awesome! The jack sample rate is the same as ours.
179 * Resampling isn't needed. */
180 *resample_factor = 1.0;
181 return 0;
184 *resample_factor = to_srate / from_srate;
186 resampler = input ? &jack_data->input_resampler :
187 &jack_data->output_resampler;
189 if (!(*resampler = resample_open(RESAMPLE_QUALITY,
190 *resample_factor, *resample_factor))) {
191 ast_log(LOG_ERROR, "Failed to open %s resampler\n",
192 input ? "input" : "output");
193 return -1;
196 return 0;
200 * \brief Handle jack input port
202 * Read nframes number of samples from the input buffer, resample it
203 * if necessary, and write it into the appropriate ringbuffer.
205 static void handle_input(void *buf, jack_nframes_t nframes,
206 struct jack_data *jack_data)
208 short s_buf[nframes];
209 float *in_buf = buf;
210 size_t res;
211 int i;
212 size_t write_len = sizeof(s_buf);
214 if (jack_data->input_resampler) {
215 int total_in_buf_used = 0;
216 int total_out_buf_used = 0;
217 float f_buf[nframes + 1];
219 memset(f_buf, 0, sizeof(f_buf));
221 while (total_in_buf_used < nframes) {
222 int in_buf_used;
223 int out_buf_used;
225 out_buf_used = resample_process(jack_data->input_resampler,
226 jack_data->input_resample_factor,
227 &in_buf[total_in_buf_used], nframes - total_in_buf_used,
228 0, &in_buf_used,
229 &f_buf[total_out_buf_used], ARRAY_LEN(f_buf) - total_out_buf_used);
231 if (out_buf_used < 0)
232 break;
234 total_out_buf_used += out_buf_used;
235 total_in_buf_used += in_buf_used;
237 if (total_out_buf_used == ARRAY_LEN(f_buf)) {
238 ast_log(LOG_ERROR, "Output buffer filled ... need to increase its size, "
239 "nframes '%d', total_out_buf_used '%d'\n", nframes, total_out_buf_used);
240 break;
244 for (i = 0; i < total_out_buf_used; i++)
245 s_buf[i] = f_buf[i] * (SHRT_MAX / 1.0);
247 write_len = total_out_buf_used * sizeof(int16_t);
248 } else {
249 /* No resampling needed */
251 for (i = 0; i < nframes; i++)
252 s_buf[i] = in_buf[i] * (SHRT_MAX / 1.0);
255 res = jack_ringbuffer_write(jack_data->input_rb, (const char *) s_buf, write_len);
256 if (res != write_len) {
257 ast_debug(2, "Tried to write %d bytes to the ringbuffer, but only wrote %d\n",
258 (int) sizeof(s_buf), (int) res);
263 * \brief Handle jack output port
265 * Read nframes number of samples from the ringbuffer and write it out to the
266 * output port buffer.
268 static void handle_output(void *buf, jack_nframes_t nframes,
269 struct jack_data *jack_data)
271 size_t res, len;
273 len = nframes * sizeof(float);
275 res = jack_ringbuffer_read(jack_data->output_rb, buf, len);
277 if (len != res) {
278 ast_debug(2, "Wanted %d bytes to send to the output port, "
279 "but only got %d\n", (int) len, (int) res);
283 static int jack_process(jack_nframes_t nframes, void *arg)
285 struct jack_data *jack_data = arg;
286 void *input_port_buf, *output_port_buf;
288 if (!jack_data->input_resample_factor)
289 alloc_resampler(jack_data, 1);
291 input_port_buf = jack_port_get_buffer(jack_data->input_port, nframes);
292 handle_input(input_port_buf, nframes, jack_data);
294 output_port_buf = jack_port_get_buffer(jack_data->output_port, nframes);
295 handle_output(output_port_buf, nframes, jack_data);
297 return 0;
300 static void jack_shutdown(void *arg)
302 struct jack_data *jack_data = arg;
304 jack_data->stop = 1;
307 static struct jack_data *destroy_jack_data(struct jack_data *jack_data)
309 if (jack_data->input_port) {
310 jack_port_unregister(jack_data->client, jack_data->input_port);
311 jack_data->input_port = NULL;
314 if (jack_data->output_port) {
315 jack_port_unregister(jack_data->client, jack_data->output_port);
316 jack_data->output_port = NULL;
319 if (jack_data->client) {
320 jack_client_close(jack_data->client);
321 jack_data->client = NULL;
324 if (jack_data->input_rb) {
325 jack_ringbuffer_free(jack_data->input_rb);
326 jack_data->input_rb = NULL;
329 if (jack_data->output_rb) {
330 jack_ringbuffer_free(jack_data->output_rb);
331 jack_data->output_rb = NULL;
334 if (jack_data->output_resampler) {
335 resample_close(jack_data->output_resampler);
336 jack_data->output_resampler = NULL;
339 if (jack_data->input_resampler) {
340 resample_close(jack_data->input_resampler);
341 jack_data->input_resampler = NULL;
344 if (jack_data->has_audiohook)
345 ast_audiohook_destroy(&jack_data->audiohook);
347 ast_string_field_free_memory(jack_data);
349 ast_free(jack_data);
351 return NULL;
354 static int init_jack_data(struct ast_channel *chan, struct jack_data *jack_data)
356 const char *client_name;
357 jack_status_t status = 0;
358 jack_options_t jack_options = JackNullOption;
360 if (!ast_strlen_zero(jack_data->client_name)) {
361 client_name = jack_data->client_name;
362 } else {
363 ast_channel_lock(chan);
364 client_name = ast_strdupa(chan->name);
365 ast_channel_unlock(chan);
368 if (!(jack_data->output_rb = jack_ringbuffer_create(RINGBUFFER_SIZE)))
369 return -1;
371 if (!(jack_data->input_rb = jack_ringbuffer_create(RINGBUFFER_SIZE)))
372 return -1;
374 if (jack_data->no_start_server)
375 jack_options |= JackNoStartServer;
377 if (!ast_strlen_zero(jack_data->server_name)) {
378 jack_options |= JackServerName;
379 jack_data->client = jack_client_open(client_name, jack_options, &status,
380 jack_data->server_name);
381 } else {
382 jack_data->client = jack_client_open(client_name, jack_options, &status);
385 if (status)
386 log_jack_status("Client Open Status", status);
388 if (!jack_data->client)
389 return -1;
391 jack_data->input_port = jack_port_register(jack_data->client, "input",
392 JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput | JackPortIsTerminal, 0);
393 if (!jack_data->input_port) {
394 ast_log(LOG_ERROR, "Failed to create input port for jack port\n");
395 return -1;
398 jack_data->output_port = jack_port_register(jack_data->client, "output",
399 JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput | JackPortIsTerminal, 0);
400 if (!jack_data->output_port) {
401 ast_log(LOG_ERROR, "Failed to create output port for jack port\n");
402 return -1;
405 if (jack_set_process_callback(jack_data->client, jack_process, jack_data)) {
406 ast_log(LOG_ERROR, "Failed to register process callback with jack client\n");
407 return -1;
410 jack_on_shutdown(jack_data->client, jack_shutdown, jack_data);
412 if (jack_activate(jack_data->client)) {
413 ast_log(LOG_ERROR, "Unable to activate jack client\n");
414 return -1;
417 while (!ast_strlen_zero(jack_data->connect_input_port)) {
418 const char **ports;
419 int i;
421 ports = jack_get_ports(jack_data->client, jack_data->connect_input_port,
422 NULL, JackPortIsInput);
424 if (!ports) {
425 ast_log(LOG_ERROR, "No input port matching '%s' was found\n",
426 jack_data->connect_input_port);
427 break;
430 for (i = 0; ports[i]; i++) {
431 ast_debug(1, "Found port '%s' that matched specified input port '%s'\n",
432 ports[i], jack_data->connect_input_port);
435 if (jack_connect(jack_data->client, jack_port_name(jack_data->output_port), ports[0])) {
436 ast_log(LOG_ERROR, "Failed to connect '%s' to '%s'\n", ports[0],
437 jack_port_name(jack_data->output_port));
438 } else {
439 ast_debug(1, "Connected '%s' to '%s'\n", ports[0],
440 jack_port_name(jack_data->output_port));
443 free((void *) ports);
445 break;
448 while (!ast_strlen_zero(jack_data->connect_output_port)) {
449 const char **ports;
450 int i;
452 ports = jack_get_ports(jack_data->client, jack_data->connect_output_port,
453 NULL, JackPortIsOutput);
455 if (!ports) {
456 ast_log(LOG_ERROR, "No output port matching '%s' was found\n",
457 jack_data->connect_output_port);
458 break;
461 for (i = 0; ports[i]; i++) {
462 ast_debug(1, "Found port '%s' that matched specified output port '%s'\n",
463 ports[i], jack_data->connect_output_port);
466 if (jack_connect(jack_data->client, ports[0], jack_port_name(jack_data->input_port))) {
467 ast_log(LOG_ERROR, "Failed to connect '%s' to '%s'\n", ports[0],
468 jack_port_name(jack_data->input_port));
469 } else {
470 ast_debug(1, "Connected '%s' to '%s'\n", ports[0],
471 jack_port_name(jack_data->input_port));
474 free((void *) ports);
476 break;
479 return 0;
482 static int queue_voice_frame(struct jack_data *jack_data, struct ast_frame *f)
484 float f_buf[f->samples * 8];
485 size_t f_buf_used = 0;
486 int i;
487 int16_t *s_buf = f->data;
488 size_t res;
490 memset(f_buf, 0, sizeof(f_buf));
492 if (!jack_data->output_resample_factor)
493 alloc_resampler(jack_data, 0);
495 if (jack_data->output_resampler) {
496 float in_buf[f->samples];
497 int total_in_buf_used = 0;
498 int total_out_buf_used = 0;
500 memset(in_buf, 0, sizeof(in_buf));
502 for (i = 0; i < f->samples; i++)
503 in_buf[i] = s_buf[i] * (1.0 / SHRT_MAX);
505 while (total_in_buf_used < ARRAY_LEN(in_buf)) {
506 int in_buf_used;
507 int out_buf_used;
509 out_buf_used = resample_process(jack_data->output_resampler,
510 jack_data->output_resample_factor,
511 &in_buf[total_in_buf_used], ARRAY_LEN(in_buf) - total_in_buf_used,
512 0, &in_buf_used,
513 &f_buf[total_out_buf_used], ARRAY_LEN(f_buf) - total_out_buf_used);
515 if (out_buf_used < 0)
516 break;
518 total_out_buf_used += out_buf_used;
519 total_in_buf_used += in_buf_used;
521 if (total_out_buf_used == ARRAY_LEN(f_buf)) {
522 ast_log(LOG_ERROR, "Output buffer filled ... need to increase its size\n");
523 break;
527 f_buf_used = total_out_buf_used;
528 if (f_buf_used > ARRAY_LEN(f_buf))
529 f_buf_used = ARRAY_LEN(f_buf);
530 } else {
531 /* No resampling needed */
533 for (i = 0; i < f->samples; i++)
534 f_buf[i] = s_buf[i] * (1.0 / SHRT_MAX);
536 f_buf_used = f->samples;
539 res = jack_ringbuffer_write(jack_data->output_rb, (const char *) f_buf, f_buf_used * sizeof(float));
540 if (res != (f_buf_used * sizeof(float))) {
541 ast_debug(2, "Tried to write %d bytes to the ringbuffer, but only wrote %d\n",
542 (int) (f_buf_used * sizeof(float)), (int) res);
545 return 0;
549 * \brief handle jack audio
551 * \param[in] chan The Asterisk channel to write the frames to if no output frame
552 * is provided.
553 * \param[in] jack_data This is the jack_data struct that contains the input
554 * ringbuffer that audio will be read from.
555 * \param[out] out_frame If this argument is non-NULL, then assuming there is
556 * enough data avilable in the ringbuffer, the audio in this frame
557 * will get replaced with audio from the input buffer. If there is
558 * not enough data available to read at this time, then the frame
559 * data gets zeroed out.
561 * Read data from the input ringbuffer, which is the properly resampled audio
562 * that was read from the jack input port. Write it to the channel in 20 ms frames,
563 * or fill up an output frame instead if one is provided.
565 * \return Nothing.
567 static void handle_jack_audio(struct ast_channel *chan, struct jack_data *jack_data,
568 struct ast_frame *out_frame)
570 short buf[160];
571 struct ast_frame f = {
572 .frametype = AST_FRAME_VOICE,
573 .subclass = AST_FORMAT_SLINEAR,
574 .src = "JACK",
575 .data = buf,
576 .datalen = sizeof(buf),
577 .samples = ARRAY_LEN(buf),
580 for (;;) {
581 size_t res, read_len;
582 char *read_buf;
584 read_len = out_frame ? out_frame->datalen : sizeof(buf);
585 read_buf = out_frame ? out_frame->data : buf;
587 res = jack_ringbuffer_read_space(jack_data->input_rb);
589 if (res < read_len) {
590 /* Not enough data ready for another frame, move on ... */
591 if (out_frame) {
592 ast_debug(1, "Sending an empty frame for the JACK_HOOK\n");
593 memset(out_frame->data, 0, out_frame->datalen);
595 break;
598 res = jack_ringbuffer_read(jack_data->input_rb, (char *) read_buf, read_len);
600 if (res < read_len) {
601 ast_log(LOG_ERROR, "Error reading from ringbuffer, even though it said there was enough data\n");
602 break;
605 if (out_frame) {
606 /* If an output frame was provided, then we just want to fill up the
607 * buffer in that frame and return. */
608 break;
611 ast_write(chan, &f);
615 enum {
616 OPT_SERVER_NAME = (1 << 0),
617 OPT_INPUT_PORT = (1 << 1),
618 OPT_OUTPUT_PORT = (1 << 2),
619 OPT_NOSTART_SERVER = (1 << 3),
620 OPT_CLIENT_NAME = (1 << 4),
623 enum {
624 OPT_ARG_SERVER_NAME,
625 OPT_ARG_INPUT_PORT,
626 OPT_ARG_OUTPUT_PORT,
627 OPT_ARG_CLIENT_NAME,
629 /* Must be the last element */
630 OPT_ARG_ARRAY_SIZE,
633 AST_APP_OPTIONS(jack_exec_options, BEGIN_OPTIONS
634 AST_APP_OPTION_ARG('s', OPT_SERVER_NAME, OPT_ARG_SERVER_NAME),
635 AST_APP_OPTION_ARG('i', OPT_INPUT_PORT, OPT_ARG_INPUT_PORT),
636 AST_APP_OPTION_ARG('o', OPT_OUTPUT_PORT, OPT_ARG_OUTPUT_PORT),
637 AST_APP_OPTION('n', OPT_NOSTART_SERVER),
638 AST_APP_OPTION_ARG('c', OPT_CLIENT_NAME, OPT_ARG_CLIENT_NAME),
639 END_OPTIONS );
641 static struct jack_data *jack_data_alloc(void)
643 struct jack_data *jack_data;
645 if (!(jack_data = ast_calloc(1, sizeof(*jack_data))))
646 return NULL;
648 if (ast_string_field_init(jack_data, 32)) {
649 ast_free(jack_data);
650 return NULL;
653 return jack_data;
657 * \note This must be done before calling init_jack_data().
659 static int handle_options(struct jack_data *jack_data, const char *__options_str)
661 struct ast_flags options = { 0, };
662 char *option_args[OPT_ARG_ARRAY_SIZE];
663 char *options_str;
665 options_str = ast_strdupa(__options_str);
667 ast_app_parse_options(jack_exec_options, &options, option_args, options_str);
669 if (ast_test_flag(&options, OPT_SERVER_NAME)) {
670 if (!ast_strlen_zero(option_args[OPT_ARG_SERVER_NAME]))
671 ast_string_field_set(jack_data, server_name, option_args[OPT_ARG_SERVER_NAME]);
672 else {
673 ast_log(LOG_ERROR, "A server name must be provided with the s() option\n");
674 return -1;
678 if (ast_test_flag(&options, OPT_CLIENT_NAME)) {
679 if (!ast_strlen_zero(option_args[OPT_ARG_CLIENT_NAME]))
680 ast_string_field_set(jack_data, client_name, option_args[OPT_ARG_CLIENT_NAME]);
681 else {
682 ast_log(LOG_ERROR, "A client name must be provided with the c() option\n");
683 return -1;
687 if (ast_test_flag(&options, OPT_INPUT_PORT)) {
688 if (!ast_strlen_zero(option_args[OPT_ARG_INPUT_PORT]))
689 ast_string_field_set(jack_data, connect_input_port, option_args[OPT_ARG_INPUT_PORT]);
690 else {
691 ast_log(LOG_ERROR, "A name must be provided with the i() option\n");
692 return -1;
696 if (ast_test_flag(&options, OPT_OUTPUT_PORT)) {
697 if (!ast_strlen_zero(option_args[OPT_ARG_OUTPUT_PORT]))
698 ast_string_field_set(jack_data, connect_output_port, option_args[OPT_ARG_OUTPUT_PORT]);
699 else {
700 ast_log(LOG_ERROR, "A name must be provided with the o() option\n");
701 return -1;
705 jack_data->no_start_server = ast_test_flag(&options, OPT_NOSTART_SERVER) ? 1 : 0;
707 return 0;
710 static int jack_exec(struct ast_channel *chan, void *data)
712 struct jack_data *jack_data;
713 AST_DECLARE_APP_ARGS(args,
714 AST_APP_ARG(options);
717 if (!(jack_data = jack_data_alloc()))
718 return -1;
720 args.options = data;
722 if (!ast_strlen_zero(args.options) && handle_options(jack_data, args.options)) {
723 destroy_jack_data(jack_data);
724 return -1;
727 if (init_jack_data(chan, jack_data)) {
728 destroy_jack_data(jack_data);
729 return -1;
732 if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
733 destroy_jack_data(jack_data);
734 return -1;
737 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
738 destroy_jack_data(jack_data);
739 return -1;
742 while (!jack_data->stop) {
743 struct ast_frame *f;
745 ast_waitfor(chan, -1);
747 f = ast_read(chan);
748 if (!f) {
749 jack_data->stop = 1;
750 continue;
753 switch (f->frametype) {
754 case AST_FRAME_CONTROL:
755 if (f->subclass == AST_CONTROL_HANGUP)
756 jack_data->stop = 1;
757 break;
758 case AST_FRAME_VOICE:
759 queue_voice_frame(jack_data, f);
760 default:
761 break;
764 ast_frfree(f);
766 handle_jack_audio(chan, jack_data, NULL);
769 jack_data = destroy_jack_data(jack_data);
771 return 0;
774 static void jack_hook_ds_destroy(void *data)
776 struct jack_data *jack_data = data;
778 destroy_jack_data(jack_data);
781 static const struct ast_datastore_info jack_hook_ds_info = {
782 .type = "JACK_HOOK",
783 .destroy = jack_hook_ds_destroy,
786 static int jack_hook_callback(struct ast_audiohook *audiohook, struct ast_channel *chan,
787 struct ast_frame *frame, enum ast_audiohook_direction direction)
789 struct ast_datastore *datastore;
790 struct jack_data *jack_data;
792 if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE)
793 return 0;
795 if (direction != AST_AUDIOHOOK_DIRECTION_READ)
796 return 0;
798 if (frame->frametype != AST_FRAME_VOICE)
799 return 0;
801 if (frame->subclass != AST_FORMAT_SLINEAR) {
802 ast_log(LOG_WARNING, "Expected frame in SLINEAR for the audiohook, but got format %d\n",
803 frame->subclass);
804 return 0;
807 ast_channel_lock(chan);
809 if (!(datastore = ast_channel_datastore_find(chan, &jack_hook_ds_info, NULL))) {
810 ast_log(LOG_ERROR, "JACK_HOOK datastore not found for '%s'\n", chan->name);
811 ast_channel_unlock(chan);
812 return -1;
815 jack_data = datastore->data;
817 queue_voice_frame(jack_data, frame);
819 handle_jack_audio(chan, jack_data, frame);
821 ast_channel_unlock(chan);
823 return 0;
826 static int enable_jack_hook(struct ast_channel *chan, char *data)
828 struct ast_datastore *datastore;
829 struct jack_data *jack_data = NULL;
830 AST_DECLARE_APP_ARGS(args,
831 AST_APP_ARG(mode);
832 AST_APP_ARG(options);
835 AST_STANDARD_APP_ARGS(args, data);
837 ast_channel_lock(chan);
839 if ((datastore = ast_channel_datastore_find(chan, &jack_hook_ds_info, NULL))) {
840 ast_log(LOG_ERROR, "JACK_HOOK already enabled for '%s'\n", chan->name);
841 goto return_error;
844 if (ast_strlen_zero(args.mode) || strcasecmp(args.mode, "manipulate")) {
845 ast_log(LOG_ERROR, "'%s' is not a supported mode. Only manipulate is supported.\n",
846 S_OR(args.mode, "<none>"));
847 goto return_error;
850 if (!(jack_data = jack_data_alloc()))
851 goto return_error;
853 if (!ast_strlen_zero(args.options) && handle_options(jack_data, args.options))
854 goto return_error;
856 if (init_jack_data(chan, jack_data))
857 goto return_error;
859 if (!(datastore = ast_channel_datastore_alloc(&jack_hook_ds_info, NULL)))
860 goto return_error;
862 jack_data->has_audiohook = 1;
863 ast_audiohook_init(&jack_data->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "JACK_HOOK");
864 jack_data->audiohook.manipulate_callback = jack_hook_callback;
866 datastore->data = jack_data;
868 if (ast_audiohook_attach(chan, &jack_data->audiohook))
869 goto return_error;
871 if (ast_channel_datastore_add(chan, datastore))
872 goto return_error;
874 ast_channel_unlock(chan);
876 return 0;
878 return_error:
879 ast_channel_unlock(chan);
881 if (jack_data)
882 destroy_jack_data(jack_data);
884 return -1;
887 static int disable_jack_hook(struct ast_channel *chan)
889 struct ast_datastore *datastore;
890 struct jack_data *jack_data;
892 ast_channel_lock(chan);
894 if (!(datastore = ast_channel_datastore_find(chan, &jack_hook_ds_info, NULL))) {
895 ast_channel_unlock(chan);
896 ast_log(LOG_WARNING, "No JACK_HOOK found to disable\n");
897 return -1;
900 ast_channel_datastore_remove(chan, datastore);
902 jack_data = datastore->data;
903 ast_audiohook_detach(&jack_data->audiohook);
905 /* Keep the channel locked while we destroy the datastore, so that we can
906 * ensure that all of the jack stuff is stopped just in case another frame
907 * tries to come through the audiohook callback. */
908 ast_channel_datastore_free(datastore);
910 ast_channel_unlock(chan);
912 return 0;
915 static int jack_hook_write(struct ast_channel *chan, const char *cmd, char *data,
916 const char *value)
918 int res;
920 if (!strcasecmp(value, "on"))
921 res = enable_jack_hook(chan, data);
922 else if (!strcasecmp(value, "off"))
923 res = disable_jack_hook(chan);
924 else {
925 ast_log(LOG_ERROR, "'%s' is not a valid value for JACK_HOOK()\n", value);
926 res = -1;
929 return res;
932 static struct ast_custom_function jack_hook_function = {
933 .name = "JACK_HOOK",
934 .synopsis = "Enable a jack hook on a channel",
935 .syntax = "JACK_HOOK(<mode>,[options])",
936 .desc =
937 " The JACK_HOOK allows turning on or off jack connectivity to this channel.\n"
938 "When the JACK_HOOK is turned on, jack ports will get created that allow\n"
939 "access to the audio stream for this channel. The mode specifies which mode\n"
940 "this hook should run in. A mode must be specified when turning the JACK_HOOK.\n"
941 "on. However, all arguments are optional when turning it off.\n"
942 "\n"
943 " Valid modes are:\n"
944 #if 0
945 /* XXX TODO */
946 " spy - Create a read-only audio hook. Only an output jack port will\n"
947 " get created.\n"
948 " whisper - Create a write-only audio hook. Only an input jack port will\n"
949 " get created.\n"
950 #endif
951 " manipulate - Create a read/write audio hook. Both an input and an output\n"
952 " jack port will get created. Audio from the channel will be\n"
953 " sent out the output port and will be replaced by the audio\n"
954 " coming in on the input port as it gets passed on.\n"
955 "\n"
956 " Valid options are:\n"
957 COMMON_OPTIONS
958 "\n"
959 " Examples:\n"
960 " To turn on the JACK_HOOK,\n"
961 " Set(JACK_HOOK(manipulate,i(pure_data_0:input0)o(pure_data_0:output0))=on)\n"
962 " To turn off the JACK_HOOK,\n"
963 " Set(JACK_HOOK()=off)\n"
965 .write = jack_hook_write,
968 static int unload_module(void)
970 int res;
972 res = ast_unregister_application(jack_app);
973 res |= ast_custom_function_unregister(&jack_hook_function);
975 return res;
978 static int load_module(void)
980 if (ast_register_application(jack_app, jack_exec, jack_synopsis, jack_desc)) {
981 return AST_MODULE_LOAD_DECLINE;
984 if (ast_custom_function_register(&jack_hook_function)) {
985 ast_unregister_application(jack_app);
986 return AST_MODULE_LOAD_DECLINE;
989 return AST_MODULE_LOAD_SUCCESS;
992 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "JACK Interface");