Jack Application. More...
#include "asterisk.h"#include <limits.h>#include <jack/jack.h>#include <jack/ringbuffer.h>#include <libresample.h>#include "asterisk/module.h"#include "asterisk/channel.h"#include "asterisk/strings.h"#include "asterisk/lock.h"#include "asterisk/app.h"#include "asterisk/pbx.h"#include "asterisk/audiohook.h"
Go to the source code of this file.
Data Structures | |
| struct | jack_data |
Defines | |
| #define | COMMON_OPTIONS |
| Common options between the Jack() app and JACK_HOOK() function. | |
| #define | RESAMPLE_QUALITY 1 |
| #define | RINGBUFFER_SIZE 16384 |
Enumerations | |
| enum | { OPT_SERVER_NAME = (1 << 0), OPT_INPUT_PORT = (1 << 1), OPT_OUTPUT_PORT = (1 << 2), OPT_NOSTART_SERVER = (1 << 3), OPT_CLIENT_NAME = (1 << 4) } |
| enum | { OPT_ARG_SERVER_NAME, OPT_ARG_INPUT_PORT, OPT_ARG_OUTPUT_PORT, OPT_ARG_CLIENT_NAME, OPT_ARG_ARRAY_SIZE } |
Functions | |
| static void | __reg_module (void) |
| static void | __unreg_module (void) |
| static int | alloc_resampler (struct jack_data *jack_data, int input) |
| static struct jack_data * | destroy_jack_data (struct jack_data *jack_data) |
| static int | disable_jack_hook (struct ast_channel *chan) |
| static int | enable_jack_hook (struct ast_channel *chan, char *data) |
| static void | handle_input (void *buf, jack_nframes_t nframes, struct jack_data *jack_data) |
| Handle jack input port. | |
| static void | handle_jack_audio (struct ast_channel *chan, struct jack_data *jack_data, struct ast_frame *out_frame) |
| handle jack audio | |
| static int | handle_options (struct jack_data *jack_data, const char *__options_str) |
| static void | handle_output (void *buf, jack_nframes_t nframes, struct jack_data *jack_data) |
| Handle jack output port. | |
| static int | init_jack_data (struct ast_channel *chan, struct jack_data *jack_data) |
| static struct jack_data * | jack_data_alloc (void) |
| static int | jack_exec (struct ast_channel *chan, void *data) |
| static int | jack_hook_callback (struct ast_audiohook *audiohook, struct ast_channel *chan, struct ast_frame *frame, enum ast_audiohook_direction direction) |
| static void | jack_hook_ds_destroy (void *data) |
| static int | jack_hook_write (struct ast_channel *chan, const char *cmd, char *data, const char *value) |
| static int | jack_process (jack_nframes_t nframes, void *arg) |
| static void | jack_shutdown (void *arg) |
| static const char * | jack_status_to_str (jack_status_t status) |
| static int | load_module (void) |
| static void | log_jack_status (const char *prefix, jack_status_t status) |
| static int | queue_voice_frame (struct jack_data *jack_data, struct ast_frame *f) |
| static int | unload_module (void) |
Variables | |
| static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "JACK Interface" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "0901e4e500243c855563a2d78b0c03e4" , .load = load_module, .unload = unload_module, } |
| static struct ast_module_info * | ast_module_info = &__mod_info |
| static char * | jack_app = "JACK" |
| static struct ast_app_option | jack_exec_options [128] = { [ 's' ] = { .flag = OPT_SERVER_NAME , .arg_index = OPT_ARG_SERVER_NAME + 1 }, [ 'i' ] = { .flag = OPT_INPUT_PORT , .arg_index = OPT_ARG_INPUT_PORT + 1 }, [ 'o' ] = { .flag = OPT_OUTPUT_PORT , .arg_index = OPT_ARG_OUTPUT_PORT + 1 }, [ 'n' ] = { .flag = OPT_NOSTART_SERVER }, [ 'c' ] = { .flag = OPT_CLIENT_NAME , .arg_index = OPT_ARG_CLIENT_NAME + 1 }, } |
| static struct ast_datastore_info | jack_hook_ds_info |
| static struct ast_custom_function | jack_hook_function |
| struct { | |
| jack_status_t status | |
| const char * str | |
| } | jack_status_table [] |
Jack Application.
This is an application to connect an Asterisk channel to an input and output jack port so that the audio can be processed through another application, or to play audio from another application.
$ svn co http://svn.digium.com/svn/thirdparty/libresample/trunk Definition in file app_jack.c.
| #define COMMON_OPTIONS |
Common options between the Jack() app and JACK_HOOK() function.
Definition at line 66 of file app_jack.c.
| #define RESAMPLE_QUALITY 1 |
Definition at line 61 of file app_jack.c.
Referenced by alloc_resampler().
| #define RINGBUFFER_SIZE 16384 |
Definition at line 63 of file app_jack.c.
Referenced by init_jack_data().
| anonymous enum |
Definition at line 648 of file app_jack.c.
00648 { 00649 OPT_SERVER_NAME = (1 << 0), 00650 OPT_INPUT_PORT = (1 << 1), 00651 OPT_OUTPUT_PORT = (1 << 2), 00652 OPT_NOSTART_SERVER = (1 << 3), 00653 OPT_CLIENT_NAME = (1 << 4), 00654 };
| anonymous enum |
| OPT_ARG_SERVER_NAME | |
| OPT_ARG_INPUT_PORT | |
| OPT_ARG_OUTPUT_PORT | |
| OPT_ARG_CLIENT_NAME | |
| OPT_ARG_ARRAY_SIZE |
Definition at line 656 of file app_jack.c.
00656 { 00657 OPT_ARG_SERVER_NAME, 00658 OPT_ARG_INPUT_PORT, 00659 OPT_ARG_OUTPUT_PORT, 00660 OPT_ARG_CLIENT_NAME, 00661 00662 /* Must be the last element */ 00663 OPT_ARG_ARRAY_SIZE, 00664 };
| static void __reg_module | ( | void | ) | [static] |
Definition at line 1025 of file app_jack.c.
| static void __unreg_module | ( | void | ) | [static] |
Definition at line 1025 of file app_jack.c.
| static int alloc_resampler | ( | struct jack_data * | jack_data, | |
| int | input | |||
| ) | [static] |
Definition at line 188 of file app_jack.c.
References ast_log(), jack_data::client, jack_data::input_resample_factor, jack_data::input_resampler, LOG_ERROR, jack_data::output_resample_factor, jack_data::output_resampler, and RESAMPLE_QUALITY.
Referenced by jack_process(), and queue_voice_frame().
00189 { 00190 double from_srate, to_srate, jack_srate; 00191 void **resampler; 00192 double *resample_factor; 00193 00194 if (input && jack_data->input_resampler) 00195 return 0; 00196 00197 if (!input && jack_data->output_resampler) 00198 return 0; 00199 00200 jack_srate = jack_get_sample_rate(jack_data->client); 00201 00202 /* XXX Hard coded 8 kHz */ 00203 00204 to_srate = input ? 8000.0 : jack_srate; 00205 from_srate = input ? jack_srate : 8000.0; 00206 00207 resample_factor = input ? &jack_data->input_resample_factor : 00208 &jack_data->output_resample_factor; 00209 00210 if (from_srate == to_srate) { 00211 /* Awesome! The jack sample rate is the same as ours. 00212 * Resampling isn't needed. */ 00213 *resample_factor = 1.0; 00214 return 0; 00215 } 00216 00217 *resample_factor = to_srate / from_srate; 00218 00219 resampler = input ? &jack_data->input_resampler : 00220 &jack_data->output_resampler; 00221 00222 if (!(*resampler = resample_open(RESAMPLE_QUALITY, 00223 *resample_factor, *resample_factor))) { 00224 ast_log(LOG_ERROR, "Failed to open %s resampler\n", 00225 input ? "input" : "output"); 00226 return -1; 00227 } 00228 00229 return 0; 00230 }
Definition at line 340 of file app_jack.c.
References ast_audiohook_destroy(), ast_free, ast_string_field_free_memory, jack_data::audiohook, jack_data::client, jack_data::has_audiohook, jack_data::input_port, jack_data::input_rb, jack_data::input_resampler, jack_data::output_port, jack_data::output_rb, and jack_data::output_resampler.
Referenced by enable_jack_hook(), jack_exec(), and jack_hook_ds_destroy().
00341 { 00342 if (jack_data->input_port) { 00343 jack_port_unregister(jack_data->client, jack_data->input_port); 00344 jack_data->input_port = NULL; 00345 } 00346 00347 if (jack_data->output_port) { 00348 jack_port_unregister(jack_data->client, jack_data->output_port); 00349 jack_data->output_port = NULL; 00350 } 00351 00352 if (jack_data->client) { 00353 jack_client_close(jack_data->client); 00354 jack_data->client = NULL; 00355 } 00356 00357 if (jack_data->input_rb) { 00358 jack_ringbuffer_free(jack_data->input_rb); 00359 jack_data->input_rb = NULL; 00360 } 00361 00362 if (jack_data->output_rb) { 00363 jack_ringbuffer_free(jack_data->output_rb); 00364 jack_data->output_rb = NULL; 00365 } 00366 00367 if (jack_data->output_resampler) { 00368 resample_close(jack_data->output_resampler); 00369 jack_data->output_resampler = NULL; 00370 } 00371 00372 if (jack_data->input_resampler) { 00373 resample_close(jack_data->input_resampler); 00374 jack_data->input_resampler = NULL; 00375 } 00376 00377 if (jack_data->has_audiohook) 00378 ast_audiohook_destroy(&jack_data->audiohook); 00379 00380 ast_string_field_free_memory(jack_data); 00381 00382 ast_free(jack_data); 00383 00384 return NULL; 00385 }
| static int disable_jack_hook | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 920 of file app_jack.c.
References ast_audiohook_detach(), ast_channel_datastore_find(), ast_channel_datastore_remove(), ast_channel_lock, ast_channel_unlock, ast_datastore_free(), ast_log(), jack_data::audiohook, ast_datastore::data, and LOG_WARNING.
Referenced by jack_hook_write().
00921 { 00922 struct ast_datastore *datastore; 00923 struct jack_data *jack_data; 00924 00925 ast_channel_lock(chan); 00926 00927 if (!(datastore = ast_channel_datastore_find(chan, &jack_hook_ds_info, NULL))) { 00928 ast_channel_unlock(chan); 00929 ast_log(LOG_WARNING, "No JACK_HOOK found to disable\n"); 00930 return -1; 00931 } 00932 00933 ast_channel_datastore_remove(chan, datastore); 00934 00935 jack_data = datastore->data; 00936 ast_audiohook_detach(&jack_data->audiohook); 00937 00938 /* Keep the channel locked while we destroy the datastore, so that we can 00939 * ensure that all of the jack stuff is stopped just in case another frame 00940 * tries to come through the audiohook callback. */ 00941 ast_datastore_free(datastore); 00942 00943 ast_channel_unlock(chan); 00944 00945 return 0; 00946 }
| static int enable_jack_hook | ( | struct ast_channel * | chan, | |
| char * | data | |||
| ) | [static] |
Definition at line 859 of file app_jack.c.
References AST_APP_ARG, ast_audiohook_attach(), ast_audiohook_init(), AST_AUDIOHOOK_TYPE_MANIPULATE, ast_channel_datastore_add(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_datastore_alloc, AST_DECLARE_APP_ARGS, ast_log(), AST_STANDARD_APP_ARGS, ast_strlen_zero(), jack_data::audiohook, ast_datastore::data, destroy_jack_data(), handle_options(), jack_data::has_audiohook, init_jack_data(), jack_data_alloc(), jack_hook_callback(), LOG_ERROR, ast_audiohook::manipulate_callback, ast_channel::name, and S_OR.
Referenced by jack_hook_write().
00860 { 00861 struct ast_datastore *datastore; 00862 struct jack_data *jack_data = NULL; 00863 AST_DECLARE_APP_ARGS(args, 00864 AST_APP_ARG(mode); 00865 AST_APP_ARG(options); 00866 ); 00867 00868 AST_STANDARD_APP_ARGS(args, data); 00869 00870 ast_channel_lock(chan); 00871 00872 if ((datastore = ast_channel_datastore_find(chan, &jack_hook_ds_info, NULL))) { 00873 ast_log(LOG_ERROR, "JACK_HOOK already enabled for '%s'\n", chan->name); 00874 goto return_error; 00875 } 00876 00877 if (ast_strlen_zero(args.mode) || strcasecmp(args.mode, "manipulate")) { 00878 ast_log(LOG_ERROR, "'%s' is not a supported mode. Only manipulate is supported.\n", 00879 S_OR(args.mode, "<none>")); 00880 goto return_error; 00881 } 00882 00883 if (!(jack_data = jack_data_alloc())) 00884 goto return_error; 00885 00886 if (!ast_strlen_zero(args.options) && handle_options(jack_data, args.options)) 00887 goto return_error; 00888 00889 if (init_jack_data(chan, jack_data)) 00890 goto return_error; 00891 00892 if (!(datastore = ast_datastore_alloc(&jack_hook_ds_info, NULL))) 00893 goto return_error; 00894 00895 jack_data->has_audiohook = 1; 00896 ast_audiohook_init(&jack_data->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "JACK_HOOK"); 00897 jack_data->audiohook.manipulate_callback = jack_hook_callback; 00898 00899 datastore->data = jack_data; 00900 00901 if (ast_audiohook_attach(chan, &jack_data->audiohook)) 00902 goto return_error; 00903 00904 if (ast_channel_datastore_add(chan, datastore)) 00905 goto return_error; 00906 00907 ast_channel_unlock(chan); 00908 00909 return 0; 00910 00911 return_error: 00912 ast_channel_unlock(chan); 00913 00914 if (jack_data) 00915 destroy_jack_data(jack_data); 00916 00917 return -1; 00918 }
| static void handle_input | ( | void * | buf, | |
| jack_nframes_t | nframes, | |||
| struct jack_data * | jack_data | |||
| ) | [static] |
Handle jack input port.
Read nframes number of samples from the input buffer, resample it if necessary, and write it into the appropriate ringbuffer.
Definition at line 238 of file app_jack.c.
References ARRAY_LEN, ast_debug, ast_log(), jack_data::input_rb, jack_data::input_resample_factor, jack_data::input_resampler, and LOG_ERROR.
Referenced by jack_process().
00240 { 00241 short s_buf[nframes]; 00242 float *in_buf = buf; 00243 size_t res; 00244 int i; 00245 size_t write_len = sizeof(s_buf); 00246 00247 if (jack_data->input_resampler) { 00248 int total_in_buf_used = 0; 00249 int total_out_buf_used = 0; 00250 float f_buf[nframes + 1]; 00251 00252 memset(f_buf, 0, sizeof(f_buf)); 00253 00254 while (total_in_buf_used < nframes) { 00255 int in_buf_used; 00256 int out_buf_used; 00257 00258 out_buf_used = resample_process(jack_data->input_resampler, 00259 jack_data->input_resample_factor, 00260 &in_buf[total_in_buf_used], nframes - total_in_buf_used, 00261 0, &in_buf_used, 00262 &f_buf[total_out_buf_used], ARRAY_LEN(f_buf) - total_out_buf_used); 00263 00264 if (out_buf_used < 0) 00265 break; 00266 00267 total_out_buf_used += out_buf_used; 00268 total_in_buf_used += in_buf_used; 00269 00270 if (total_out_buf_used == ARRAY_LEN(f_buf)) { 00271 ast_log(LOG_ERROR, "Output buffer filled ... need to increase its size, " 00272 "nframes '%d', total_out_buf_used '%d'\n", nframes, total_out_buf_used); 00273 break; 00274 } 00275 } 00276 00277 for (i = 0; i < total_out_buf_used; i++) 00278 s_buf[i] = f_buf[i] * (SHRT_MAX / 1.0); 00279 00280 write_len = total_out_buf_used * sizeof(int16_t); 00281 } else { 00282 /* No resampling needed */ 00283 00284 for (i = 0; i < nframes; i++) 00285 s_buf[i] = in_buf[i] * (SHRT_MAX / 1.0); 00286 } 00287 00288 res = jack_ringbuffer_write(jack_data->input_rb, (const char *) s_buf, write_len); 00289 if (res != write_len) { 00290 ast_debug(2, "Tried to write %d bytes to the ringbuffer, but only wrote %d\n", 00291 (int) sizeof(s_buf), (int) res); 00292 } 00293 }
| static void handle_jack_audio | ( | struct ast_channel * | chan, | |
| struct jack_data * | jack_data, | |||
| struct ast_frame * | out_frame | |||
| ) | [static] |
handle jack audio
| [in] | chan | The Asterisk channel to write the frames to if no output frame is provided. |
| [in] | jack_data | This is the jack_data struct that contains the input ringbuffer that audio will be read from. |
| [out] | out_frame | If this argument is non-NULL, then assuming there is enough data avilable in the ringbuffer, the audio in this frame will get replaced with audio from the input buffer. If there is not enough data available to read at this time, then the frame data gets zeroed out. |
Read data from the input ringbuffer, which is the properly resampled audio that was read from the jack input port. Write it to the channel in 20 ms frames, or fill up an output frame instead if one is provided.
Definition at line 600 of file app_jack.c.
References ARRAY_LEN, ast_debug, AST_FORMAT_SLINEAR, AST_FRAME_VOICE, ast_log(), ast_write(), buf, ast_frame::data, ast_frame::datalen, ast_frame::frametype, jack_data::input_rb, LOG_ERROR, ast_frame::ptr, and ast_frame::samples.
Referenced by jack_exec(), and jack_hook_callback().
00602 { 00603 short buf[160]; 00604 struct ast_frame f = { 00605 .frametype = AST_FRAME_VOICE, 00606 .subclass = AST_FORMAT_SLINEAR, 00607 .src = "JACK", 00608 .data.ptr = buf, 00609 .datalen = sizeof(buf), 00610 .samples = ARRAY_LEN(buf), 00611 }; 00612 00613 for (;;) { 00614 size_t res, read_len; 00615 char *read_buf; 00616 00617 read_len = out_frame ? out_frame->datalen : sizeof(buf); 00618 read_buf = out_frame ? out_frame->data.ptr : buf; 00619 00620 res = jack_ringbuffer_read_space(jack_data->input_rb); 00621 00622 if (res < read_len) { 00623 /* Not enough data ready for another frame, move on ... */ 00624 if (out_frame) { 00625 ast_debug(1, "Sending an empty frame for the JACK_HOOK\n"); 00626 memset(out_frame->data.ptr, 0, out_frame->datalen); 00627 } 00628 break; 00629 } 00630 00631 res = jack_ringbuffer_read(jack_data->input_rb, (char *) read_buf, read_len); 00632 00633 if (res < read_len) { 00634 ast_log(LOG_ERROR, "Error reading from ringbuffer, even though it said there was enough data\n"); 00635 break; 00636 } 00637 00638 if (out_frame) { 00639 /* If an output frame was provided, then we just want to fill up the 00640 * buffer in that frame and return. */ 00641 break; 00642 } 00643 00644 ast_write(chan, &f); 00645 } 00646 }
| static int handle_options | ( | struct jack_data * | jack_data, | |
| const char * | __options_str | |||
| ) | [static] |
Definition at line 692 of file app_jack.c.
References ast_app_parse_options(), ast_log(), ast_string_field_set, ast_strlen_zero(), ast_test_flag, jack_exec_options, LOG_ERROR, jack_data::no_start_server, OPT_ARG_ARRAY_SIZE, OPT_ARG_CLIENT_NAME, OPT_ARG_INPUT_PORT, OPT_ARG_OUTPUT_PORT, OPT_ARG_SERVER_NAME, OPT_CLIENT_NAME, OPT_INPUT_PORT, OPT_NOSTART_SERVER, OPT_OUTPUT_PORT, OPT_SERVER_NAME, and option_args.
Referenced by enable_jack_hook(), and jack_exec().
00693 { 00694 struct ast_flags options = { 0, }; 00695 char *option_args[OPT_ARG_ARRAY_SIZE]; 00696 char *options_str; 00697 00698 options_str = ast_strdupa(__options_str); 00699 00700 ast_app_parse_options(jack_exec_options, &options, option_args, options_str); 00701 00702 if (ast_test_flag(&options, OPT_SERVER_NAME)) { 00703 if (!ast_strlen_zero(option_args[OPT_ARG_SERVER_NAME])) 00704 ast_string_field_set(jack_data, server_name, option_args[OPT_ARG_SERVER_NAME]); 00705 else { 00706 ast_log(LOG_ERROR, "A server name must be provided with the s() option\n"); 00707 return -1; 00708 } 00709 } 00710 00711 if (ast_test_flag(&options, OPT_CLIENT_NAME)) { 00712 if (!ast_strlen_zero(option_args[OPT_ARG_CLIENT_NAME])) 00713 ast_string_field_set(jack_data, client_name, option_args[OPT_ARG_CLIENT_NAME]); 00714 else { 00715 ast_log(LOG_ERROR, "A client name must be provided with the c() option\n"); 00716 return -1; 00717 } 00718 } 00719 00720 if (ast_test_flag(&options, OPT_INPUT_PORT)) { 00721 if (!ast_strlen_zero(option_args[OPT_ARG_INPUT_PORT])) 00722 ast_string_field_set(jack_data, connect_input_port, option_args[OPT_ARG_INPUT_PORT]); 00723 else { 00724 ast_log(LOG_ERROR, "A name must be provided with the i() option\n"); 00725 return -1; 00726 } 00727 } 00728 00729 if (ast_test_flag(&options, OPT_OUTPUT_PORT)) { 00730 if (!ast_strlen_zero(option_args[OPT_ARG_OUTPUT_PORT])) 00731 ast_string_field_set(jack_data, connect_output_port, option_args[OPT_ARG_OUTPUT_PORT]); 00732 else { 00733 ast_log(LOG_ERROR, "A name must be provided with the o() option\n"); 00734 return -1; 00735 } 00736 } 00737 00738 jack_data->no_start_server = ast_test_flag(&options, OPT_NOSTART_SERVER) ? 1 : 0; 00739 00740 return 0; 00741 }
| static void handle_output | ( | void * | buf, | |
| jack_nframes_t | nframes, | |||
| struct jack_data * | jack_data | |||
| ) | [static] |
Handle jack output port.
Read nframes number of samples from the ringbuffer and write it out to the output port buffer.
Definition at line 301 of file app_jack.c.
References ast_debug, len(), and jack_data::output_rb.
Referenced by jack_process().
00303 { 00304 size_t res, len; 00305 00306 len = nframes * sizeof(float); 00307 00308 res = jack_ringbuffer_read(jack_data->output_rb, buf, len); 00309 00310 if (len != res) { 00311 ast_debug(2, "Wanted %d bytes to send to the output port, " 00312 "but only got %d\n", (int) len, (int) res); 00313 } 00314 }
| static int init_jack_data | ( | struct ast_channel * | chan, | |
| struct jack_data * | jack_data | |||
| ) | [static] |
Definition at line 387 of file app_jack.c.
References ast_channel_lock, ast_channel_unlock, ast_debug, ast_log(), ast_strlen_zero(), jack_data::client, jack_data::client_name, jack_data::connect_input_port, jack_data::connect_output_port, free, jack_data::input_port, jack_data::input_rb, jack_process(), jack_shutdown(), LOG_ERROR, log_jack_status(), ast_channel::name, jack_data::no_start_server, jack_data::output_port, jack_data::output_rb, RINGBUFFER_SIZE, jack_data::server_name, and status.
Referenced by enable_jack_hook(), and jack_exec().
00388 { 00389 const char *client_name; 00390 jack_status_t status = 0; 00391 jack_options_t jack_options = JackNullOption; 00392 00393 if (!ast_strlen_zero(jack_data->client_name)) { 00394 client_name = jack_data->client_name; 00395 } else { 00396 ast_channel_lock(chan); 00397 client_name = ast_strdupa(chan->name); 00398 ast_channel_unlock(chan); 00399 } 00400 00401 if (!(jack_data->output_rb = jack_ringbuffer_create(RINGBUFFER_SIZE))) 00402 return -1; 00403 00404 if (!(jack_data->input_rb = jack_ringbuffer_create(RINGBUFFER_SIZE))) 00405 return -1; 00406 00407 if (jack_data->no_start_server) 00408 jack_options |= JackNoStartServer; 00409 00410 if (!ast_strlen_zero(jack_data->server_name)) { 00411 jack_options |= JackServerName; 00412 jack_data->client = jack_client_open(client_name, jack_options, &status, 00413 jack_data->server_name); 00414 } else { 00415 jack_data->client = jack_client_open(client_name, jack_options, &status); 00416 } 00417 00418 if (status) 00419 log_jack_status("Client Open Status", status); 00420 00421 if (!jack_data->client) 00422 return -1; 00423 00424 jack_data->input_port = jack_port_register(jack_data->client, "input", 00425 JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput | JackPortIsTerminal, 0); 00426 if (!jack_data->input_port) { 00427 ast_log(LOG_ERROR, "Failed to create input port for jack port\n"); 00428 return -1; 00429 } 00430 00431 jack_data->output_port = jack_port_register(jack_data->client, "output", 00432 JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput | JackPortIsTerminal, 0); 00433 if (!jack_data->output_port) { 00434 ast_log(LOG_ERROR, "Failed to create output port for jack port\n"); 00435 return -1; 00436 } 00437 00438 if (jack_set_process_callback(jack_data->client, jack_process, jack_data)) { 00439 ast_log(LOG_ERROR, "Failed to register process callback with jack client\n"); 00440 return -1; 00441 } 00442 00443 jack_on_shutdown(jack_data->client, jack_shutdown, jack_data); 00444 00445 if (jack_activate(jack_data->client)) { 00446 ast_log(LOG_ERROR, "Unable to activate jack client\n"); 00447 return -1; 00448 } 00449 00450 while (!ast_strlen_zero(jack_data->connect_input_port)) { 00451 const char **ports; 00452 int i; 00453 00454 ports = jack_get_ports(jack_data->client, jack_data->connect_input_port, 00455 NULL, JackPortIsInput); 00456 00457 if (!ports) { 00458 ast_log(LOG_ERROR, "No input port matching '%s' was found\n", 00459 jack_data->connect_input_port); 00460 break; 00461 } 00462 00463 for (i = 0; ports[i]; i++) { 00464 ast_debug(1, "Found port '%s' that matched specified input port '%s'\n", 00465 ports[i], jack_data->connect_input_port); 00466 } 00467 00468 if (jack_connect(jack_data->client, jack_port_name(jack_data->output_port), ports[0])) { 00469 ast_log(LOG_ERROR, "Failed to connect '%s' to '%s'\n", ports[0], 00470 jack_port_name(jack_data->output_port)); 00471 } else { 00472 ast_debug(1, "Connected '%s' to '%s'\n", ports[0], 00473 jack_port_name(jack_data->output_port)); 00474 } 00475 00476 free((void *) ports); 00477 00478 break; 00479 } 00480 00481 while (!ast_strlen_zero(jack_data->connect_output_port)) { 00482 const char **ports; 00483 int i; 00484 00485 ports = jack_get_ports(jack_data->client, jack_data->connect_output_port, 00486 NULL, JackPortIsOutput); 00487 00488 if (!ports) { 00489 ast_log(LOG_ERROR, "No output port matching '%s' was found\n", 00490 jack_data->connect_output_port); 00491 break; 00492 } 00493 00494 for (i = 0; ports[i]; i++) { 00495 ast_debug(1, "Found port '%s' that matched specified output port '%s'\n", 00496 ports[i], jack_data->connect_output_port); 00497 } 00498 00499 if (jack_connect(jack_data->client, ports[0], jack_port_name(jack_data->input_port))) { 00500 ast_log(LOG_ERROR, "Failed to connect '%s' to '%s'\n", ports[0], 00501 jack_port_name(jack_data->input_port)); 00502 } else { 00503 ast_debug(1, "Connected '%s' to '%s'\n", ports[0], 00504 jack_port_name(jack_data->input_port)); 00505 } 00506 00507 free((void *) ports); 00508 00509 break; 00510 } 00511 00512 return 0; 00513 }
| static struct jack_data* jack_data_alloc | ( | void | ) | [static, read] |
Definition at line 674 of file app_jack.c.
References ast_calloc, ast_free, and ast_string_field_init.
Referenced by enable_jack_hook(), and jack_exec().
00675 { 00676 struct jack_data *jack_data; 00677 00678 if (!(jack_data = ast_calloc(1, sizeof(*jack_data)))) 00679 return NULL; 00680 00681 if (ast_string_field_init(jack_data, 32)) { 00682 ast_free(jack_data); 00683 return NULL; 00684 } 00685 00686 return jack_data; 00687 }
| static int jack_exec | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
Definition at line 743 of file app_jack.c.
References AST_APP_ARG, AST_CONTROL_HANGUP, AST_DECLARE_APP_ARGS, AST_FORMAT_SLINEAR, AST_FRAME_CONTROL, AST_FRAME_VOICE, ast_frfree, ast_read(), ast_set_read_format(), ast_set_write_format(), ast_strlen_zero(), ast_waitfor(), destroy_jack_data(), f, ast_frame::frametype, handle_jack_audio(), handle_options(), init_jack_data(), jack_data_alloc(), queue_voice_frame(), jack_data::stop, and ast_frame::subclass.
Referenced by load_module().
00744 { 00745 struct jack_data *jack_data; 00746 AST_DECLARE_APP_ARGS(args, 00747 AST_APP_ARG(options); 00748 ); 00749 00750 if (!(jack_data = jack_data_alloc())) 00751 return -1; 00752 00753 args.options = data; 00754 00755 if (!ast_strlen_zero(args.options) && handle_options(jack_data, args.options)) { 00756 destroy_jack_data(jack_data); 00757 return -1; 00758 } 00759 00760 if (init_jack_data(chan, jack_data)) { 00761 destroy_jack_data(jack_data); 00762 return -1; 00763 } 00764 00765 if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) { 00766 destroy_jack_data(jack_data); 00767 return -1; 00768 } 00769 00770 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) { 00771 destroy_jack_data(jack_data); 00772 return -1; 00773 } 00774 00775 while (!jack_data->stop) { 00776 struct ast_frame *f; 00777 00778 ast_waitfor(chan, -1); 00779 00780 f = ast_read(chan); 00781 if (!f) { 00782 jack_data->stop = 1; 00783 continue; 00784 } 00785 00786 switch (f->frametype) { 00787 case AST_FRAME_CONTROL: 00788 if (f->subclass == AST_CONTROL_HANGUP) 00789 jack_data->stop = 1; 00790 break; 00791 case AST_FRAME_VOICE: 00792 queue_voice_frame(jack_data, f); 00793 default: 00794 break; 00795 } 00796 00797 ast_frfree(f); 00798 00799 handle_jack_audio(chan, jack_data, NULL); 00800 } 00801 00802 jack_data = destroy_jack_data(jack_data); 00803 00804 return 0; 00805 }
| static int jack_hook_callback | ( | struct ast_audiohook * | audiohook, | |
| struct ast_channel * | chan, | |||
| struct ast_frame * | frame, | |||
| enum ast_audiohook_direction | direction | |||
| ) | [static] |
Definition at line 819 of file app_jack.c.
References AST_AUDIOHOOK_DIRECTION_READ, AST_AUDIOHOOK_STATUS_DONE, ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, AST_FORMAT_SLINEAR, AST_FRAME_VOICE, ast_log(), ast_datastore::data, ast_frame::frametype, handle_jack_audio(), LOG_ERROR, LOG_WARNING, ast_channel::name, queue_voice_frame(), ast_audiohook::status, and ast_frame::subclass.
Referenced by enable_jack_hook().
00821 { 00822 struct ast_datastore *datastore; 00823 struct jack_data *jack_data; 00824 00825 if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE) 00826 return 0; 00827 00828 if (direction != AST_AUDIOHOOK_DIRECTION_READ) 00829 return 0; 00830 00831 if (frame->frametype != AST_FRAME_VOICE) 00832 return 0; 00833 00834 if (frame->subclass != AST_FORMAT_SLINEAR) { 00835 ast_log(LOG_WARNING, "Expected frame in SLINEAR for the audiohook, but got format %d\n", 00836 frame->subclass); 00837 return 0; 00838 } 00839 00840 ast_channel_lock(chan); 00841 00842 if (!(datastore = ast_channel_datastore_find(chan, &jack_hook_ds_info, NULL))) { 00843 ast_log(LOG_ERROR, "JACK_HOOK datastore not found for '%s'\n", chan->name); 00844 ast_channel_unlock(chan); 00845 return -1; 00846 } 00847 00848 jack_data = datastore->data; 00849 00850 queue_voice_frame(jack_data, frame); 00851 00852 handle_jack_audio(chan, jack_data, frame); 00853 00854 ast_channel_unlock(chan); 00855 00856 return 0; 00857 }
| static void jack_hook_ds_destroy | ( | void * | data | ) | [static] |
Definition at line 807 of file app_jack.c.
References destroy_jack_data().
00808 { 00809 struct jack_data *jack_data = data; 00810 00811 destroy_jack_data(jack_data); 00812 }
| static int jack_hook_write | ( | struct ast_channel * | chan, | |
| const char * | cmd, | |||
| char * | data, | |||
| const char * | value | |||
| ) | [static] |
Definition at line 948 of file app_jack.c.
References ast_log(), disable_jack_hook(), enable_jack_hook(), and LOG_ERROR.
00950 { 00951 int res; 00952 00953 if (!strcasecmp(value, "on")) 00954 res = enable_jack_hook(chan, data); 00955 else if (!strcasecmp(value, "off")) 00956 res = disable_jack_hook(chan); 00957 else { 00958 ast_log(LOG_ERROR, "'%s' is not a valid value for JACK_HOOK()\n", value); 00959 res = -1; 00960 } 00961 00962 return res; 00963 }
| static int jack_process | ( | jack_nframes_t | nframes, | |
| void * | arg | |||
| ) | [static] |
Definition at line 316 of file app_jack.c.
References alloc_resampler(), handle_input(), handle_output(), jack_data::input_port, jack_data::input_resample_factor, and jack_data::output_port.
Referenced by init_jack_data().
00317 { 00318 struct jack_data *jack_data = arg; 00319 void *input_port_buf, *output_port_buf; 00320 00321 if (!jack_data->input_resample_factor) 00322 alloc_resampler(jack_data, 1); 00323 00324 input_port_buf = jack_port_get_buffer(jack_data->input_port, nframes); 00325 handle_input(input_port_buf, nframes, jack_data); 00326 00327 output_port_buf = jack_port_get_buffer(jack_data->output_port, nframes); 00328 handle_output(output_port_buf, nframes, jack_data); 00329 00330 return 0; 00331 }
| static void jack_shutdown | ( | void * | arg | ) | [static] |
Definition at line 333 of file app_jack.c.
References jack_data::stop.
Referenced by init_jack_data().
| static const char* jack_status_to_str | ( | jack_status_t | status | ) | [static] |
Definition at line 157 of file app_jack.c.
References ARRAY_LEN, and jack_status_table.
Referenced by log_jack_status().
00158 { 00159 int i; 00160 00161 for (i = 0; i < ARRAY_LEN(jack_status_table); i++) { 00162 if (jack_status_table[i].status == status) 00163 return jack_status_table[i].str; 00164 } 00165 00166 return "Unknown Error"; 00167 }
| static int load_module | ( | void | ) | [static] |
Definition at line 1011 of file app_jack.c.
References ast_custom_function_register, AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_register_application_xml, ast_unregister_application(), and jack_exec().
01012 { 01013 if (ast_register_application_xml(jack_app, jack_exec)) { 01014 return AST_MODULE_LOAD_DECLINE; 01015 } 01016 01017 if (ast_custom_function_register(&jack_hook_function)) { 01018 ast_unregister_application(jack_app); 01019 return AST_MODULE_LOAD_DECLINE; 01020 } 01021 01022 return AST_MODULE_LOAD_SUCCESS; 01023 }
| static void log_jack_status | ( | const char * | prefix, | |
| jack_status_t | status | |||
| ) | [static] |
Definition at line 169 of file app_jack.c.
References ast_log(), ast_str_alloca, ast_str_append(), ast_str_buffer(), ast_str_set(), first, jack_status_to_str(), LOG_NOTICE, and str.
Referenced by init_jack_data().
00170 { 00171 struct ast_str *str = ast_str_alloca(512); 00172 int i, first = 0; 00173 00174 for (i = 0; i < (sizeof(status) * 8); i++) { 00175 if (!(status & (1 << i))) 00176 continue; 00177 00178 if (!first) { 00179 ast_str_set(&str, 0, "%s", jack_status_to_str((1 << i))); 00180 first = 1; 00181 } else 00182 ast_str_append(&str, 0, ", %s", jack_status_to_str((1 << i))); 00183 } 00184 00185 ast_log(LOG_NOTICE, "%s: %s\n", prefix, ast_str_buffer(str)); 00186 }
Definition at line 515 of file app_jack.c.
References alloc_resampler(), ARRAY_LEN, ast_debug, ast_log(), ast_frame::data, LOG_ERROR, jack_data::output_rb, jack_data::output_resample_factor, jack_data::output_resampler, ast_frame::ptr, and ast_frame::samples.
Referenced by jack_exec(), and jack_hook_callback().
00516 { 00517 float f_buf[f->samples * 8]; 00518 size_t f_buf_used = 0; 00519 int i; 00520 int16_t *s_buf = f->data.ptr; 00521 size_t res; 00522 00523 memset(f_buf, 0, sizeof(f_buf)); 00524 00525 if (!jack_data->output_resample_factor) 00526 alloc_resampler(jack_data, 0); 00527 00528 if (jack_data->output_resampler) { 00529 float in_buf[f->samples]; 00530 int total_in_buf_used = 0; 00531 int total_out_buf_used = 0; 00532 00533 memset(in_buf, 0, sizeof(in_buf)); 00534 00535 for (i = 0; i < f->samples; i++) 00536 in_buf[i] = s_buf[i] * (1.0 / SHRT_MAX); 00537 00538 while (total_in_buf_used < ARRAY_LEN(in_buf)) { 00539 int in_buf_used; 00540 int out_buf_used; 00541 00542 out_buf_used = resample_process(jack_data->output_resampler, 00543 jack_data->output_resample_factor, 00544 &in_buf[total_in_buf_used], ARRAY_LEN(in_buf) - total_in_buf_used, 00545 0, &in_buf_used, 00546 &f_buf[total_out_buf_used], ARRAY_LEN(f_buf) - total_out_buf_used); 00547 00548 if (out_buf_used < 0) 00549 break; 00550 00551 total_out_buf_used += out_buf_used; 00552 total_in_buf_used += in_buf_used; 00553 00554 if (total_out_buf_used == ARRAY_LEN(f_buf)) { 00555 ast_log(LOG_ERROR, "Output buffer filled ... need to increase its size\n"); 00556 break; 00557 } 00558 } 00559 00560 f_buf_used = total_out_buf_used; 00561 if (f_buf_used > ARRAY_LEN(f_buf)) 00562 f_buf_used = ARRAY_LEN(f_buf); 00563 } else { 00564 /* No resampling needed */ 00565 00566 for (i = 0; i < f->samples; i++) 00567 f_buf[i] = s_buf[i] * (1.0 / SHRT_MAX); 00568 00569 f_buf_used = f->samples; 00570 } 00571 00572 res = jack_ringbuffer_write(jack_data->output_rb, (const char *) f_buf, f_buf_used * sizeof(float)); 00573 if (res != (f_buf_used * sizeof(float))) { 00574 ast_debug(2, "Tried to write %d bytes to the ringbuffer, but only wrote %d\n", 00575 (int) (f_buf_used * sizeof(float)), (int) res); 00576 } 00577 00578 return 0; 00579 }
| static int unload_module | ( | void | ) | [static] |
Definition at line 1001 of file app_jack.c.
References ast_custom_function_unregister(), and ast_unregister_application().
01002 { 01003 int res; 01004 01005 res = ast_unregister_application(jack_app); 01006 res |= ast_custom_function_unregister(&jack_hook_function); 01007 01008 return res; 01009 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "JACK Interface" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "0901e4e500243c855563a2d78b0c03e4" , .load = load_module, .unload = unload_module, } [static] |
Definition at line 1025 of file app_jack.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 1025 of file app_jack.c.
char* jack_app = "JACK" [static] |
Definition at line 115 of file app_jack.c.
struct ast_app_option jack_exec_options[128] = { [ 's' ] = { .flag = OPT_SERVER_NAME , .arg_index = OPT_ARG_SERVER_NAME + 1 }, [ 'i' ] = { .flag = OPT_INPUT_PORT , .arg_index = OPT_ARG_INPUT_PORT + 1 }, [ 'o' ] = { .flag = OPT_OUTPUT_PORT , .arg_index = OPT_ARG_OUTPUT_PORT + 1 }, [ 'n' ] = { .flag = OPT_NOSTART_SERVER }, [ 'c' ] = { .flag = OPT_CLIENT_NAME , .arg_index = OPT_ARG_CLIENT_NAME + 1 }, } [static] |
Definition at line 672 of file app_jack.c.
Referenced by handle_options().
struct ast_datastore_info jack_hook_ds_info [static] |
{
.type = "JACK_HOOK",
.destroy = jack_hook_ds_destroy,
}
Definition at line 814 of file app_jack.c.
struct ast_custom_function jack_hook_function [static] |
Definition at line 965 of file app_jack.c.
struct { ... } jack_status_table[] [static] |
Referenced by jack_status_to_str().
| jack_status_t status |
Definition at line 141 of file app_jack.c.
Referenced by __ast_pbx_run(), __iax2_show_peers(), _sip_show_peer(), _sip_show_peers(), acf_odbc_read(), acf_odbc_write(), action_agents(), action_extensionstate(), agent_hangup(), agent_read(), agi_exec_full(), aji_handle_presence(), aji_handle_subscribe(), aji_show_clients(), aji_status_exec(), ast_safe_system(), build_status(), build_timeout(), chanavail_exec(), child_handler(), complete_dpreply(), dundi_show_peers(), function_agent(), handle_cli_iax2_show_peer(), handle_cli_realtime_pgsql_status(), handle_open_receive_channel_ack_message(), handle_pri_show_span(), handle_pri_show_spans(), httpd_helper_thread(), init_jack_data(), join_queue(), local_hangup(), manager_iax2_show_peer_list(), ospauth_exec(), ospfinished_exec(), osplookup_exec(), ospnext_exec(), parse_status(), queue_exec(), read_exec(), readexten_exec(), realtime_ldap_status(), ring_entry(), rpt(), run_ras(), sendtext_exec(), sendurl_exec(), show_entry_history(), ss7_handle_cqm(), transfer_exec(), wait_for_answer(), and wait_our_turn().
| const char* str |
Definition at line 142 of file app_jack.c.
Referenced by _free_port_cfg(), acf_curl_exec(), action_status(), add_publish_event(), add_subscribe_event(), amixer_max(), ast_event_subscribe(), ast_hashtab_hash_string(), ast_hashtab_hash_string_nocase(), ast_hashtab_hash_string_sax(), do_magic_pickup(), find_realtime(), handle_playtones(), handle_tcptls_connection(), hash_string(), hid_device_init(), hid_device_mklist(), iax_parse_ies(), init_appendbuf(), jingle_new(), log_jack_status(), match_ie_val(), misdn_cfg_get(), misdn_cfg_get_config_string(), misdn_cfg_get_next_port(), misdn_cfg_get_ports_string(), misdn_cfg_is_group_method(), misdn_cfg_is_port_valid(), process_text_line(), regex(), setamixer(), usb_get_usbdev(), variable_count_cmp_fn(), and yyparse().
1.6.2