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