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 int | alloc_resampler (struct jack_data *jack_data, int input) |
AST_APP_OPTIONS (jack_exec_options, BEGIN_OPTIONS AST_APP_OPTION_ARG('s', OPT_SERVER_NAME, OPT_ARG_SERVER_NAME), AST_APP_OPTION_ARG('i', OPT_INPUT_PORT, OPT_ARG_INPUT_PORT), AST_APP_OPTION_ARG('o', OPT_OUTPUT_PORT, OPT_ARG_OUTPUT_PORT), AST_APP_OPTION('n', OPT_NOSTART_SERVER), AST_APP_OPTION_ARG('c', OPT_CLIENT_NAME, OPT_ARG_CLIENT_NAME), END_OPTIONS) | |
AST_MODULE_INFO_STANDARD (ASTERISK_GPL_KEY,"JACK Interface") | |
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 const char | jack_app [] = "JACK" |
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 67 of file app_jack.c.
#define RESAMPLE_QUALITY 1 |
Definition at line 62 of file app_jack.c.
Referenced by alloc_resampler().
#define RINGBUFFER_SIZE 16384 |
Definition at line 64 of file app_jack.c.
Referenced by init_jack_data().
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 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 }
AST_APP_OPTIONS | ( | jack_exec_options | , | |
BEGIN_OPTIONS | AST_APP_OPTION_ARG's', OPT_SERVER_NAME, OPT_ARG_SERVER_NAME, | |||
AST_APP_OPTION_ARG('i', OPT_INPUT_PORT, OPT_ARG_INPUT_PORT) | , | |||
AST_APP_OPTION_ARG('o', OPT_OUTPUT_PORT, OPT_ARG_OUTPUT_PORT) | , | |||
AST_APP_OPTION('n', OPT_NOSTART_SERVER) | , | |||
AST_APP_OPTION_ARG('c', OPT_CLIENT_NAME, OPT_ARG_CLIENT_NAME) | , | |||
END_OPTIONS | ||||
) |
AST_MODULE_INFO_STANDARD | ( | ASTERISK_GPL_KEY | , | |
"JACK Interface" | ||||
) |
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 921 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().
00922 { 00923 struct ast_datastore *datastore; 00924 struct jack_data *jack_data; 00925 00926 ast_channel_lock(chan); 00927 00928 if (!(datastore = ast_channel_datastore_find(chan, &jack_hook_ds_info, NULL))) { 00929 ast_channel_unlock(chan); 00930 ast_log(LOG_WARNING, "No JACK_HOOK found to disable\n"); 00931 return -1; 00932 } 00933 00934 ast_channel_datastore_remove(chan, datastore); 00935 00936 jack_data = datastore->data; 00937 ast_audiohook_detach(&jack_data->audiohook); 00938 00939 /* Keep the channel locked while we destroy the datastore, so that we can 00940 * ensure that all of the jack stuff is stopped just in case another frame 00941 * tries to come through the audiohook callback. */ 00942 ast_datastore_free(datastore); 00943 00944 ast_channel_unlock(chan); 00945 00946 return 0; 00947 }
static int enable_jack_hook | ( | struct ast_channel * | chan, | |
char * | data | |||
) | [static] |
Definition at line 854 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_datastore_free(), 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, and S_OR.
Referenced by jack_hook_write().
00855 { 00856 struct ast_datastore *datastore; 00857 struct jack_data *jack_data = NULL; 00858 AST_DECLARE_APP_ARGS(args, 00859 AST_APP_ARG(mode); 00860 AST_APP_ARG(options); 00861 ); 00862 00863 AST_STANDARD_APP_ARGS(args, data); 00864 00865 ast_channel_lock(chan); 00866 00867 if ((datastore = ast_channel_datastore_find(chan, &jack_hook_ds_info, NULL))) { 00868 ast_log(LOG_ERROR, "JACK_HOOK already enabled for '%s'\n", chan->name); 00869 goto return_error; 00870 } 00871 00872 if (ast_strlen_zero(args.mode) || strcasecmp(args.mode, "manipulate")) { 00873 ast_log(LOG_ERROR, "'%s' is not a supported mode. Only manipulate is supported.\n", 00874 S_OR(args.mode, "<none>")); 00875 goto return_error; 00876 } 00877 00878 if (!(jack_data = jack_data_alloc())) 00879 goto return_error; 00880 00881 if (!ast_strlen_zero(args.options) && handle_options(jack_data, args.options)) 00882 goto return_error; 00883 00884 if (init_jack_data(chan, jack_data)) 00885 goto return_error; 00886 00887 if (!(datastore = ast_datastore_alloc(&jack_hook_ds_info, NULL))) 00888 goto return_error; 00889 00890 jack_data->has_audiohook = 1; 00891 ast_audiohook_init(&jack_data->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "JACK_HOOK"); 00892 jack_data->audiohook.manipulate_callback = jack_hook_callback; 00893 00894 datastore->data = jack_data; 00895 00896 if (ast_audiohook_attach(chan, &jack_data->audiohook)) 00897 goto return_error; 00898 00899 if (ast_channel_datastore_add(chan, datastore)) 00900 goto return_error; 00901 00902 ast_channel_unlock(chan); 00903 00904 return 0; 00905 00906 return_error: 00907 ast_channel_unlock(chan); 00908 00909 if (jack_data) { 00910 destroy_jack_data(jack_data); 00911 } 00912 00913 if (datastore) { 00914 datastore->data = NULL; 00915 ast_datastore_free(datastore); 00916 } 00917 00918 return -1; 00919 }
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. |
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 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, ast_frame::frametype, 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, 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, free, jack_data::input_port, jack_data::input_rb, jack_process(), jack_shutdown(), LOG_ERROR, log_jack_status(), jack_data::no_start_server, jack_data::output_port, jack_data::output_rb, RINGBUFFER_SIZE, 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, read] |
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, ast_frame::frametype, handle_jack_audio(), handle_options(), init_jack_data(), ast_frame_subclass::integer, jack_data_alloc(), queue_voice_frame(), jack_data::stop, and ast_frame::subclass.
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 if (ast_waitfor(chan, -1) < 0) { 00772 break; 00773 } 00774 00775 f = ast_read(chan); 00776 if (!f) { 00777 jack_data->stop = 1; 00778 continue; 00779 } 00780 00781 switch (f->frametype) { 00782 case AST_FRAME_CONTROL: 00783 if (f->subclass.integer == AST_CONTROL_HANGUP) 00784 jack_data->stop = 1; 00785 break; 00786 case AST_FRAME_VOICE: 00787 queue_voice_frame(jack_data, f); 00788 default: 00789 break; 00790 } 00791 00792 ast_frfree(f); 00793 00794 handle_jack_audio(chan, jack_data, NULL); 00795 } 00796 00797 jack_data = destroy_jack_data(jack_data); 00798 00799 return 0; 00800 }
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 814 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(), ast_frame_subclass::codec, ast_datastore::data, ast_frame::frametype, handle_jack_audio(), LOG_ERROR, LOG_WARNING, queue_voice_frame(), ast_audiohook::status, and ast_frame::subclass.
Referenced by enable_jack_hook().
00816 { 00817 struct ast_datastore *datastore; 00818 struct jack_data *jack_data; 00819 00820 if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE) 00821 return 0; 00822 00823 if (direction != AST_AUDIOHOOK_DIRECTION_READ) 00824 return 0; 00825 00826 if (frame->frametype != AST_FRAME_VOICE) 00827 return 0; 00828 00829 if (frame->subclass.codec != AST_FORMAT_SLINEAR) { 00830 ast_log(LOG_WARNING, "Expected frame in SLINEAR for the audiohook, but got format %s\n", 00831 ast_getformatname(frame->subclass.codec)); 00832 return 0; 00833 } 00834 00835 ast_channel_lock(chan); 00836 00837 if (!(datastore = ast_channel_datastore_find(chan, &jack_hook_ds_info, NULL))) { 00838 ast_log(LOG_ERROR, "JACK_HOOK datastore not found for '%s'\n", chan->name); 00839 ast_channel_unlock(chan); 00840 return -1; 00841 } 00842 00843 jack_data = datastore->data; 00844 00845 queue_voice_frame(jack_data, frame); 00846 00847 handle_jack_audio(chan, jack_data, frame); 00848 00849 ast_channel_unlock(chan); 00850 00851 return 0; 00852 }
static void jack_hook_ds_destroy | ( | void * | data | ) | [static] |
Definition at line 802 of file app_jack.c.
References destroy_jack_data().
00803 { 00804 struct jack_data *jack_data = data; 00805 00806 destroy_jack_data(jack_data); 00807 }
static int jack_hook_write | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | data, | |||
const char * | value | |||
) | [static] |
Definition at line 949 of file app_jack.c.
References ast_log(), disable_jack_hook(), enable_jack_hook(), LOG_ERROR, and LOG_WARNING.
00951 { 00952 int res; 00953 00954 if (!chan) { 00955 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd); 00956 return -1; 00957 } 00958 00959 if (!strcasecmp(value, "on")) 00960 res = enable_jack_hook(chan, data); 00961 else if (!strcasecmp(value, "off")) 00962 res = disable_jack_hook(chan); 00963 else { 00964 ast_log(LOG_ERROR, "'%s' is not a valid value for JACK_HOOK()\n", value); 00965 res = -1; 00966 } 00967 00968 return res; 00969 }
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 1017 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().
01018 { 01019 if (ast_register_application_xml(jack_app, jack_exec)) { 01020 return AST_MODULE_LOAD_DECLINE; 01021 } 01022 01023 if (ast_custom_function_register(&jack_hook_function)) { 01024 ast_unregister_application(jack_app); 01025 return AST_MODULE_LOAD_DECLINE; 01026 } 01027 01028 return AST_MODULE_LOAD_SUCCESS; 01029 }
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(), 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().
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 1007 of file app_jack.c.
References ast_custom_function_unregister(), and ast_unregister_application().
01008 { 01009 int res; 01010 01011 res = ast_unregister_application(jack_app); 01012 res |= ast_custom_function_unregister(&jack_hook_function); 01013 01014 return res; 01015 }
const char jack_app[] = "JACK" [static] |
Definition at line 117 of file app_jack.c.
struct ast_datastore_info jack_hook_ds_info [static] |
{ .type = "JACK_HOOK", .destroy = jack_hook_ds_destroy, }
Definition at line 809 of file app_jack.c.
struct ast_custom_function jack_hook_function [static] |
Definition at line 971 of file app_jack.c.
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 __ast_pbx_run(), __iax2_show_peers(), _child_handler(), _sip_show_peer(), _sip_show_peers_one(), 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_LIST_HEAD(), ast_safe_system(), ast_srtp_change_source(), build_dialplan_useage_map(), 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(), readexten_exec(), realtime_ldap_status(), redirecting_read(), redirecting_write(), ring_entry(), run_ras(), sendtext_exec(), sendurl_exec(), shaun_of_the_dead(), show_entry_history(), 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_required_respheader(), add_subscribe_event(), add_timeval_ie(), add_user_extension(), alloc_event(), 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(), ast_cc_agent_set_interfaces_chanvar(), ast_event_subscribe(), ast_func_read(), ast_hashtab_hash_string(), ast_hashtab_hash_string_nocase(), ast_hashtab_hash_string_sax(), ast_include_rename(), ast_set_cc_interfaces_chanvar(), ast_sockaddr_stringify_fmt(), build_user_routes(), cc_extension_monitor_init(), cc_generic_agent_start_monitoring(), custom_log(), dial_handle_playtones(), do_magic_pickup(), find_realtime(), frame_trace_helper(), function_fieldnum_helper(), function_fieldqty_helper(), handle_cli_core_show_translation(), handle_getvariablefull(), handle_playtones(), handle_tcptls_connection(), hash_string(), iax_parse_ies(), 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(), syslog_log(), transmit_info_with_aoc(), variable_count_cmp_fn(), and yyparse().