#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, const char *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_LOAD_ORDER , .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 = "88eaa8f5c1bd988bedd71113385e0886" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, } |
static struct ast_module_info * | ast_module_info = &__mod_info |
static const 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 [] |
$ 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 67 of file app_jack.c.
#define RESAMPLE_QUALITY 1 |
#define RINGBUFFER_SIZE 16384 |
anonymous enum |
Definition at line 650 of file app_jack.c.
00650 { 00651 OPT_SERVER_NAME = (1 << 0), 00652 OPT_INPUT_PORT = (1 << 1), 00653 OPT_OUTPUT_PORT = (1 << 2), 00654 OPT_NOSTART_SERVER = (1 << 3), 00655 OPT_CLIENT_NAME = (1 << 4), 00656 };
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 658 of file app_jack.c.
00658 { 00659 OPT_ARG_SERVER_NAME, 00660 OPT_ARG_INPUT_PORT, 00661 OPT_ARG_OUTPUT_PORT, 00662 OPT_ARG_CLIENT_NAME, 00663 00664 /* Must be the last element */ 00665 OPT_ARG_ARRAY_SIZE, 00666 };
static void __reg_module | ( | void | ) | [static] |
Definition at line 1018 of file app_jack.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 1018 of file app_jack.c.
static int alloc_resampler | ( | struct jack_data * | jack_data, | |
int | input | |||
) | [static] |
Definition at line 190 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().
00191 { 00192 double from_srate, to_srate, jack_srate; 00193 void **resampler; 00194 double *resample_factor; 00195 00196 if (input && jack_data->input_resampler) 00197 return 0; 00198 00199 if (!input && jack_data->output_resampler) 00200 return 0; 00201 00202 jack_srate = jack_get_sample_rate(jack_data->client); 00203 00204 /* XXX Hard coded 8 kHz */ 00205 00206 to_srate = input ? 8000.0 : jack_srate; 00207 from_srate = input ? jack_srate : 8000.0; 00208 00209 resample_factor = input ? &jack_data->input_resample_factor : 00210 &jack_data->output_resample_factor; 00211 00212 if (from_srate == to_srate) { 00213 /* Awesome! The jack sample rate is the same as ours. 00214 * Resampling isn't needed. */ 00215 *resample_factor = 1.0; 00216 return 0; 00217 } 00218 00219 *resample_factor = to_srate / from_srate; 00220 00221 resampler = input ? &jack_data->input_resampler : 00222 &jack_data->output_resampler; 00223 00224 if (!(*resampler = resample_open(RESAMPLE_QUALITY, 00225 *resample_factor, *resample_factor))) { 00226 ast_log(LOG_ERROR, "Failed to open %s resampler\n", 00227 input ? "input" : "output"); 00228 return -1; 00229 } 00230 00231 return 0; 00232 }
Definition at line 342 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().
00343 { 00344 if (jack_data->input_port) { 00345 jack_port_unregister(jack_data->client, jack_data->input_port); 00346 jack_data->input_port = NULL; 00347 } 00348 00349 if (jack_data->output_port) { 00350 jack_port_unregister(jack_data->client, jack_data->output_port); 00351 jack_data->output_port = NULL; 00352 } 00353 00354 if (jack_data->client) { 00355 jack_client_close(jack_data->client); 00356 jack_data->client = NULL; 00357 } 00358 00359 if (jack_data->input_rb) { 00360 jack_ringbuffer_free(jack_data->input_rb); 00361 jack_data->input_rb = NULL; 00362 } 00363 00364 if (jack_data->output_rb) { 00365 jack_ringbuffer_free(jack_data->output_rb); 00366 jack_data->output_rb = NULL; 00367 } 00368 00369 if (jack_data->output_resampler) { 00370 resample_close(jack_data->output_resampler); 00371 jack_data->output_resampler = NULL; 00372 } 00373 00374 if (jack_data->input_resampler) { 00375 resample_close(jack_data->input_resampler); 00376 jack_data->input_resampler = NULL; 00377 } 00378 00379 if (jack_data->has_audiohook) 00380 ast_audiohook_destroy(&jack_data->audiohook); 00381 00382 ast_string_field_free_memory(jack_data); 00383 00384 ast_free(jack_data); 00385 00386 return NULL; 00387 }
static int disable_jack_hook | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 913 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, jack_hook_ds_info, and LOG_WARNING.
Referenced by jack_hook_write().
00914 { 00915 struct ast_datastore *datastore; 00916 struct jack_data *jack_data; 00917 00918 ast_channel_lock(chan); 00919 00920 if (!(datastore = ast_channel_datastore_find(chan, &jack_hook_ds_info, NULL))) { 00921 ast_channel_unlock(chan); 00922 ast_log(LOG_WARNING, "No JACK_HOOK found to disable\n"); 00923 return -1; 00924 } 00925 00926 ast_channel_datastore_remove(chan, datastore); 00927 00928 jack_data = datastore->data; 00929 ast_audiohook_detach(&jack_data->audiohook); 00930 00931 /* Keep the channel locked while we destroy the datastore, so that we can 00932 * ensure that all of the jack stuff is stopped just in case another frame 00933 * tries to come through the audiohook callback. */ 00934 ast_datastore_free(datastore); 00935 00936 ast_channel_unlock(chan); 00937 00938 return 0; 00939 }
static int enable_jack_hook | ( | struct ast_channel * | chan, | |
char * | data | |||
) | [static] |
Definition at line 852 of file app_jack.c.
References args, 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(), jack_hook_ds_info, LOG_ERROR, ast_audiohook::manipulate_callback, ast_channel::name, and S_OR.
Referenced by jack_hook_write().
00853 { 00854 struct ast_datastore *datastore; 00855 struct jack_data *jack_data = NULL; 00856 AST_DECLARE_APP_ARGS(args, 00857 AST_APP_ARG(mode); 00858 AST_APP_ARG(options); 00859 ); 00860 00861 AST_STANDARD_APP_ARGS(args, data); 00862 00863 ast_channel_lock(chan); 00864 00865 if ((datastore = ast_channel_datastore_find(chan, &jack_hook_ds_info, NULL))) { 00866 ast_log(LOG_ERROR, "JACK_HOOK already enabled for '%s'\n", chan->name); 00867 goto return_error; 00868 } 00869 00870 if (ast_strlen_zero(args.mode) || strcasecmp(args.mode, "manipulate")) { 00871 ast_log(LOG_ERROR, "'%s' is not a supported mode. Only manipulate is supported.\n", 00872 S_OR(args.mode, "<none>")); 00873 goto return_error; 00874 } 00875 00876 if (!(jack_data = jack_data_alloc())) 00877 goto return_error; 00878 00879 if (!ast_strlen_zero(args.options) && handle_options(jack_data, args.options)) 00880 goto return_error; 00881 00882 if (init_jack_data(chan, jack_data)) 00883 goto return_error; 00884 00885 if (!(datastore = ast_datastore_alloc(&jack_hook_ds_info, NULL))) 00886 goto return_error; 00887 00888 jack_data->has_audiohook = 1; 00889 ast_audiohook_init(&jack_data->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "JACK_HOOK"); 00890 jack_data->audiohook.manipulate_callback = jack_hook_callback; 00891 00892 datastore->data = jack_data; 00893 00894 if (ast_audiohook_attach(chan, &jack_data->audiohook)) 00895 goto return_error; 00896 00897 if (ast_channel_datastore_add(chan, datastore)) 00898 goto return_error; 00899 00900 ast_channel_unlock(chan); 00901 00902 return 0; 00903 00904 return_error: 00905 ast_channel_unlock(chan); 00906 00907 if (jack_data) 00908 destroy_jack_data(jack_data); 00909 00910 return -1; 00911 }
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 240 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().
00242 { 00243 short s_buf[nframes]; 00244 float *in_buf = buf; 00245 size_t res; 00246 int i; 00247 size_t write_len = sizeof(s_buf); 00248 00249 if (jack_data->input_resampler) { 00250 int total_in_buf_used = 0; 00251 int total_out_buf_used = 0; 00252 float f_buf[nframes + 1]; 00253 00254 memset(f_buf, 0, sizeof(f_buf)); 00255 00256 while (total_in_buf_used < nframes) { 00257 int in_buf_used; 00258 int out_buf_used; 00259 00260 out_buf_used = resample_process(jack_data->input_resampler, 00261 jack_data->input_resample_factor, 00262 &in_buf[total_in_buf_used], nframes - total_in_buf_used, 00263 0, &in_buf_used, 00264 &f_buf[total_out_buf_used], ARRAY_LEN(f_buf) - total_out_buf_used); 00265 00266 if (out_buf_used < 0) 00267 break; 00268 00269 total_out_buf_used += out_buf_used; 00270 total_in_buf_used += in_buf_used; 00271 00272 if (total_out_buf_used == ARRAY_LEN(f_buf)) { 00273 ast_log(LOG_ERROR, "Output buffer filled ... need to increase its size, " 00274 "nframes '%d', total_out_buf_used '%d'\n", nframes, total_out_buf_used); 00275 break; 00276 } 00277 } 00278 00279 for (i = 0; i < total_out_buf_used; i++) 00280 s_buf[i] = f_buf[i] * (SHRT_MAX / 1.0); 00281 00282 write_len = total_out_buf_used * sizeof(int16_t); 00283 } else { 00284 /* No resampling needed */ 00285 00286 for (i = 0; i < nframes; i++) 00287 s_buf[i] = in_buf[i] * (SHRT_MAX / 1.0); 00288 } 00289 00290 res = jack_ringbuffer_write(jack_data->input_rb, (const char *) s_buf, write_len); 00291 if (res != write_len) { 00292 ast_debug(2, "Tried to write %d bytes to the ringbuffer, but only wrote %d\n", 00293 (int) sizeof(s_buf), (int) res); 00294 } 00295 }
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. |
Definition at line 602 of file app_jack.c.
References ARRAY_LEN, ast_debug, AST_FORMAT_SLINEAR, AST_FRAME_VOICE, ast_log(), ast_write(), ast_frame::data, ast_frame::datalen, f, jack_data::input_rb, LOG_ERROR, ast_frame::ptr, and ast_frame::samples.
Referenced by jack_exec(), and jack_hook_callback().
00604 { 00605 short buf[160]; 00606 struct ast_frame f = { 00607 .frametype = AST_FRAME_VOICE, 00608 .subclass.codec = AST_FORMAT_SLINEAR, 00609 .src = "JACK", 00610 .data.ptr = buf, 00611 .datalen = sizeof(buf), 00612 .samples = ARRAY_LEN(buf), 00613 }; 00614 00615 for (;;) { 00616 size_t res, read_len; 00617 char *read_buf; 00618 00619 read_len = out_frame ? out_frame->datalen : sizeof(buf); 00620 read_buf = out_frame ? out_frame->data.ptr : buf; 00621 00622 res = jack_ringbuffer_read_space(jack_data->input_rb); 00623 00624 if (res < read_len) { 00625 /* Not enough data ready for another frame, move on ... */ 00626 if (out_frame) { 00627 ast_debug(1, "Sending an empty frame for the JACK_HOOK\n"); 00628 memset(out_frame->data.ptr, 0, out_frame->datalen); 00629 } 00630 break; 00631 } 00632 00633 res = jack_ringbuffer_read(jack_data->input_rb, (char *) read_buf, read_len); 00634 00635 if (res < read_len) { 00636 ast_log(LOG_ERROR, "Error reading from ringbuffer, even though it said there was enough data\n"); 00637 break; 00638 } 00639 00640 if (out_frame) { 00641 /* If an output frame was provided, then we just want to fill up the 00642 * buffer in that frame and return. */ 00643 break; 00644 } 00645 00646 ast_write(chan, &f); 00647 } 00648 }
static int handle_options | ( | struct jack_data * | jack_data, | |
const char * | __options_str | |||
) | [static] |
Definition at line 690 of file app_jack.c.
References ast_app_parse_options(), ast_log(), ast_strdupa, 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, and OPT_SERVER_NAME.
Referenced by enable_jack_hook(), and jack_exec().
00691 { 00692 struct ast_flags options = { 0, }; 00693 char *option_args[OPT_ARG_ARRAY_SIZE]; 00694 char *options_str; 00695 00696 options_str = ast_strdupa(__options_str); 00697 00698 ast_app_parse_options(jack_exec_options, &options, option_args, options_str); 00699 00700 if (ast_test_flag(&options, OPT_SERVER_NAME)) { 00701 if (!ast_strlen_zero(option_args[OPT_ARG_SERVER_NAME])) 00702 ast_string_field_set(jack_data, server_name, option_args[OPT_ARG_SERVER_NAME]); 00703 else { 00704 ast_log(LOG_ERROR, "A server name must be provided with the s() option\n"); 00705 return -1; 00706 } 00707 } 00708 00709 if (ast_test_flag(&options, OPT_CLIENT_NAME)) { 00710 if (!ast_strlen_zero(option_args[OPT_ARG_CLIENT_NAME])) 00711 ast_string_field_set(jack_data, client_name, option_args[OPT_ARG_CLIENT_NAME]); 00712 else { 00713 ast_log(LOG_ERROR, "A client name must be provided with the c() option\n"); 00714 return -1; 00715 } 00716 } 00717 00718 if (ast_test_flag(&options, OPT_INPUT_PORT)) { 00719 if (!ast_strlen_zero(option_args[OPT_ARG_INPUT_PORT])) 00720 ast_string_field_set(jack_data, connect_input_port, option_args[OPT_ARG_INPUT_PORT]); 00721 else { 00722 ast_log(LOG_ERROR, "A name must be provided with the i() option\n"); 00723 return -1; 00724 } 00725 } 00726 00727 if (ast_test_flag(&options, OPT_OUTPUT_PORT)) { 00728 if (!ast_strlen_zero(option_args[OPT_ARG_OUTPUT_PORT])) 00729 ast_string_field_set(jack_data, connect_output_port, option_args[OPT_ARG_OUTPUT_PORT]); 00730 else { 00731 ast_log(LOG_ERROR, "A name must be provided with the o() option\n"); 00732 return -1; 00733 } 00734 } 00735 00736 jack_data->no_start_server = ast_test_flag(&options, OPT_NOSTART_SERVER) ? 1 : 0; 00737 00738 return 0; 00739 }
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 303 of file app_jack.c.
References ast_debug, len(), and jack_data::output_rb.
Referenced by jack_process().
00305 { 00306 size_t res, len; 00307 00308 len = nframes * sizeof(float); 00309 00310 res = jack_ringbuffer_read(jack_data->output_rb, buf, len); 00311 00312 if (len != res) { 00313 ast_debug(2, "Wanted %d bytes to send to the output port, " 00314 "but only got %d\n", (int) len, (int) res); 00315 } 00316 }
static int init_jack_data | ( | struct ast_channel * | chan, | |
struct jack_data * | jack_data | |||
) | [static] |
Definition at line 389 of file app_jack.c.
References ast_channel_lock, ast_channel_unlock, ast_debug, ast_log(), ast_strdupa, ast_strlen_zero(), jack_data::client, jack_data::client_name, jack_data::connect_input_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().
00390 { 00391 const char *client_name; 00392 jack_status_t status = 0; 00393 jack_options_t jack_options = JackNullOption; 00394 00395 if (!ast_strlen_zero(jack_data->client_name)) { 00396 client_name = jack_data->client_name; 00397 } else { 00398 ast_channel_lock(chan); 00399 client_name = ast_strdupa(chan->name); 00400 ast_channel_unlock(chan); 00401 } 00402 00403 if (!(jack_data->output_rb = jack_ringbuffer_create(RINGBUFFER_SIZE))) 00404 return -1; 00405 00406 if (!(jack_data->input_rb = jack_ringbuffer_create(RINGBUFFER_SIZE))) 00407 return -1; 00408 00409 if (jack_data->no_start_server) 00410 jack_options |= JackNoStartServer; 00411 00412 if (!ast_strlen_zero(jack_data->server_name)) { 00413 jack_options |= JackServerName; 00414 jack_data->client = jack_client_open(client_name, jack_options, &status, 00415 jack_data->server_name); 00416 } else { 00417 jack_data->client = jack_client_open(client_name, jack_options, &status); 00418 } 00419 00420 if (status) 00421 log_jack_status("Client Open Status", status); 00422 00423 if (!jack_data->client) 00424 return -1; 00425 00426 jack_data->input_port = jack_port_register(jack_data->client, "input", 00427 JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput | JackPortIsTerminal, 0); 00428 if (!jack_data->input_port) { 00429 ast_log(LOG_ERROR, "Failed to create input port for jack port\n"); 00430 return -1; 00431 } 00432 00433 jack_data->output_port = jack_port_register(jack_data->client, "output", 00434 JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput | JackPortIsTerminal, 0); 00435 if (!jack_data->output_port) { 00436 ast_log(LOG_ERROR, "Failed to create output port for jack port\n"); 00437 return -1; 00438 } 00439 00440 if (jack_set_process_callback(jack_data->client, jack_process, jack_data)) { 00441 ast_log(LOG_ERROR, "Failed to register process callback with jack client\n"); 00442 return -1; 00443 } 00444 00445 jack_on_shutdown(jack_data->client, jack_shutdown, jack_data); 00446 00447 if (jack_activate(jack_data->client)) { 00448 ast_log(LOG_ERROR, "Unable to activate jack client\n"); 00449 return -1; 00450 } 00451 00452 while (!ast_strlen_zero(jack_data->connect_input_port)) { 00453 const char **ports; 00454 int i; 00455 00456 ports = jack_get_ports(jack_data->client, jack_data->connect_input_port, 00457 NULL, JackPortIsInput); 00458 00459 if (!ports) { 00460 ast_log(LOG_ERROR, "No input port matching '%s' was found\n", 00461 jack_data->connect_input_port); 00462 break; 00463 } 00464 00465 for (i = 0; ports[i]; i++) { 00466 ast_debug(1, "Found port '%s' that matched specified input port '%s'\n", 00467 ports[i], jack_data->connect_input_port); 00468 } 00469 00470 if (jack_connect(jack_data->client, jack_port_name(jack_data->output_port), ports[0])) { 00471 ast_log(LOG_ERROR, "Failed to connect '%s' to '%s'\n", ports[0], 00472 jack_port_name(jack_data->output_port)); 00473 } else { 00474 ast_debug(1, "Connected '%s' to '%s'\n", ports[0], 00475 jack_port_name(jack_data->output_port)); 00476 } 00477 00478 free((void *) ports); 00479 00480 break; 00481 } 00482 00483 while (!ast_strlen_zero(jack_data->connect_output_port)) { 00484 const char **ports; 00485 int i; 00486 00487 ports = jack_get_ports(jack_data->client, jack_data->connect_output_port, 00488 NULL, JackPortIsOutput); 00489 00490 if (!ports) { 00491 ast_log(LOG_ERROR, "No output port matching '%s' was found\n", 00492 jack_data->connect_output_port); 00493 break; 00494 } 00495 00496 for (i = 0; ports[i]; i++) { 00497 ast_debug(1, "Found port '%s' that matched specified output port '%s'\n", 00498 ports[i], jack_data->connect_output_port); 00499 } 00500 00501 if (jack_connect(jack_data->client, ports[0], jack_port_name(jack_data->input_port))) { 00502 ast_log(LOG_ERROR, "Failed to connect '%s' to '%s'\n", ports[0], 00503 jack_port_name(jack_data->input_port)); 00504 } else { 00505 ast_debug(1, "Connected '%s' to '%s'\n", ports[0], 00506 jack_port_name(jack_data->input_port)); 00507 } 00508 00509 free((void *) ports); 00510 00511 break; 00512 } 00513 00514 return 0; 00515 }
static struct jack_data* jack_data_alloc | ( | void | ) | [static] |
Definition at line 676 of file app_jack.c.
References ast_calloc_with_stringfields.
Referenced by enable_jack_hook(), and jack_exec().
00677 { 00678 struct jack_data *jack_data; 00679 00680 if (!(jack_data = ast_calloc_with_stringfields(1, struct jack_data, 32))) { 00681 return NULL; 00682 } 00683 00684 return jack_data; 00685 }
static int jack_exec | ( | struct ast_channel * | chan, | |
const char * | data | |||
) | [static] |
Definition at line 741 of file app_jack.c.
References AST_CONTROL_HANGUP, 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, handle_jack_audio(), handle_options(), init_jack_data(), jack_data_alloc(), queue_voice_frame(), and jack_data::stop.
Referenced by load_module().
00742 { 00743 struct jack_data *jack_data; 00744 00745 if (!(jack_data = jack_data_alloc())) 00746 return -1; 00747 00748 if (!ast_strlen_zero(data) && handle_options(jack_data, data)) { 00749 destroy_jack_data(jack_data); 00750 return -1; 00751 } 00752 00753 if (init_jack_data(chan, jack_data)) { 00754 destroy_jack_data(jack_data); 00755 return -1; 00756 } 00757 00758 if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) { 00759 destroy_jack_data(jack_data); 00760 return -1; 00761 } 00762 00763 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) { 00764 destroy_jack_data(jack_data); 00765 return -1; 00766 } 00767 00768 while (!jack_data->stop) { 00769 struct ast_frame *f; 00770 00771 ast_waitfor(chan, -1); 00772 00773 f = ast_read(chan); 00774 if (!f) { 00775 jack_data->stop = 1; 00776 continue; 00777 } 00778 00779 switch (f->frametype) { 00780 case AST_FRAME_CONTROL: 00781 if (f->subclass.integer == AST_CONTROL_HANGUP) 00782 jack_data->stop = 1; 00783 break; 00784 case AST_FRAME_VOICE: 00785 queue_voice_frame(jack_data, f); 00786 default: 00787 break; 00788 } 00789 00790 ast_frfree(f); 00791 00792 handle_jack_audio(chan, jack_data, NULL); 00793 } 00794 00795 jack_data = destroy_jack_data(jack_data); 00796 00797 return 0; 00798 }
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 812 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_getformatname(), ast_log(), jack_data::audiohook, ast_frame_subclass::codec, ast_datastore::data, ast_frame::frametype, handle_jack_audio(), jack_hook_ds_info, LOG_ERROR, LOG_WARNING, ast_channel::name, queue_voice_frame(), ast_audiohook::status, and ast_frame::subclass.
Referenced by enable_jack_hook().
00814 { 00815 struct ast_datastore *datastore; 00816 struct jack_data *jack_data; 00817 00818 if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE) 00819 return 0; 00820 00821 if (direction != AST_AUDIOHOOK_DIRECTION_READ) 00822 return 0; 00823 00824 if (frame->frametype != AST_FRAME_VOICE) 00825 return 0; 00826 00827 if (frame->subclass.codec != AST_FORMAT_SLINEAR) { 00828 ast_log(LOG_WARNING, "Expected frame in SLINEAR for the audiohook, but got format %s\n", 00829 ast_getformatname(frame->subclass.codec)); 00830 return 0; 00831 } 00832 00833 ast_channel_lock(chan); 00834 00835 if (!(datastore = ast_channel_datastore_find(chan, &jack_hook_ds_info, NULL))) { 00836 ast_log(LOG_ERROR, "JACK_HOOK datastore not found for '%s'\n", chan->name); 00837 ast_channel_unlock(chan); 00838 return -1; 00839 } 00840 00841 jack_data = datastore->data; 00842 00843 queue_voice_frame(jack_data, frame); 00844 00845 handle_jack_audio(chan, jack_data, frame); 00846 00847 ast_channel_unlock(chan); 00848 00849 return 0; 00850 }
static void jack_hook_ds_destroy | ( | void * | data | ) | [static] |
Definition at line 800 of file app_jack.c.
References destroy_jack_data().
00801 { 00802 struct jack_data *jack_data = data; 00803 00804 destroy_jack_data(jack_data); 00805 }
static int jack_hook_write | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | data, | |||
const char * | value | |||
) | [static] |
Definition at line 941 of file app_jack.c.
References ast_log(), disable_jack_hook(), enable_jack_hook(), and LOG_ERROR.
00943 { 00944 int res; 00945 00946 if (!strcasecmp(value, "on")) 00947 res = enable_jack_hook(chan, data); 00948 else if (!strcasecmp(value, "off")) 00949 res = disable_jack_hook(chan); 00950 else { 00951 ast_log(LOG_ERROR, "'%s' is not a valid value for JACK_HOOK()\n", value); 00952 res = -1; 00953 } 00954 00955 return res; 00956 }
static int jack_process | ( | jack_nframes_t | nframes, | |
void * | arg | |||
) | [static] |
Definition at line 318 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().
00319 { 00320 struct jack_data *jack_data = arg; 00321 void *input_port_buf, *output_port_buf; 00322 00323 if (!jack_data->input_resample_factor) 00324 alloc_resampler(jack_data, 1); 00325 00326 input_port_buf = jack_port_get_buffer(jack_data->input_port, nframes); 00327 handle_input(input_port_buf, nframes, jack_data); 00328 00329 output_port_buf = jack_port_get_buffer(jack_data->output_port, nframes); 00330 handle_output(output_port_buf, nframes, jack_data); 00331 00332 return 0; 00333 }
static void jack_shutdown | ( | void * | arg | ) | [static] |
Definition at line 335 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 159 of file app_jack.c.
References ARRAY_LEN, and jack_status_table.
Referenced by log_jack_status().
00160 { 00161 int i; 00162 00163 for (i = 0; i < ARRAY_LEN(jack_status_table); i++) { 00164 if (jack_status_table[i].status == status) 00165 return jack_status_table[i].str; 00166 } 00167 00168 return "Unknown Error"; 00169 }
static int load_module | ( | void | ) | [static] |
Definition at line 1004 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(), jack_exec(), and jack_hook_function.
01005 { 01006 if (ast_register_application_xml(jack_app, jack_exec)) { 01007 return AST_MODULE_LOAD_DECLINE; 01008 } 01009 01010 if (ast_custom_function_register(&jack_hook_function)) { 01011 ast_unregister_application(jack_app); 01012 return AST_MODULE_LOAD_DECLINE; 01013 } 01014 01015 return AST_MODULE_LOAD_SUCCESS; 01016 }
static void log_jack_status | ( | const char * | prefix, | |
jack_status_t | status | |||
) | [static] |
Definition at line 171 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().
00172 { 00173 struct ast_str *str = ast_str_alloca(512); 00174 int i, first = 0; 00175 00176 for (i = 0; i < (sizeof(status) * 8); i++) { 00177 if (!(status & (1 << i))) 00178 continue; 00179 00180 if (!first) { 00181 ast_str_set(&str, 0, "%s", jack_status_to_str((1 << i))); 00182 first = 1; 00183 } else 00184 ast_str_append(&str, 0, ", %s", jack_status_to_str((1 << i))); 00185 } 00186 00187 ast_log(LOG_NOTICE, "%s: %s\n", prefix, ast_str_buffer(str)); 00188 }
Definition at line 517 of file app_jack.c.
References alloc_resampler(), ARRAY_LEN, ast_debug, ast_log(), f, LOG_ERROR, jack_data::output_rb, jack_data::output_resample_factor, and jack_data::output_resampler.
Referenced by jack_exec(), and jack_hook_callback().
00518 { 00519 float f_buf[f->samples * 8]; 00520 size_t f_buf_used = 0; 00521 int i; 00522 int16_t *s_buf = f->data.ptr; 00523 size_t res; 00524 00525 memset(f_buf, 0, sizeof(f_buf)); 00526 00527 if (!jack_data->output_resample_factor) 00528 alloc_resampler(jack_data, 0); 00529 00530 if (jack_data->output_resampler) { 00531 float in_buf[f->samples]; 00532 int total_in_buf_used = 0; 00533 int total_out_buf_used = 0; 00534 00535 memset(in_buf, 0, sizeof(in_buf)); 00536 00537 for (i = 0; i < f->samples; i++) 00538 in_buf[i] = s_buf[i] * (1.0 / SHRT_MAX); 00539 00540 while (total_in_buf_used < ARRAY_LEN(in_buf)) { 00541 int in_buf_used; 00542 int out_buf_used; 00543 00544 out_buf_used = resample_process(jack_data->output_resampler, 00545 jack_data->output_resample_factor, 00546 &in_buf[total_in_buf_used], ARRAY_LEN(in_buf) - total_in_buf_used, 00547 0, &in_buf_used, 00548 &f_buf[total_out_buf_used], ARRAY_LEN(f_buf) - total_out_buf_used); 00549 00550 if (out_buf_used < 0) 00551 break; 00552 00553 total_out_buf_used += out_buf_used; 00554 total_in_buf_used += in_buf_used; 00555 00556 if (total_out_buf_used == ARRAY_LEN(f_buf)) { 00557 ast_log(LOG_ERROR, "Output buffer filled ... need to increase its size\n"); 00558 break; 00559 } 00560 } 00561 00562 f_buf_used = total_out_buf_used; 00563 if (f_buf_used > ARRAY_LEN(f_buf)) 00564 f_buf_used = ARRAY_LEN(f_buf); 00565 } else { 00566 /* No resampling needed */ 00567 00568 for (i = 0; i < f->samples; i++) 00569 f_buf[i] = s_buf[i] * (1.0 / SHRT_MAX); 00570 00571 f_buf_used = f->samples; 00572 } 00573 00574 res = jack_ringbuffer_write(jack_data->output_rb, (const char *) f_buf, f_buf_used * sizeof(float)); 00575 if (res != (f_buf_used * sizeof(float))) { 00576 ast_debug(2, "Tried to write %d bytes to the ringbuffer, but only wrote %d\n", 00577 (int) (f_buf_used * sizeof(float)), (int) res); 00578 } 00579 00580 return 0; 00581 }
static int unload_module | ( | void | ) | [static] |
Definition at line 994 of file app_jack.c.
References ast_custom_function_unregister(), ast_unregister_application(), and jack_hook_function.
00995 { 00996 int res; 00997 00998 res = ast_unregister_application(jack_app); 00999 res |= ast_custom_function_unregister(&jack_hook_function); 01000 01001 return res; 01002 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .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 = "88eaa8f5c1bd988bedd71113385e0886" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, } [static] |
Definition at line 1018 of file app_jack.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 1018 of file app_jack.c.
const char jack_app[] = "JACK" [static] |
Definition at line 117 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] |
struct ast_datastore_info jack_hook_ds_info [static] |
Initial value:
{ .type = "JACK_HOOK", .destroy = jack_hook_ds_destroy, }
Definition at line 807 of file app_jack.c.
Referenced by disable_jack_hook(), enable_jack_hook(), and jack_hook_callback().
struct ast_custom_function jack_hook_function [static] |
struct { ... } jack_status_table[] [static] |
Referenced by jack_status_to_str().
jack_status_t status |
Definition at line 143 of file app_jack.c.
Referenced by __iax2_show_peers(), _child_handler(), _sip_show_peer(), _sip_show_peers(), acf_odbc_read(), acf_odbc_write(), action_agents(), action_extensionstate(), agi_exec_full(), aji_handle_presence(), aji_handle_subscribe(), aji_show_clients(), aji_status_exec(), ast_safe_system(), ast_srtp_change_source(), build_dialplan_useage_map(), build_status(), build_timeout(), callerid_read(), callerid_write(), chanavail_exec(), complete_dpreply(), connectedline_read(), connectedline_write(), dundi_show_peers(), filestream_destructor(), function_agent(), handle_cc_notify(), handle_cli_iax2_show_peer(), handle_cli_realtime_pgsql_status(), handle_open_receive_channel_ack_message(), init_jack_data(), join_queue(), local_hangup(), manager_iax2_show_peer_list(), ospauth_exec(), ospfinished_exec(), osplookup_exec(), ospnext_exec(), parse_status(), party_id_read(), party_id_write(), party_name_read(), party_name_write(), party_number_read(), party_number_write(), party_subaddress_read(), party_subaddress_write(), peers_data_provider_get(), queue_exec(), read_exec(), readexten_exec(), realtime_ldap_status(), redirecting_read(), redirecting_write(), ring_entry(), rpt(), run_ras(), sendtext_exec(), sendurl_exec(), shaun_of_the_dead(), show_entry_history(), sig_pri_cc_agent_req_rsp(), sig_pri_cli_show_span(), sig_pri_cli_show_spans(), transfer_exec(), wait_for_answer(), and wait_our_turn().
const char* str |
Definition at line 144 of file app_jack.c.
Referenced by _free_port_cfg(), acf_curl_helper(), acf_cut_exec(), action_status(), add_ie(), add_ipv4_ie(), add_publish_event(), add_subscribe_event(), add_timeval_ie(), add_user_extension(), alloc_event(), amixer_max(), aoc_charge_type_str(), aoc_charged_item_str(), aoc_rate_type_str(), aoc_scale_str(), aoc_type_of_totaling_str(), aoc_volume_unit_str(), aocmessage_get_unit_entry(), append_ie(), append_ies(), ast_cc_agent_set_interfaces_chanvar(), ast_event_subscribe(), ast_func_read(), ast_func_read2(), ast_hashtab_hash_string(), ast_hashtab_hash_string_nocase(), ast_hashtab_hash_string_sax(), ast_include_rename(), ast_parse_digest(), ast_set_cc_interfaces_chanvar(), ast_sockaddr_stringify_fmt(), ast_str_expr(), ast_str_get_encoded_str(), ast_str_retrieve_variable(), ast_term_color_code(), ast_translate_path_to_str(), base64_helper(), blacklist_read2(), build_cc_interfaces_chanvar(), build_user_routes(), cc_extension_monitor_init(), cc_generic_agent_start_monitoring(), cc_unique_append(), custom_log(), dial_handle_playtones(), do_magic_pickup(), encode_timestamp(), find_realtime(), frame_trace_helper(), function_fieldnum_helper(), function_fieldqty_helper(), get_pidf_body(), handle_cli_core_show_translation(), handle_getvariablefull(), handle_playtones(), handle_tcptls_connection(), hash_string(), hid_device_init(), hid_device_mklist(), iax_parse_ies(), import_helper(), import_read2(), init_appendbuf(), jingle_new(), log_jack_status(), mansession_cmp_fn(), 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(), misdn_to_str_plan(), misdn_to_str_pres(), misdn_to_str_screen(), misdn_to_str_ton(), parse_cdata(), pbx_retrieve_variable(), pp_each_extension_helper(), pp_each_user_helper(), process_text_line(), regex(), replace(), sdp_crypto_process(), security_event_cb(), sendtext_exec(), set2(), setamixer(), substitute_escapes(), syslog_log(), transmit_info_with_aoc(), usb_get_usbdev(), variable_count_cmp_fn(), and yyparse().