#include "asterisk.h"
#include <limits.h>
#include <jack/jack.h>
#include <jack/ringbuffer.h>
#include <libresample.h>
#include "asterisk/module.h"
#include "asterisk/channel.h"
#include "asterisk/strings.h"
#include "asterisk/lock.h"
#include "asterisk/app.h"
#include "asterisk/pbx.h"
#include "asterisk/audiohook.h"
Go to the source code of this file.
Data Structures | |
struct | jack_data |
Defines | |
#define | COMMON_OPTIONS |
Common options between the Jack() app and JACK_HOOK() function. | |
#define | RESAMPLE_QUALITY 1 |
#define | RINGBUFFER_SIZE 16384 |
Enumerations | |
enum | { OPT_SERVER_NAME = (1 << 0), OPT_INPUT_PORT = (1 << 1), OPT_OUTPUT_PORT = (1 << 2), OPT_NOSTART_SERVER = (1 << 3), OPT_CLIENT_NAME = (1 << 4) } |
enum | { OPT_ARG_SERVER_NAME, OPT_ARG_INPUT_PORT, OPT_ARG_OUTPUT_PORT, OPT_ARG_CLIENT_NAME, OPT_ARG_ARRAY_SIZE } |
Functions | |
static void | __reg_module (void) |
static void | __unreg_module (void) |
static int | alloc_resampler (struct jack_data *jack_data, int input) |
static struct jack_data * | destroy_jack_data (struct jack_data *jack_data) |
static int | disable_jack_hook (struct ast_channel *chan) |
static int | enable_jack_hook (struct ast_channel *chan, char *data) |
static void | handle_input (void *buf, jack_nframes_t nframes, struct jack_data *jack_data) |
Handle jack input port. | |
static void | handle_jack_audio (struct ast_channel *chan, struct jack_data *jack_data, struct ast_frame *out_frame) |
handle jack audio | |
static int | handle_options (struct jack_data *jack_data, const char *__options_str) |
static void | handle_output (void *buf, jack_nframes_t nframes, struct jack_data *jack_data) |
Handle jack output port. | |
static int | init_jack_data (struct ast_channel *chan, struct jack_data *jack_data) |
static struct jack_data * | jack_data_alloc (void) |
static int | jack_exec (struct ast_channel *chan, void *data) |
static int | jack_hook_callback (struct ast_audiohook *audiohook, struct ast_channel *chan, struct ast_frame *frame, enum ast_audiohook_direction direction) |
static void | jack_hook_ds_destroy (void *data) |
static int | jack_hook_write (struct ast_channel *chan, const char *cmd, char *data, const char *value) |
static int | jack_process (jack_nframes_t nframes, void *arg) |
static void | jack_shutdown (void *arg) |
static const char * | jack_status_to_str (jack_status_t status) |
static int | load_module (void) |
static void | log_jack_status (const char *prefix, jack_status_t status) |
static int | queue_voice_frame (struct jack_data *jack_data, struct ast_frame *f) |
static int | unload_module (void) |
Variables | |
static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "JACK Interface" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, } |
static struct ast_module_info * | ast_module_info = &__mod_info |
static char * | jack_app = "JACK" |
static char * | jack_desc |
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 [] |
static char * | jack_synopsis |
$ 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 620 of file app_jack.c.
00620 { 00621 OPT_SERVER_NAME = (1 << 0), 00622 OPT_INPUT_PORT = (1 << 1), 00623 OPT_OUTPUT_PORT = (1 << 2), 00624 OPT_NOSTART_SERVER = (1 << 3), 00625 OPT_CLIENT_NAME = (1 << 4), 00626 };
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 628 of file app_jack.c.
00628 { 00629 OPT_ARG_SERVER_NAME, 00630 OPT_ARG_INPUT_PORT, 00631 OPT_ARG_OUTPUT_PORT, 00632 OPT_ARG_CLIENT_NAME, 00633 00634 /* Must be the last element */ 00635 OPT_ARG_ARRAY_SIZE, 00636 };
static void __reg_module | ( | void | ) | [static] |
Definition at line 997 of file app_jack.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 997 of file app_jack.c.
static int alloc_resampler | ( | struct jack_data * | jack_data, | |
int | input | |||
) | [static] |
Definition at line 160 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().
00161 { 00162 double from_srate, to_srate, jack_srate; 00163 void **resampler; 00164 double *resample_factor; 00165 00166 if (input && jack_data->input_resampler) 00167 return 0; 00168 00169 if (!input && jack_data->output_resampler) 00170 return 0; 00171 00172 jack_srate = jack_get_sample_rate(jack_data->client); 00173 00174 /* XXX Hard coded 8 kHz */ 00175 00176 to_srate = input ? 8000.0 : jack_srate; 00177 from_srate = input ? jack_srate : 8000.0; 00178 00179 resample_factor = input ? &jack_data->input_resample_factor : 00180 &jack_data->output_resample_factor; 00181 00182 if (from_srate == to_srate) { 00183 /* Awesome! The jack sample rate is the same as ours. 00184 * Resampling isn't needed. */ 00185 *resample_factor = 1.0; 00186 return 0; 00187 } 00188 00189 *resample_factor = to_srate / from_srate; 00190 00191 resampler = input ? &jack_data->input_resampler : 00192 &jack_data->output_resampler; 00193 00194 if (!(*resampler = resample_open(RESAMPLE_QUALITY, 00195 *resample_factor, *resample_factor))) { 00196 ast_log(LOG_ERROR, "Failed to open %s resampler\n", 00197 input ? "input" : "output"); 00198 return -1; 00199 } 00200 00201 return 0; 00202 }
Definition at line 312 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().
00313 { 00314 if (jack_data->input_port) { 00315 jack_port_unregister(jack_data->client, jack_data->input_port); 00316 jack_data->input_port = NULL; 00317 } 00318 00319 if (jack_data->output_port) { 00320 jack_port_unregister(jack_data->client, jack_data->output_port); 00321 jack_data->output_port = NULL; 00322 } 00323 00324 if (jack_data->client) { 00325 jack_client_close(jack_data->client); 00326 jack_data->client = NULL; 00327 } 00328 00329 if (jack_data->input_rb) { 00330 jack_ringbuffer_free(jack_data->input_rb); 00331 jack_data->input_rb = NULL; 00332 } 00333 00334 if (jack_data->output_rb) { 00335 jack_ringbuffer_free(jack_data->output_rb); 00336 jack_data->output_rb = NULL; 00337 } 00338 00339 if (jack_data->output_resampler) { 00340 resample_close(jack_data->output_resampler); 00341 jack_data->output_resampler = NULL; 00342 } 00343 00344 if (jack_data->input_resampler) { 00345 resample_close(jack_data->input_resampler); 00346 jack_data->input_resampler = NULL; 00347 } 00348 00349 if (jack_data->has_audiohook) 00350 ast_audiohook_destroy(&jack_data->audiohook); 00351 00352 ast_string_field_free_memory(jack_data); 00353 00354 ast_free(jack_data); 00355 00356 return NULL; 00357 }
static int disable_jack_hook | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 892 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, chan, ast_datastore::data, jack_hook_ds_info, and LOG_WARNING.
Referenced by jack_hook_write().
00893 { 00894 struct ast_datastore *datastore; 00895 struct jack_data *jack_data; 00896 00897 ast_channel_lock(chan); 00898 00899 if (!(datastore = ast_channel_datastore_find(chan, &jack_hook_ds_info, NULL))) { 00900 ast_channel_unlock(chan); 00901 ast_log(LOG_WARNING, "No JACK_HOOK found to disable\n"); 00902 return -1; 00903 } 00904 00905 ast_channel_datastore_remove(chan, datastore); 00906 00907 jack_data = datastore->data; 00908 ast_audiohook_detach(&jack_data->audiohook); 00909 00910 /* Keep the channel locked while we destroy the datastore, so that we can 00911 * ensure that all of the jack stuff is stopped just in case another frame 00912 * tries to come through the audiohook callback. */ 00913 ast_datastore_free(datastore); 00914 00915 ast_channel_unlock(chan); 00916 00917 return 0; 00918 }
static int enable_jack_hook | ( | struct ast_channel * | chan, | |
char * | data | |||
) | [static] |
Definition at line 831 of file app_jack.c.
References AST_APP_ARG, ast_audiohook_attach(), ast_audiohook_init(), AST_AUDIOHOOK_TYPE_MANIPULATE, ast_channel_datastore_add(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_datastore_alloc(), AST_DECLARE_APP_ARGS, ast_log(), AST_STANDARD_APP_ARGS, ast_strlen_zero(), jack_data::audiohook, chan, 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().
00832 { 00833 struct ast_datastore *datastore; 00834 struct jack_data *jack_data = NULL; 00835 AST_DECLARE_APP_ARGS(args, 00836 AST_APP_ARG(mode); 00837 AST_APP_ARG(options); 00838 ); 00839 00840 AST_STANDARD_APP_ARGS(args, data); 00841 00842 ast_channel_lock(chan); 00843 00844 if ((datastore = ast_channel_datastore_find(chan, &jack_hook_ds_info, NULL))) { 00845 ast_log(LOG_ERROR, "JACK_HOOK already enabled for '%s'\n", chan->name); 00846 goto return_error; 00847 } 00848 00849 if (ast_strlen_zero(args.mode) || strcasecmp(args.mode, "manipulate")) { 00850 ast_log(LOG_ERROR, "'%s' is not a supported mode. Only manipulate is supported.\n", 00851 S_OR(args.mode, "<none>")); 00852 goto return_error; 00853 } 00854 00855 if (!(jack_data = jack_data_alloc())) 00856 goto return_error; 00857 00858 if (!ast_strlen_zero(args.options) && handle_options(jack_data, args.options)) 00859 goto return_error; 00860 00861 if (init_jack_data(chan, jack_data)) 00862 goto return_error; 00863 00864 if (!(datastore = ast_datastore_alloc(&jack_hook_ds_info, NULL))) 00865 goto return_error; 00866 00867 jack_data->has_audiohook = 1; 00868 ast_audiohook_init(&jack_data->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "JACK_HOOK"); 00869 jack_data->audiohook.manipulate_callback = jack_hook_callback; 00870 00871 datastore->data = jack_data; 00872 00873 if (ast_audiohook_attach(chan, &jack_data->audiohook)) 00874 goto return_error; 00875 00876 if (ast_channel_datastore_add(chan, datastore)) 00877 goto return_error; 00878 00879 ast_channel_unlock(chan); 00880 00881 return 0; 00882 00883 return_error: 00884 ast_channel_unlock(chan); 00885 00886 if (jack_data) 00887 destroy_jack_data(jack_data); 00888 00889 return -1; 00890 }
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 210 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().
00212 { 00213 short s_buf[nframes]; 00214 float *in_buf = buf; 00215 size_t res; 00216 int i; 00217 size_t write_len = sizeof(s_buf); 00218 00219 if (jack_data->input_resampler) { 00220 int total_in_buf_used = 0; 00221 int total_out_buf_used = 0; 00222 float f_buf[nframes + 1]; 00223 00224 memset(f_buf, 0, sizeof(f_buf)); 00225 00226 while (total_in_buf_used < nframes) { 00227 int in_buf_used; 00228 int out_buf_used; 00229 00230 out_buf_used = resample_process(jack_data->input_resampler, 00231 jack_data->input_resample_factor, 00232 &in_buf[total_in_buf_used], nframes - total_in_buf_used, 00233 0, &in_buf_used, 00234 &f_buf[total_out_buf_used], ARRAY_LEN(f_buf) - total_out_buf_used); 00235 00236 if (out_buf_used < 0) 00237 break; 00238 00239 total_out_buf_used += out_buf_used; 00240 total_in_buf_used += in_buf_used; 00241 00242 if (total_out_buf_used == ARRAY_LEN(f_buf)) { 00243 ast_log(LOG_ERROR, "Output buffer filled ... need to increase its size, " 00244 "nframes '%d', total_out_buf_used '%d'\n", nframes, total_out_buf_used); 00245 break; 00246 } 00247 } 00248 00249 for (i = 0; i < total_out_buf_used; i++) 00250 s_buf[i] = f_buf[i] * (SHRT_MAX / 1.0); 00251 00252 write_len = total_out_buf_used * sizeof(int16_t); 00253 } else { 00254 /* No resampling needed */ 00255 00256 for (i = 0; i < nframes; i++) 00257 s_buf[i] = in_buf[i] * (SHRT_MAX / 1.0); 00258 } 00259 00260 res = jack_ringbuffer_write(jack_data->input_rb, (const char *) s_buf, write_len); 00261 if (res != write_len) { 00262 ast_debug(2, "Tried to write %d bytes to the ringbuffer, but only wrote %d\n", 00263 (int) sizeof(s_buf), (int) res); 00264 } 00265 }
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 572 of file app_jack.c.
References ARRAY_LEN, ast_debug, AST_FORMAT_SLINEAR, AST_FRAME_VOICE, ast_log(), ast_write(), buf, chan, ast_frame::data, ast_frame::datalen, f, jack_data::input_rb, LOG_ERROR, ast_frame::ptr, and ast_frame::samples.
Referenced by jack_hook_callback().
00574 { 00575 short buf[160]; 00576 struct ast_frame f = { 00577 .frametype = AST_FRAME_VOICE, 00578 .subclass = AST_FORMAT_SLINEAR, 00579 .src = "JACK", 00580 .data.ptr = buf, 00581 .datalen = sizeof(buf), 00582 .samples = ARRAY_LEN(buf), 00583 }; 00584 00585 for (;;) { 00586 size_t res, read_len; 00587 char *read_buf; 00588 00589 read_len = out_frame ? out_frame->datalen : sizeof(buf); 00590 read_buf = out_frame ? out_frame->data.ptr : buf; 00591 00592 res = jack_ringbuffer_read_space(jack_data->input_rb); 00593 00594 if (res < read_len) { 00595 /* Not enough data ready for another frame, move on ... */ 00596 if (out_frame) { 00597 ast_debug(1, "Sending an empty frame for the JACK_HOOK\n"); 00598 memset(out_frame->data.ptr, 0, out_frame->datalen); 00599 } 00600 break; 00601 } 00602 00603 res = jack_ringbuffer_read(jack_data->input_rb, (char *) read_buf, read_len); 00604 00605 if (res < read_len) { 00606 ast_log(LOG_ERROR, "Error reading from ringbuffer, even though it said there was enough data\n"); 00607 break; 00608 } 00609 00610 if (out_frame) { 00611 /* If an output frame was provided, then we just want to fill up the 00612 * buffer in that frame and return. */ 00613 break; 00614 } 00615 00616 ast_write(chan, &f); 00617 } 00618 }
static int handle_options | ( | struct jack_data * | jack_data, | |
const char * | __options_str | |||
) | [static] |
Definition at line 664 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, OPT_SERVER_NAME, and option_args.
Referenced by enable_jack_hook(), and jack_exec().
00665 { 00666 struct ast_flags options = { 0, }; 00667 char *option_args[OPT_ARG_ARRAY_SIZE]; 00668 char *options_str; 00669 00670 options_str = ast_strdupa(__options_str); 00671 00672 ast_app_parse_options(jack_exec_options, &options, option_args, options_str); 00673 00674 if (ast_test_flag(&options, OPT_SERVER_NAME)) { 00675 if (!ast_strlen_zero(option_args[OPT_ARG_SERVER_NAME])) 00676 ast_string_field_set(jack_data, server_name, option_args[OPT_ARG_SERVER_NAME]); 00677 else { 00678 ast_log(LOG_ERROR, "A server name must be provided with the s() option\n"); 00679 return -1; 00680 } 00681 } 00682 00683 if (ast_test_flag(&options, OPT_CLIENT_NAME)) { 00684 if (!ast_strlen_zero(option_args[OPT_ARG_CLIENT_NAME])) 00685 ast_string_field_set(jack_data, client_name, option_args[OPT_ARG_CLIENT_NAME]); 00686 else { 00687 ast_log(LOG_ERROR, "A client name must be provided with the c() option\n"); 00688 return -1; 00689 } 00690 } 00691 00692 if (ast_test_flag(&options, OPT_INPUT_PORT)) { 00693 if (!ast_strlen_zero(option_args[OPT_ARG_INPUT_PORT])) 00694 ast_string_field_set(jack_data, connect_input_port, option_args[OPT_ARG_INPUT_PORT]); 00695 else { 00696 ast_log(LOG_ERROR, "A name must be provided with the i() option\n"); 00697 return -1; 00698 } 00699 } 00700 00701 if (ast_test_flag(&options, OPT_OUTPUT_PORT)) { 00702 if (!ast_strlen_zero(option_args[OPT_ARG_OUTPUT_PORT])) 00703 ast_string_field_set(jack_data, connect_output_port, option_args[OPT_ARG_OUTPUT_PORT]); 00704 else { 00705 ast_log(LOG_ERROR, "A name must be provided with the o() option\n"); 00706 return -1; 00707 } 00708 } 00709 00710 jack_data->no_start_server = ast_test_flag(&options, OPT_NOSTART_SERVER) ? 1 : 0; 00711 00712 return 0; 00713 }
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 273 of file app_jack.c.
References ast_debug, len(), and jack_data::output_rb.
Referenced by jack_process().
00275 { 00276 size_t res, len; 00277 00278 len = nframes * sizeof(float); 00279 00280 res = jack_ringbuffer_read(jack_data->output_rb, buf, len); 00281 00282 if (len != res) { 00283 ast_debug(2, "Wanted %d bytes to send to the output port, " 00284 "but only got %d\n", (int) len, (int) res); 00285 } 00286 }
static int init_jack_data | ( | struct ast_channel * | chan, | |
struct jack_data * | jack_data | |||
) | [static] |
Definition at line 359 of file app_jack.c.
References ast_channel_lock, ast_channel_unlock, ast_debug, ast_log(), ast_strdupa, ast_strlen_zero(), chan, 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().
00360 { 00361 const char *client_name; 00362 jack_status_t status = 0; 00363 jack_options_t jack_options = JackNullOption; 00364 00365 if (!ast_strlen_zero(jack_data->client_name)) { 00366 client_name = jack_data->client_name; 00367 } else { 00368 ast_channel_lock(chan); 00369 client_name = ast_strdupa(chan->name); 00370 ast_channel_unlock(chan); 00371 } 00372 00373 if (!(jack_data->output_rb = jack_ringbuffer_create(RINGBUFFER_SIZE))) 00374 return -1; 00375 00376 if (!(jack_data->input_rb = jack_ringbuffer_create(RINGBUFFER_SIZE))) 00377 return -1; 00378 00379 if (jack_data->no_start_server) 00380 jack_options |= JackNoStartServer; 00381 00382 if (!ast_strlen_zero(jack_data->server_name)) { 00383 jack_options |= JackServerName; 00384 jack_data->client = jack_client_open(client_name, jack_options, &status, 00385 jack_data->server_name); 00386 } else { 00387 jack_data->client = jack_client_open(client_name, jack_options, &status); 00388 } 00389 00390 if (status) 00391 log_jack_status("Client Open Status", status); 00392 00393 if (!jack_data->client) 00394 return -1; 00395 00396 jack_data->input_port = jack_port_register(jack_data->client, "input", 00397 JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput | JackPortIsTerminal, 0); 00398 if (!jack_data->input_port) { 00399 ast_log(LOG_ERROR, "Failed to create input port for jack port\n"); 00400 return -1; 00401 } 00402 00403 jack_data->output_port = jack_port_register(jack_data->client, "output", 00404 JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput | JackPortIsTerminal, 0); 00405 if (!jack_data->output_port) { 00406 ast_log(LOG_ERROR, "Failed to create output port for jack port\n"); 00407 return -1; 00408 } 00409 00410 if (jack_set_process_callback(jack_data->client, jack_process, jack_data)) { 00411 ast_log(LOG_ERROR, "Failed to register process callback with jack client\n"); 00412 return -1; 00413 } 00414 00415 jack_on_shutdown(jack_data->client, jack_shutdown, jack_data); 00416 00417 if (jack_activate(jack_data->client)) { 00418 ast_log(LOG_ERROR, "Unable to activate jack client\n"); 00419 return -1; 00420 } 00421 00422 while (!ast_strlen_zero(jack_data->connect_input_port)) { 00423 const char **ports; 00424 int i; 00425 00426 ports = jack_get_ports(jack_data->client, jack_data->connect_input_port, 00427 NULL, JackPortIsInput); 00428 00429 if (!ports) { 00430 ast_log(LOG_ERROR, "No input port matching '%s' was found\n", 00431 jack_data->connect_input_port); 00432 break; 00433 } 00434 00435 for (i = 0; ports[i]; i++) { 00436 ast_debug(1, "Found port '%s' that matched specified input port '%s'\n", 00437 ports[i], jack_data->connect_input_port); 00438 } 00439 00440 if (jack_connect(jack_data->client, jack_port_name(jack_data->output_port), ports[0])) { 00441 ast_log(LOG_ERROR, "Failed to connect '%s' to '%s'\n", ports[0], 00442 jack_port_name(jack_data->output_port)); 00443 } else { 00444 ast_debug(1, "Connected '%s' to '%s'\n", ports[0], 00445 jack_port_name(jack_data->output_port)); 00446 } 00447 00448 free((void *) ports); 00449 00450 break; 00451 } 00452 00453 while (!ast_strlen_zero(jack_data->connect_output_port)) { 00454 const char **ports; 00455 int i; 00456 00457 ports = jack_get_ports(jack_data->client, jack_data->connect_output_port, 00458 NULL, JackPortIsOutput); 00459 00460 if (!ports) { 00461 ast_log(LOG_ERROR, "No output port matching '%s' was found\n", 00462 jack_data->connect_output_port); 00463 break; 00464 } 00465 00466 for (i = 0; ports[i]; i++) { 00467 ast_debug(1, "Found port '%s' that matched specified output port '%s'\n", 00468 ports[i], jack_data->connect_output_port); 00469 } 00470 00471 if (jack_connect(jack_data->client, ports[0], jack_port_name(jack_data->input_port))) { 00472 ast_log(LOG_ERROR, "Failed to connect '%s' to '%s'\n", ports[0], 00473 jack_port_name(jack_data->input_port)); 00474 } else { 00475 ast_debug(1, "Connected '%s' to '%s'\n", ports[0], 00476 jack_port_name(jack_data->input_port)); 00477 } 00478 00479 free((void *) ports); 00480 00481 break; 00482 } 00483 00484 return 0; 00485 }
static struct jack_data* jack_data_alloc | ( | void | ) | [static] |
Definition at line 646 of file app_jack.c.
References ast_calloc, ast_free, and ast_string_field_init.
Referenced by enable_jack_hook(), and jack_exec().
00647 { 00648 struct jack_data *jack_data; 00649 00650 if (!(jack_data = ast_calloc(1, sizeof(*jack_data)))) 00651 return NULL; 00652 00653 if (ast_string_field_init(jack_data, 32)) { 00654 ast_free(jack_data); 00655 return NULL; 00656 } 00657 00658 return jack_data; 00659 }
static int jack_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 715 of file app_jack.c.
References AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_strlen_zero(), destroy_jack_data(), handle_options(), and jack_data_alloc().
Referenced by load_module().
00716 { 00717 struct jack_data *jack_data; 00718 AST_DECLARE_APP_ARGS(args, 00719 AST_APP_ARG(options); 00720 ); 00721 00722 if (!(jack_data = jack_data_alloc())) 00723 return -1; 00724 00725 args.options = data; 00726 00727 if (!ast_strlen_zero(args.options) && handle_options(jack_data, args.options)) { 00728 destroy_jack_data(jack_data); 00729 return -1; 00730 } 00731 00732 if (init_jack_data(chan, jack_data)) { 00733 destroy_jack_data(jack_data); 00734 return -1; 00735 } 00736 00737 if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) { 00738 destroy_jack_data(jack_data); 00739 return -1; 00740 } 00741 00742 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) { 00743 destroy_jack_data(jack_data); 00744 return -1; 00745 } 00746 00747 while (!jack_data->stop) { 00748 struct ast_frame *f; 00749 00750 ast_waitfor(chan, -1); 00751 00752 f = ast_read(chan); 00753 if (!f) { 00754 jack_data->stop = 1; 00755 continue; 00756 } 00757 00758 switch (f->frametype) { 00759 case AST_FRAME_CONTROL: 00760 if (f->subclass == AST_CONTROL_HANGUP) 00761 jack_data->stop = 1; 00762 break; 00763 case AST_FRAME_VOICE: 00764 queue_voice_frame(jack_data, f); 00765 default: 00766 break; 00767 } 00768 00769 ast_frfree(f); 00770 00771 handle_jack_audio(chan, jack_data, NULL); 00772 } 00773 00774 jack_data = destroy_jack_data(jack_data); 00775 00776 return 0; 00777 }
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 791 of file app_jack.c.
References AST_AUDIOHOOK_DIRECTION_READ, AST_AUDIOHOOK_STATUS_DONE, ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, AST_FORMAT_SLINEAR, AST_FRAME_VOICE, ast_log(), jack_data::audiohook, chan, 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().
00793 { 00794 struct ast_datastore *datastore; 00795 struct jack_data *jack_data; 00796 00797 if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE) 00798 return 0; 00799 00800 if (direction != AST_AUDIOHOOK_DIRECTION_READ) 00801 return 0; 00802 00803 if (frame->frametype != AST_FRAME_VOICE) 00804 return 0; 00805 00806 if (frame->subclass != AST_FORMAT_SLINEAR) { 00807 ast_log(LOG_WARNING, "Expected frame in SLINEAR for the audiohook, but got format %d\n", 00808 frame->subclass); 00809 return 0; 00810 } 00811 00812 ast_channel_lock(chan); 00813 00814 if (!(datastore = ast_channel_datastore_find(chan, &jack_hook_ds_info, NULL))) { 00815 ast_log(LOG_ERROR, "JACK_HOOK datastore not found for '%s'\n", chan->name); 00816 ast_channel_unlock(chan); 00817 return -1; 00818 } 00819 00820 jack_data = datastore->data; 00821 00822 queue_voice_frame(jack_data, frame); 00823 00824 handle_jack_audio(chan, jack_data, frame); 00825 00826 ast_channel_unlock(chan); 00827 00828 return 0; 00829 }
static void jack_hook_ds_destroy | ( | void * | data | ) | [static] |
Definition at line 779 of file app_jack.c.
References destroy_jack_data().
00780 { 00781 struct jack_data *jack_data = data; 00782 00783 destroy_jack_data(jack_data); 00784 }
static int jack_hook_write | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | data, | |||
const char * | value | |||
) | [static] |
Definition at line 920 of file app_jack.c.
References ast_log(), chan, disable_jack_hook(), enable_jack_hook(), and LOG_ERROR.
00922 { 00923 int res; 00924 00925 if (!strcasecmp(value, "on")) 00926 res = enable_jack_hook(chan, data); 00927 else if (!strcasecmp(value, "off")) 00928 res = disable_jack_hook(chan); 00929 else { 00930 ast_log(LOG_ERROR, "'%s' is not a valid value for JACK_HOOK()\n", value); 00931 res = -1; 00932 } 00933 00934 return res; 00935 }
static int jack_process | ( | jack_nframes_t | nframes, | |
void * | arg | |||
) | [static] |
Definition at line 288 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().
00289 { 00290 struct jack_data *jack_data = arg; 00291 void *input_port_buf, *output_port_buf; 00292 00293 if (!jack_data->input_resample_factor) 00294 alloc_resampler(jack_data, 1); 00295 00296 input_port_buf = jack_port_get_buffer(jack_data->input_port, nframes); 00297 handle_input(input_port_buf, nframes, jack_data); 00298 00299 output_port_buf = jack_port_get_buffer(jack_data->output_port, nframes); 00300 handle_output(output_port_buf, nframes, jack_data); 00301 00302 return 0; 00303 }
static void jack_shutdown | ( | void * | arg | ) | [static] |
Definition at line 305 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 129 of file app_jack.c.
References ARRAY_LEN, and jack_status_table.
Referenced by log_jack_status().
00130 { 00131 int i; 00132 00133 for (i = 0; i < ARRAY_LEN(jack_status_table); i++) { 00134 if (jack_status_table[i].status == status) 00135 return jack_status_table[i].str; 00136 } 00137 00138 return "Unknown Error"; 00139 }
static int load_module | ( | void | ) | [static] |
Definition at line 983 of file app_jack.c.
References ast_custom_function_register, AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_register_application, ast_unregister_application(), jack_exec(), and jack_hook_function.
00984 { 00985 if (ast_register_application(jack_app, jack_exec, jack_synopsis, jack_desc)) { 00986 return AST_MODULE_LOAD_DECLINE; 00987 } 00988 00989 if (ast_custom_function_register(&jack_hook_function)) { 00990 ast_unregister_application(jack_app); 00991 return AST_MODULE_LOAD_DECLINE; 00992 } 00993 00994 return AST_MODULE_LOAD_SUCCESS; 00995 }
static void log_jack_status | ( | const char * | prefix, | |
jack_status_t | status | |||
) | [static] |
Definition at line 141 of file app_jack.c.
References ast_log(), ast_str_alloca, ast_str_append(), ast_str_set(), first, jack_status_to_str(), LOG_NOTICE, and str.
Referenced by init_jack_data().
00142 { 00143 struct ast_str *str = ast_str_alloca(512); 00144 int i, first = 0; 00145 00146 for (i = 0; i < (sizeof(status) * 8); i++) { 00147 if (!(status & (1 << i))) 00148 continue; 00149 00150 if (!first) { 00151 ast_str_set(&str, 0, "%s", jack_status_to_str((1 << i))); 00152 first = 1; 00153 } else 00154 ast_str_append(&str, 0, ", %s", jack_status_to_str((1 << i))); 00155 } 00156 00157 ast_log(LOG_NOTICE, "%s: %s\n", prefix, str->str); 00158 }
Definition at line 487 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_hook_callback().
00488 { 00489 float f_buf[f->samples * 8]; 00490 size_t f_buf_used = 0; 00491 int i; 00492 int16_t *s_buf = f->data.ptr; 00493 size_t res; 00494 00495 memset(f_buf, 0, sizeof(f_buf)); 00496 00497 if (!jack_data->output_resample_factor) 00498 alloc_resampler(jack_data, 0); 00499 00500 if (jack_data->output_resampler) { 00501 float in_buf[f->samples]; 00502 int total_in_buf_used = 0; 00503 int total_out_buf_used = 0; 00504 00505 memset(in_buf, 0, sizeof(in_buf)); 00506 00507 for (i = 0; i < f->samples; i++) 00508 in_buf[i] = s_buf[i] * (1.0 / SHRT_MAX); 00509 00510 while (total_in_buf_used < ARRAY_LEN(in_buf)) { 00511 int in_buf_used; 00512 int out_buf_used; 00513 00514 out_buf_used = resample_process(jack_data->output_resampler, 00515 jack_data->output_resample_factor, 00516 &in_buf[total_in_buf_used], ARRAY_LEN(in_buf) - total_in_buf_used, 00517 0, &in_buf_used, 00518 &f_buf[total_out_buf_used], ARRAY_LEN(f_buf) - total_out_buf_used); 00519 00520 if (out_buf_used < 0) 00521 break; 00522 00523 total_out_buf_used += out_buf_used; 00524 total_in_buf_used += in_buf_used; 00525 00526 if (total_out_buf_used == ARRAY_LEN(f_buf)) { 00527 ast_log(LOG_ERROR, "Output buffer filled ... need to increase its size\n"); 00528 break; 00529 } 00530 } 00531 00532 f_buf_used = total_out_buf_used; 00533 if (f_buf_used > ARRAY_LEN(f_buf)) 00534 f_buf_used = ARRAY_LEN(f_buf); 00535 } else { 00536 /* No resampling needed */ 00537 00538 for (i = 0; i < f->samples; i++) 00539 f_buf[i] = s_buf[i] * (1.0 / SHRT_MAX); 00540 00541 f_buf_used = f->samples; 00542 } 00543 00544 res = jack_ringbuffer_write(jack_data->output_rb, (const char *) f_buf, f_buf_used * sizeof(float)); 00545 if (res != (f_buf_used * sizeof(float))) { 00546 ast_debug(2, "Tried to write %d bytes to the ringbuffer, but only wrote %d\n", 00547 (int) (f_buf_used * sizeof(float)), (int) res); 00548 } 00549 00550 return 0; 00551 }
static int unload_module | ( | void | ) | [static] |
Definition at line 973 of file app_jack.c.
References ast_custom_function_unregister(), ast_unregister_application(), and jack_hook_function.
00974 { 00975 int res; 00976 00977 res = ast_unregister_application(jack_app); 00978 res |= ast_custom_function_unregister(&jack_hook_function); 00979 00980 return res; 00981 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "JACK Interface" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, } [static] |
Definition at line 997 of file app_jack.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 997 of file app_jack.c.
char* jack_app = "JACK" [static] |
Definition at line 77 of file app_jack.c.
char* jack_desc [static] |
Definition at line 80 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 786 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().
char* jack_synopsis [static] |
Initial value:
"JACK (Jack Audio Connection Kit) Application"
Definition at line 78 of file app_jack.c.
jack_status_t status |
Definition at line 113 of file app_jack.c.
Referenced by __iax2_show_peers(), _sip_show_peer(), _sip_show_peers(), action_agents(), action_extensionstate(), agent_hangup(), agent_read(), agi_exec_full(), aji_handle_presence(), aji_handle_subscribe(), aji_show_clients(), aji_status_exec(), ast_safe_system(), build_status(), build_timeout(), chanavail_exec(), child_handler(), complete_dpreply(), dundi_show_peers(), function_agent(), handle_cli_iax2_show_peer(), handle_cli_realtime_pgsql_status(), handle_open_receive_channel_ack_message(), httpd_helper_thread(), init_jack_data(), join_queue(), local_hangup(), manager_iax2_show_peer_list(), ospauth_exec(), ospfinished_exec(), osplookup_exec(), ospnext_exec(), parse_status(), queue_exec(), read_exec(), readexten_exec(), realtime_ldap_status(), ring_entry(), rpt(), run_ras(), sendtext_exec(), sendurl_exec(), show_entry_history(), transfer_exec(), wait_for_answer(), and wait_our_turn().
const char* str |
Definition at line 114 of file app_jack.c.
Referenced by _free_port_cfg(), acf_curl_exec(), action_status(), amixer_max(), ast_event_subscribe(), ast_hashtab_hash_string(), ast_hashtab_hash_string_nocase(), ast_hashtab_hash_string_sax(), ast_str_get_encoded_str(), handle_tls_connection(), hash_string(), hid_device_init(), hid_device_mklist(), iax_parse_ies(), init_appendbuf(), jingle_new(), log_jack_status(), match_ie_val(), misdn_cfg_get(), misdn_cfg_get_config_string(), misdn_cfg_get_next_port(), misdn_cfg_get_ports_string(), misdn_cfg_is_group_method(), misdn_cfg_is_port_valid(), process_text_line(), regex(), setamixer(), substitute_escapes(), usb_get_usbdev(), variable_count_cmp_fn(), and WriteMemoryCallback().