#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) } |
enum | { OPT_ARG_SERVER_NAME, OPT_ARG_INPUT_PORT, OPT_ARG_OUTPUT_PORT, 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 = "068e67f60f50dd9ee86464c05884a49d" , .load = load_module, .unload = unload_module, } |
static const 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 }, } |
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 613 of file app_jack.c.
00613 { 00614 OPT_SERVER_NAME = (1 << 0), 00615 OPT_INPUT_PORT = (1 << 1), 00616 OPT_OUTPUT_PORT = (1 << 2), 00617 OPT_NOSTART_SERVER = (1 << 3), 00618 };
anonymous enum |
Definition at line 620 of file app_jack.c.
00620 { 00621 OPT_ARG_SERVER_NAME, 00622 OPT_ARG_INPUT_PORT, 00623 OPT_ARG_OUTPUT_PORT, 00624 /* Must be the last element */ 00625 OPT_ARG_ARRAY_SIZE, 00626 };
static void __reg_module | ( | void | ) | [static] |
Definition at line 976 of file app_jack.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 976 of file app_jack.c.
static int alloc_resampler | ( | struct jack_data * | jack_data, | |
int | input | |||
) | [static] |
Definition at line 157 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().
00158 { 00159 double from_srate, to_srate, jack_srate; 00160 void **resampler; 00161 double *resample_factor; 00162 00163 if (input && jack_data->input_resampler) 00164 return 0; 00165 00166 if (!input && jack_data->output_resampler) 00167 return 0; 00168 00169 jack_srate = jack_get_sample_rate(jack_data->client); 00170 00171 /* XXX Hard coded 8 kHz */ 00172 00173 to_srate = input ? 8000.0 : jack_srate; 00174 from_srate = input ? jack_srate : 8000.0; 00175 00176 resample_factor = input ? &jack_data->input_resample_factor : 00177 &jack_data->output_resample_factor; 00178 00179 if (from_srate == to_srate) { 00180 /* Awesome! The jack sample rate is the same as ours. 00181 * Resampling isn't needed. */ 00182 *resample_factor = 1.0; 00183 return 0; 00184 } 00185 00186 *resample_factor = to_srate / from_srate; 00187 00188 resampler = input ? &jack_data->input_resampler : 00189 &jack_data->output_resampler; 00190 00191 if (!(*resampler = resample_open(RESAMPLE_QUALITY, 00192 *resample_factor, *resample_factor))) { 00193 ast_log(LOG_ERROR, "Failed to open %s resampler\n", 00194 input ? "input" : "output"); 00195 return -1; 00196 } 00197 00198 return 0; 00199 }
Definition at line 309 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().
00310 { 00311 if (jack_data->input_port) { 00312 jack_port_unregister(jack_data->client, jack_data->input_port); 00313 jack_data->input_port = NULL; 00314 } 00315 00316 if (jack_data->output_port) { 00317 jack_port_unregister(jack_data->client, jack_data->output_port); 00318 jack_data->output_port = NULL; 00319 } 00320 00321 if (jack_data->client) { 00322 jack_client_close(jack_data->client); 00323 jack_data->client = NULL; 00324 } 00325 00326 if (jack_data->input_rb) { 00327 jack_ringbuffer_free(jack_data->input_rb); 00328 jack_data->input_rb = NULL; 00329 } 00330 00331 if (jack_data->output_rb) { 00332 jack_ringbuffer_free(jack_data->output_rb); 00333 jack_data->output_rb = NULL; 00334 } 00335 00336 if (jack_data->output_resampler) { 00337 resample_close(jack_data->output_resampler); 00338 jack_data->output_resampler = NULL; 00339 } 00340 00341 if (jack_data->input_resampler) { 00342 resample_close(jack_data->input_resampler); 00343 jack_data->input_resampler = NULL; 00344 } 00345 00346 if (jack_data->has_audiohook) 00347 ast_audiohook_destroy(&jack_data->audiohook); 00348 00349 ast_string_field_free_memory(jack_data); 00350 00351 ast_free(jack_data); 00352 00353 return NULL; 00354 }
static int disable_jack_hook | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 872 of file app_jack.c.
References ast_audiohook_detach(), ast_channel_datastore_find(), ast_channel_datastore_free(), ast_channel_datastore_remove(), ast_channel_lock, ast_channel_unlock, ast_log(), jack_data::audiohook, chan, ast_datastore::data, jack_hook_ds_info, and LOG_WARNING.
Referenced by jack_hook_write().
00873 { 00874 struct ast_datastore *datastore; 00875 struct jack_data *jack_data; 00876 00877 ast_channel_lock(chan); 00878 00879 if (!(datastore = ast_channel_datastore_find(chan, &jack_hook_ds_info, NULL))) { 00880 ast_channel_unlock(chan); 00881 ast_log(LOG_WARNING, "No JACK_HOOK found to disable\n"); 00882 return -1; 00883 } 00884 00885 ast_channel_datastore_remove(chan, datastore); 00886 00887 jack_data = datastore->data; 00888 ast_audiohook_detach(&jack_data->audiohook); 00889 00890 /* Keep the channel locked while we destroy the datastore, so that we can 00891 * ensure that all of the jack stuff is stopped just in case another frame 00892 * tries to come through the audiohook callback. */ 00893 ast_channel_datastore_free(datastore); 00894 00895 ast_channel_unlock(chan); 00896 00897 return 0; 00898 }
static int enable_jack_hook | ( | struct ast_channel * | chan, | |
char * | data | |||
) | [static] |
Definition at line 811 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_alloc(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, 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().
00812 { 00813 struct ast_datastore *datastore; 00814 struct jack_data *jack_data = NULL; 00815 AST_DECLARE_APP_ARGS(args, 00816 AST_APP_ARG(mode); 00817 AST_APP_ARG(options); 00818 ); 00819 00820 AST_STANDARD_APP_ARGS(args, data); 00821 00822 ast_channel_lock(chan); 00823 00824 if ((datastore = ast_channel_datastore_find(chan, &jack_hook_ds_info, NULL))) { 00825 ast_log(LOG_ERROR, "JACK_HOOK already enabled for '%s'\n", chan->name); 00826 goto return_error; 00827 } 00828 00829 if (ast_strlen_zero(args.mode) || strcasecmp(args.mode, "manipulate")) { 00830 ast_log(LOG_ERROR, "'%s' is not a supported mode. Only manipulate is supported.\n", 00831 S_OR(args.mode, "<none>")); 00832 goto return_error; 00833 } 00834 00835 if (!(jack_data = jack_data_alloc())) 00836 goto return_error; 00837 00838 if (!ast_strlen_zero(args.options) && handle_options(jack_data, args.options)) 00839 goto return_error; 00840 00841 if (init_jack_data(chan, jack_data)) 00842 goto return_error; 00843 00844 if (!(datastore = ast_channel_datastore_alloc(&jack_hook_ds_info, NULL))) 00845 goto return_error; 00846 00847 jack_data->has_audiohook = 1; 00848 ast_audiohook_init(&jack_data->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "JACK_HOOK"); 00849 jack_data->audiohook.manipulate_callback = jack_hook_callback; 00850 00851 datastore->data = jack_data; 00852 00853 if (ast_audiohook_attach(chan, &jack_data->audiohook)) 00854 goto return_error; 00855 00856 if (ast_channel_datastore_add(chan, datastore)) 00857 goto return_error; 00858 00859 ast_channel_unlock(chan); 00860 00861 return 0; 00862 00863 return_error: 00864 ast_channel_unlock(chan); 00865 00866 if (jack_data) 00867 destroy_jack_data(jack_data); 00868 00869 return -1; 00870 }
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 207 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().
00209 { 00210 short s_buf[nframes]; 00211 float *in_buf = buf; 00212 size_t res; 00213 int i; 00214 size_t write_len = sizeof(s_buf); 00215 00216 if (jack_data->input_resampler) { 00217 int total_in_buf_used = 0; 00218 int total_out_buf_used = 0; 00219 float f_buf[nframes + 1]; 00220 00221 memset(f_buf, 0, sizeof(f_buf)); 00222 00223 while (total_in_buf_used < nframes) { 00224 int in_buf_used; 00225 int out_buf_used; 00226 00227 out_buf_used = resample_process(jack_data->input_resampler, 00228 jack_data->input_resample_factor, 00229 &in_buf[total_in_buf_used], nframes - total_in_buf_used, 00230 0, &in_buf_used, 00231 &f_buf[total_out_buf_used], ARRAY_LEN(f_buf) - total_out_buf_used); 00232 00233 if (out_buf_used < 0) 00234 break; 00235 00236 total_out_buf_used += out_buf_used; 00237 total_in_buf_used += in_buf_used; 00238 00239 if (total_out_buf_used == ARRAY_LEN(f_buf)) { 00240 ast_log(LOG_ERROR, "Output buffer filled ... need to increase its size, " 00241 "nframes '%d', total_out_buf_used '%d'\n", nframes, total_out_buf_used); 00242 break; 00243 } 00244 } 00245 00246 for (i = 0; i < total_out_buf_used; i++) 00247 s_buf[i] = f_buf[i] * (SHRT_MAX / 1.0); 00248 00249 write_len = total_out_buf_used * sizeof(int16_t); 00250 } else { 00251 /* No resampling needed */ 00252 00253 for (i = 0; i < nframes; i++) 00254 s_buf[i] = in_buf[i] * (SHRT_MAX / 1.0); 00255 } 00256 00257 res = jack_ringbuffer_write(jack_data->input_rb, (const char *) s_buf, write_len); 00258 if (res != write_len) { 00259 ast_debug(2, "Tried to write %d bytes to the ringbuffer, but only wrote %d\n", 00260 (int) sizeof(s_buf), (int) res); 00261 } 00262 }
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 565 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, and ast_frame::samples.
Referenced by jack_hook_callback().
00567 { 00568 short buf[160]; 00569 struct ast_frame f = { 00570 .frametype = AST_FRAME_VOICE, 00571 .subclass = AST_FORMAT_SLINEAR, 00572 .src = "JACK", 00573 .data = buf, 00574 .datalen = sizeof(buf), 00575 .samples = ARRAY_LEN(buf), 00576 }; 00577 00578 for (;;) { 00579 size_t res, read_len; 00580 char *read_buf; 00581 00582 read_len = out_frame ? out_frame->datalen : sizeof(buf); 00583 read_buf = out_frame ? out_frame->data : buf; 00584 00585 res = jack_ringbuffer_read_space(jack_data->input_rb); 00586 00587 if (res < read_len) { 00588 /* Not enough data ready for another frame, move on ... */ 00589 if (out_frame) { 00590 ast_debug(1, "Sending an empty frame for the JACK_HOOK\n"); 00591 memset(out_frame->data, 0, out_frame->datalen); 00592 } 00593 break; 00594 } 00595 00596 res = jack_ringbuffer_read(jack_data->input_rb, (char *) read_buf, read_len); 00597 00598 if (res < read_len) { 00599 ast_log(LOG_ERROR, "Error reading from ringbuffer, even though it said there was enough data\n"); 00600 break; 00601 } 00602 00603 if (out_frame) { 00604 /* If an output frame was provided, then we just want to fill up the 00605 * buffer in that frame and return. */ 00606 break; 00607 } 00608 00609 ast_write(chan, &f); 00610 } 00611 }
static int handle_options | ( | struct jack_data * | jack_data, | |
const char * | __options_str | |||
) | [static] |
Definition at line 653 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_INPUT_PORT, OPT_ARG_OUTPUT_PORT, OPT_ARG_SERVER_NAME, OPT_INPUT_PORT, OPT_NOSTART_SERVER, OPT_OUTPUT_PORT, OPT_SERVER_NAME, and option_args.
Referenced by enable_jack_hook(), and jack_exec().
00654 { 00655 struct ast_flags options = { 0, }; 00656 char *option_args[OPT_ARG_ARRAY_SIZE]; 00657 char *options_str; 00658 00659 options_str = ast_strdupa(__options_str); 00660 00661 ast_app_parse_options(jack_exec_options, &options, option_args, options_str); 00662 00663 if (ast_test_flag(&options, OPT_SERVER_NAME)) { 00664 if (!ast_strlen_zero(option_args[OPT_ARG_SERVER_NAME])) 00665 ast_string_field_set(jack_data, server_name, option_args[OPT_ARG_SERVER_NAME]); 00666 else { 00667 ast_log(LOG_ERROR, "A server name must be provided with the s() option\n"); 00668 return -1; 00669 } 00670 } 00671 00672 if (ast_test_flag(&options, OPT_INPUT_PORT)) { 00673 if (!ast_strlen_zero(option_args[OPT_ARG_INPUT_PORT])) 00674 ast_string_field_set(jack_data, connect_input_port, option_args[OPT_ARG_INPUT_PORT]); 00675 else { 00676 ast_log(LOG_ERROR, "A name must be provided with the i() option\n"); 00677 return -1; 00678 } 00679 } 00680 00681 if (ast_test_flag(&options, OPT_OUTPUT_PORT)) { 00682 if (!ast_strlen_zero(option_args[OPT_ARG_OUTPUT_PORT])) 00683 ast_string_field_set(jack_data, connect_output_port, option_args[OPT_ARG_OUTPUT_PORT]); 00684 else { 00685 ast_log(LOG_ERROR, "A name must be provided with the o() option\n"); 00686 return -1; 00687 } 00688 } 00689 00690 jack_data->no_start_server = ast_test_flag(&options, OPT_NOSTART_SERVER) ? 1 : 0; 00691 00692 return 0; 00693 }
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 270 of file app_jack.c.
References ast_debug, len(), and jack_data::output_rb.
Referenced by jack_process().
00272 { 00273 size_t res, len; 00274 00275 len = nframes * sizeof(float); 00276 00277 res = jack_ringbuffer_read(jack_data->output_rb, buf, len); 00278 00279 if (len != res) { 00280 ast_debug(2, "Wanted %d bytes to send to the output port, " 00281 "but only got %d\n", (int) len, (int) res); 00282 } 00283 }
static int init_jack_data | ( | struct ast_channel * | chan, | |
struct jack_data * | jack_data | |||
) | [static] |
Definition at line 356 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::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().
00357 { 00358 const char *chan_name; 00359 jack_status_t status = 0; 00360 jack_options_t jack_options = JackNullOption; 00361 00362 ast_channel_lock(chan); 00363 chan_name = ast_strdupa(chan->name); 00364 ast_channel_unlock(chan); 00365 00366 if (!(jack_data->output_rb = jack_ringbuffer_create(RINGBUFFER_SIZE))) 00367 return -1; 00368 00369 if (!(jack_data->input_rb = jack_ringbuffer_create(RINGBUFFER_SIZE))) 00370 return -1; 00371 00372 if (jack_data->no_start_server) 00373 jack_options |= JackNoStartServer; 00374 00375 if (!ast_strlen_zero(jack_data->server_name)) { 00376 jack_options |= JackServerName; 00377 jack_data->client = jack_client_open(chan_name, jack_options, &status, 00378 jack_data->server_name); 00379 } else { 00380 jack_data->client = jack_client_open(chan_name, jack_options, &status); 00381 } 00382 00383 if (status) 00384 log_jack_status("Client Open Status", status); 00385 00386 if (!jack_data->client) 00387 return -1; 00388 00389 jack_data->input_port = jack_port_register(jack_data->client, "input", 00390 JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput | JackPortIsTerminal, 0); 00391 if (!jack_data->input_port) { 00392 ast_log(LOG_ERROR, "Failed to create input port for jack port\n"); 00393 return -1; 00394 } 00395 00396 jack_data->output_port = jack_port_register(jack_data->client, "output", 00397 JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput | JackPortIsTerminal, 0); 00398 if (!jack_data->output_port) { 00399 ast_log(LOG_ERROR, "Failed to create output port for jack port\n"); 00400 return -1; 00401 } 00402 00403 if (jack_set_process_callback(jack_data->client, jack_process, jack_data)) { 00404 ast_log(LOG_ERROR, "Failed to register process callback with jack client\n"); 00405 return -1; 00406 } 00407 00408 jack_on_shutdown(jack_data->client, jack_shutdown, jack_data); 00409 00410 if (jack_activate(jack_data->client)) { 00411 ast_log(LOG_ERROR, "Unable to activate jack client\n"); 00412 return -1; 00413 } 00414 00415 while (!ast_strlen_zero(jack_data->connect_input_port)) { 00416 const char **ports; 00417 int i; 00418 00419 ports = jack_get_ports(jack_data->client, jack_data->connect_input_port, 00420 NULL, JackPortIsInput); 00421 00422 if (!ports) { 00423 ast_log(LOG_ERROR, "No input port matching '%s' was found\n", 00424 jack_data->connect_input_port); 00425 break; 00426 } 00427 00428 for (i = 0; ports[i]; i++) { 00429 ast_debug(1, "Found port '%s' that matched specified input port '%s'\n", 00430 ports[i], jack_data->connect_input_port); 00431 } 00432 00433 if (jack_connect(jack_data->client, jack_port_name(jack_data->output_port), ports[0])) { 00434 ast_log(LOG_ERROR, "Failed to connect '%s' to '%s'\n", ports[0], 00435 jack_port_name(jack_data->output_port)); 00436 } else { 00437 ast_debug(1, "Connected '%s' to '%s'\n", ports[0], 00438 jack_port_name(jack_data->output_port)); 00439 } 00440 00441 free((void *) ports); 00442 00443 break; 00444 } 00445 00446 while (!ast_strlen_zero(jack_data->connect_output_port)) { 00447 const char **ports; 00448 int i; 00449 00450 ports = jack_get_ports(jack_data->client, jack_data->connect_output_port, 00451 NULL, JackPortIsOutput); 00452 00453 if (!ports) { 00454 ast_log(LOG_ERROR, "No output port matching '%s' was found\n", 00455 jack_data->connect_output_port); 00456 break; 00457 } 00458 00459 for (i = 0; ports[i]; i++) { 00460 ast_debug(1, "Found port '%s' that matched specified output port '%s'\n", 00461 ports[i], jack_data->connect_output_port); 00462 } 00463 00464 if (jack_connect(jack_data->client, ports[0], jack_port_name(jack_data->input_port))) { 00465 ast_log(LOG_ERROR, "Failed to connect '%s' to '%s'\n", ports[0], 00466 jack_port_name(jack_data->input_port)); 00467 } else { 00468 ast_debug(1, "Connected '%s' to '%s'\n", ports[0], 00469 jack_port_name(jack_data->input_port)); 00470 } 00471 00472 free((void *) ports); 00473 00474 break; 00475 } 00476 00477 return 0; 00478 }
static struct jack_data* jack_data_alloc | ( | void | ) | [static] |
Definition at line 635 of file app_jack.c.
References ast_calloc, ast_free, and ast_string_field_init.
Referenced by enable_jack_hook(), and jack_exec().
00636 { 00637 struct jack_data *jack_data; 00638 00639 if (!(jack_data = ast_calloc(1, sizeof(*jack_data)))) 00640 return NULL; 00641 00642 if (ast_string_field_init(jack_data, 32)) { 00643 ast_free(jack_data); 00644 return NULL; 00645 } 00646 00647 return jack_data; 00648 }
static int jack_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 695 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().
00696 { 00697 struct jack_data *jack_data; 00698 AST_DECLARE_APP_ARGS(args, 00699 AST_APP_ARG(options); 00700 ); 00701 00702 if (!(jack_data = jack_data_alloc())) 00703 return -1; 00704 00705 args.options = data; 00706 00707 if (!ast_strlen_zero(args.options) && handle_options(jack_data, args.options)) { 00708 destroy_jack_data(jack_data); 00709 return -1; 00710 } 00711 00712 if (init_jack_data(chan, jack_data)) { 00713 destroy_jack_data(jack_data); 00714 return -1; 00715 } 00716 00717 if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) { 00718 destroy_jack_data(jack_data); 00719 return -1; 00720 } 00721 00722 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) { 00723 destroy_jack_data(jack_data); 00724 return -1; 00725 } 00726 00727 while (!jack_data->stop) { 00728 struct ast_frame *f; 00729 00730 ast_waitfor(chan, -1); 00731 00732 f = ast_read(chan); 00733 if (!f) { 00734 jack_data->stop = 1; 00735 continue; 00736 } 00737 00738 switch (f->frametype) { 00739 case AST_FRAME_CONTROL: 00740 if (f->subclass == AST_CONTROL_HANGUP) 00741 jack_data->stop = 1; 00742 break; 00743 case AST_FRAME_VOICE: 00744 queue_voice_frame(jack_data, f); 00745 default: 00746 break; 00747 } 00748 00749 ast_frfree(f); 00750 00751 handle_jack_audio(chan, jack_data, NULL); 00752 } 00753 00754 jack_data = destroy_jack_data(jack_data); 00755 00756 return 0; 00757 }
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 771 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().
00773 { 00774 struct ast_datastore *datastore; 00775 struct jack_data *jack_data; 00776 00777 if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE) 00778 return 0; 00779 00780 if (direction != AST_AUDIOHOOK_DIRECTION_READ) 00781 return 0; 00782 00783 if (frame->frametype != AST_FRAME_VOICE) 00784 return 0; 00785 00786 if (frame->subclass != AST_FORMAT_SLINEAR) { 00787 ast_log(LOG_WARNING, "Expected frame in SLINEAR for the audiohook, but got format %d\n", 00788 frame->subclass); 00789 return 0; 00790 } 00791 00792 ast_channel_lock(chan); 00793 00794 if (!(datastore = ast_channel_datastore_find(chan, &jack_hook_ds_info, NULL))) { 00795 ast_log(LOG_ERROR, "JACK_HOOK datastore not found for '%s'\n", chan->name); 00796 ast_channel_unlock(chan); 00797 return -1; 00798 } 00799 00800 jack_data = datastore->data; 00801 00802 queue_voice_frame(jack_data, frame); 00803 00804 handle_jack_audio(chan, jack_data, frame); 00805 00806 ast_channel_unlock(chan); 00807 00808 return 0; 00809 }
static void jack_hook_ds_destroy | ( | void * | data | ) | [static] |
Definition at line 759 of file app_jack.c.
References destroy_jack_data().
00760 { 00761 struct jack_data *jack_data = data; 00762 00763 destroy_jack_data(jack_data); 00764 }
static int jack_hook_write | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | data, | |||
const char * | value | |||
) | [static] |
Definition at line 900 of file app_jack.c.
References ast_log(), chan, disable_jack_hook(), enable_jack_hook(), and LOG_ERROR.
00902 { 00903 int res; 00904 00905 if (!strcasecmp(value, "on")) 00906 res = enable_jack_hook(chan, data); 00907 else if (!strcasecmp(value, "off")) 00908 res = disable_jack_hook(chan); 00909 else { 00910 ast_log(LOG_ERROR, "'%s' is not a valid value for JACK_HOOK()\n", value); 00911 res = -1; 00912 } 00913 00914 return res; 00915 }
static int jack_process | ( | jack_nframes_t | nframes, | |
void * | arg | |||
) | [static] |
Definition at line 285 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().
00286 { 00287 struct jack_data *jack_data = arg; 00288 void *input_port_buf, *output_port_buf; 00289 00290 if (!jack_data->input_resample_factor) 00291 alloc_resampler(jack_data, 1); 00292 00293 input_port_buf = jack_port_get_buffer(jack_data->input_port, nframes); 00294 handle_input(input_port_buf, nframes, jack_data); 00295 00296 output_port_buf = jack_port_get_buffer(jack_data->output_port, nframes); 00297 handle_output(output_port_buf, nframes, jack_data); 00298 00299 return 0; 00300 }
static void jack_shutdown | ( | void * | arg | ) | [static] |
Definition at line 302 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 126 of file app_jack.c.
References ARRAY_LEN, and jack_status_table.
Referenced by log_jack_status().
00127 { 00128 int i; 00129 00130 for (i = 0; i < ARRAY_LEN(jack_status_table); i++) { 00131 if (jack_status_table[i].status == status) 00132 return jack_status_table[i].str; 00133 } 00134 00135 return "Unknown Error"; 00136 }
static int load_module | ( | void | ) | [static] |
Definition at line 963 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.
00964 { 00965 if (ast_register_application(jack_app, jack_exec, jack_synopsis, jack_desc)) 00966 return AST_MODULE_LOAD_DECLINE; 00967 00968 if (ast_custom_function_register(&jack_hook_function)) { 00969 ast_unregister_application(jack_app); 00970 return AST_MODULE_LOAD_DECLINE; 00971 } 00972 00973 return AST_MODULE_LOAD_SUCCESS; 00974 }
static void log_jack_status | ( | const char * | prefix, | |
jack_status_t | status | |||
) | [static] |
Definition at line 138 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().
00139 { 00140 struct ast_str *str = ast_str_alloca(512); 00141 int i, first = 0; 00142 00143 for (i = 0; i < (sizeof(status) * 8); i++) { 00144 if (!(status & (1 << i))) 00145 continue; 00146 00147 if (!first) { 00148 ast_str_set(&str, 0, "%s", jack_status_to_str((1 << i))); 00149 first = 1; 00150 } else 00151 ast_str_append(&str, 0, ", %s", jack_status_to_str((1 << i))); 00152 } 00153 00154 ast_log(LOG_NOTICE, "%s: %s\n", prefix, str->str); 00155 }
Definition at line 480 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().
00481 { 00482 float f_buf[f->samples * 8]; 00483 size_t f_buf_used = 0; 00484 int i; 00485 int16_t *s_buf = f->data; 00486 size_t res; 00487 00488 memset(f_buf, 0, sizeof(f_buf)); 00489 00490 if (!jack_data->output_resample_factor) 00491 alloc_resampler(jack_data, 0); 00492 00493 if (jack_data->output_resampler) { 00494 float in_buf[f->samples]; 00495 int total_in_buf_used = 0; 00496 int total_out_buf_used = 0; 00497 00498 memset(in_buf, 0, sizeof(in_buf)); 00499 00500 for (i = 0; i < f->samples; i++) 00501 in_buf[i] = s_buf[i] * (1.0 / SHRT_MAX); 00502 00503 while (total_in_buf_used < ARRAY_LEN(in_buf)) { 00504 int in_buf_used; 00505 int out_buf_used; 00506 00507 out_buf_used = resample_process(jack_data->output_resampler, 00508 jack_data->output_resample_factor, 00509 &in_buf[total_in_buf_used], ARRAY_LEN(in_buf) - total_in_buf_used, 00510 0, &in_buf_used, 00511 &f_buf[total_out_buf_used], ARRAY_LEN(f_buf) - total_out_buf_used); 00512 00513 if (out_buf_used < 0) 00514 break; 00515 00516 total_out_buf_used += out_buf_used; 00517 total_in_buf_used += in_buf_used; 00518 00519 if (total_out_buf_used == ARRAY_LEN(f_buf)) { 00520 ast_log(LOG_ERROR, "Output buffer filled ... need to increase its size\n"); 00521 break; 00522 } 00523 } 00524 00525 f_buf_used = total_out_buf_used; 00526 if (f_buf_used > ARRAY_LEN(f_buf)) 00527 f_buf_used = ARRAY_LEN(f_buf); 00528 } else { 00529 /* No resampling needed */ 00530 00531 for (i = 0; i < f->samples; i++) 00532 f_buf[i] = s_buf[i] * (1.0 / SHRT_MAX); 00533 00534 f_buf_used = f->samples; 00535 } 00536 00537 res = jack_ringbuffer_write(jack_data->output_rb, (const char *) f_buf, f_buf_used * sizeof(float)); 00538 if (res != (f_buf_used * sizeof(float))) { 00539 ast_debug(2, "Tried to write %d bytes to the ringbuffer, but only wrote %d\n", 00540 (int) (f_buf_used * sizeof(float)), (int) res); 00541 } 00542 00543 return 0; 00544 }
static int unload_module | ( | void | ) | [static] |
Definition at line 953 of file app_jack.c.
References ast_custom_function_unregister(), ast_unregister_application(), and jack_hook_function.
00954 { 00955 int res; 00956 00957 res = ast_unregister_application(jack_app); 00958 res |= ast_custom_function_unregister(&jack_hook_function); 00959 00960 return res; 00961 }
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 = "068e67f60f50dd9ee86464c05884a49d" , .load = load_module, .unload = unload_module, } [static] |
Definition at line 976 of file app_jack.c.
const struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 976 of file app_jack.c.
char* jack_app = "JACK" [static] |
Definition at line 75 of file app_jack.c.
char* jack_desc [static] |
Definition at line 78 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 }, } [static] |
struct ast_datastore_info jack_hook_ds_info [static] |
Initial value:
{ .type = "JACK_HOOK", .destroy = jack_hook_ds_destroy, }
Definition at line 766 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 76 of file app_jack.c.
jack_status_t status |
Definition at line 110 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(), features_alloc(), function_agent(), handle_cli_iax2_show_peer(), handle_cli_realtime_pgsql_status(), handle_open_receive_channel_ack_message(), init_jack_data(), local_hangup(), manager_iax2_show_peer_list(), ospauth_exec(), ospfinished_exec(), osplookup_exec(), ospnext_exec(), parse_status(), read_exec(), readexten_exec(), realtime_ldap_status(), ring_entry(), run_ras(), sendtext_exec(), sendurl_exec(), show_entry_history(), transfer_exec(), and wait_for_answer().
const char* str |
Definition at line 111 of file app_jack.c.
Referenced by _free_port_cfg(), amixer_max(), ast_event_get_cached(), ast_hashtab_hash_string(), ast_hashtab_hash_string_nocase(), ast_hashtab_hash_string_sax(), ast_make_file_from_fd(), ast_str_get_encoded_str(), hash_string(), iax_parse_ies(), jingle_new(), load_rpt_vars(), log_jack_status(), 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(), regex(), send_link_dtmf(), setamixer(), substitute_escapes(), and variable_count_cmp_fn().