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.
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
39 <depend>resample</depend>
44 ASTERISK_FILE_VERSION(__FILE__
, "$Revision$")
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" \
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
=
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"
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
;
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
;
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
)
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);
146 for (i
= 0; i
< (sizeof(status
) * 8); i
++) {
147 if (!(status
& (1 << i
)))
151 ast_str_set(&str
, 0, "%s", jack_status_to_str((1 << i
)));
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
;
164 double *resample_factor
;
166 if (input
&& jack_data
->input_resampler
)
169 if (!input
&& jack_data
->output_resampler
)
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;
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");
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
];
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
) {
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
,
234 &f_buf
[total_out_buf_used
], ARRAY_LEN(f_buf
) - total_out_buf_used
);
236 if (out_buf_used
< 0)
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
);
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);
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
)
278 len
= nframes
* sizeof(float);
280 res
= jack_ringbuffer_read(jack_data
->output_rb
, buf
, len
);
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
);
305 static void jack_shutdown(void *arg
)
307 struct jack_data
*jack_data
= arg
;
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
);
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
;
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
)))
376 if (!(jack_data
->input_rb
= jack_ringbuffer_create(RINGBUFFER_SIZE
)))
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
);
387 jack_data
->client
= jack_client_open(client_name
, jack_options
, &status
);
391 log_jack_status("Client Open Status", status
);
393 if (!jack_data
->client
)
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");
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");
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");
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");
422 while (!ast_strlen_zero(jack_data
->connect_input_port
)) {
426 ports
= jack_get_ports(jack_data
->client
, jack_data
->connect_input_port
,
427 NULL
, JackPortIsInput
);
430 ast_log(LOG_ERROR
, "No input port matching '%s' was found\n",
431 jack_data
->connect_input_port
);
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
));
444 ast_debug(1, "Connected '%s' to '%s'\n", ports
[0],
445 jack_port_name(jack_data
->output_port
));
448 free((void *) ports
);
453 while (!ast_strlen_zero(jack_data
->connect_output_port
)) {
457 ports
= jack_get_ports(jack_data
->client
, jack_data
->connect_output_port
,
458 NULL
, JackPortIsOutput
);
461 ast_log(LOG_ERROR
, "No output port matching '%s' was found\n",
462 jack_data
->connect_output_port
);
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
));
475 ast_debug(1, "Connected '%s' to '%s'\n", ports
[0],
476 jack_port_name(jack_data
->input_port
));
479 free((void *) ports
);
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;
492 int16_t *s_buf
= f
->data
.ptr
;
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
)) {
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
,
518 &f_buf
[total_out_buf_used
], ARRAY_LEN(f_buf
) - total_out_buf_used
);
520 if (out_buf_used
< 0)
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");
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
);
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
);
554 * \brief handle jack audio
556 * \param[in] chan The Asterisk channel to write the frames to if no output frame
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.
572 static void handle_jack_audio(struct ast_channel
*chan
, struct jack_data
*jack_data
,
573 struct ast_frame
*out_frame
)
576 struct ast_frame f
= {
577 .frametype
= AST_FRAME_VOICE
,
578 .subclass
= AST_FORMAT_SLINEAR
,
581 .datalen
= sizeof(buf
),
582 .samples
= ARRAY_LEN(buf
),
586 size_t res
, read_len
;
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 ... */
597 ast_debug(1, "Sending an empty frame for the JACK_HOOK\n");
598 memset(out_frame
->data
.ptr
, 0, out_frame
->datalen
);
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");
611 /* If an output frame was provided, then we just want to fill up the
612 * buffer in that frame and return. */
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),
634 /* Must be the last element */
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
),
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
))))
653 if (ast_string_field_init(jack_data
, 32)) {
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
];
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
]);
678 ast_log(LOG_ERROR
, "A server name must be provided with the s() option\n");
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
]);
687 ast_log(LOG_ERROR
, "A client name must be provided with the c() option\n");
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
]);
696 ast_log(LOG_ERROR
, "A name must be provided with the i() option\n");
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
]);
705 ast_log(LOG_ERROR
, "A name must be provided with the o() option\n");
710 jack_data
->no_start_server
= ast_test_flag(&options
, OPT_NOSTART_SERVER
) ? 1 : 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()))
727 if (!ast_strlen_zero(args
.options
) && handle_options(jack_data
, args
.options
)) {
728 destroy_jack_data(jack_data
);
732 if (init_jack_data(chan
, jack_data
)) {
733 destroy_jack_data(jack_data
);
737 if (ast_set_read_format(chan
, AST_FORMAT_SLINEAR
)) {
738 destroy_jack_data(jack_data
);
742 if (ast_set_write_format(chan
, AST_FORMAT_SLINEAR
)) {
743 destroy_jack_data(jack_data
);
747 while (!jack_data
->stop
) {
750 ast_waitfor(chan
, -1);
758 switch (f
->frametype
) {
759 case AST_FRAME_CONTROL
:
760 if (f
->subclass
== AST_CONTROL_HANGUP
)
763 case AST_FRAME_VOICE
:
764 queue_voice_frame(jack_data
, f
);
771 handle_jack_audio(chan
, jack_data
, NULL
);
774 jack_data
= destroy_jack_data(jack_data
);
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
= {
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
)
800 if (direction
!= AST_AUDIOHOOK_DIRECTION_READ
)
803 if (frame
->frametype
!= AST_FRAME_VOICE
)
806 if (frame
->subclass
!= AST_FORMAT_SLINEAR
) {
807 ast_log(LOG_WARNING
, "Expected frame in SLINEAR for the audiohook, but got format %d\n",
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
);
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
);
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
,
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
);
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>"));
855 if (!(jack_data
= jack_data_alloc()))
858 if (!ast_strlen_zero(args
.options
) && handle_options(jack_data
, args
.options
))
861 if (init_jack_data(chan
, jack_data
))
864 if (!(datastore
= ast_datastore_alloc(&jack_hook_ds_info
, NULL
)))
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
))
876 if (ast_channel_datastore_add(chan
, datastore
))
879 ast_channel_unlock(chan
);
884 ast_channel_unlock(chan
);
887 destroy_jack_data(jack_data
);
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");
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
);
920 static int jack_hook_write(struct ast_channel
*chan
, const char *cmd
, char *data
,
925 if (!strcasecmp(value
, "on"))
926 res
= enable_jack_hook(chan
, data
);
927 else if (!strcasecmp(value
, "off"))
928 res
= disable_jack_hook(chan
);
930 ast_log(LOG_ERROR
, "'%s' is not a valid value for JACK_HOOK()\n", value
);
937 static struct ast_custom_function jack_hook_function
= {
939 .synopsis
= "Enable a jack hook on a channel",
940 .syntax
= "JACK_HOOK(<mode>,[options])",
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"
948 " Valid modes are:\n"
951 " spy - Create a read-only audio hook. Only an output jack port will\n"
953 " whisper - Create a write-only audio hook. Only an input jack port will\n"
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"
961 " Valid options are:\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)
977 res
= ast_unregister_application(jack_app
);
978 res
|= ast_custom_function_unregister(&jack_hook_function
);
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");