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 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 __MODULE_INFO_SECTION | __mod_info = { __MODULE_INFO_GLOBALS .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "JACK Interface" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, } |
static struct ast_module_info * | ast_module_info = &__mod_info |
static char * | jack_app = "JACK" |
static struct ast_app_option | jack_exec_options [128] = { [ 's' ] = { .flag = OPT_SERVER_NAME , .arg_index = OPT_ARG_SERVER_NAME + 1 }, [ 'i' ] = { .flag = OPT_INPUT_PORT , .arg_index = OPT_ARG_INPUT_PORT + 1 }, [ 'o' ] = { .flag = OPT_OUTPUT_PORT , .arg_index = OPT_ARG_OUTPUT_PORT + 1 }, [ 'n' ] = { .flag = OPT_NOSTART_SERVER }, [ 'c' ] = { .flag = OPT_CLIENT_NAME , .arg_index = OPT_ARG_CLIENT_NAME + 1 }, } |
static struct ast_datastore_info | jack_hook_ds_info |
static struct ast_custom_function | jack_hook_function |
struct { | |
jack_status_t status | |
const char * str | |
} | jack_status_table [] |
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 66 of file app_jack.c.
#define RESAMPLE_QUALITY 1 |
Definition at line 61 of file app_jack.c.
Referenced by alloc_resampler().
#define RINGBUFFER_SIZE 16384 |
Definition at line 63 of file app_jack.c.
Referenced by init_jack_data().
anonymous enum |
Definition at line 648 of file app_jack.c.
{ 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), };
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 656 of file app_jack.c.
{ OPT_ARG_SERVER_NAME, OPT_ARG_INPUT_PORT, OPT_ARG_OUTPUT_PORT, OPT_ARG_CLIENT_NAME, /* Must be the last element */ OPT_ARG_ARRAY_SIZE, };
static void __reg_module | ( | void | ) | [static] |
Definition at line 1025 of file app_jack.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 1025 of file app_jack.c.
static int alloc_resampler | ( | struct jack_data * | jack_data, |
int | input | ||
) | [static] |
Definition at line 188 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().
{ double from_srate, to_srate, jack_srate; void **resampler; double *resample_factor; if (input && jack_data->input_resampler) return 0; if (!input && jack_data->output_resampler) return 0; jack_srate = jack_get_sample_rate(jack_data->client); /* XXX Hard coded 8 kHz */ to_srate = input ? 8000.0 : jack_srate; from_srate = input ? jack_srate : 8000.0; resample_factor = input ? &jack_data->input_resample_factor : &jack_data->output_resample_factor; if (from_srate == to_srate) { /* Awesome! The jack sample rate is the same as ours. * Resampling isn't needed. */ *resample_factor = 1.0; return 0; } *resample_factor = to_srate / from_srate; resampler = input ? &jack_data->input_resampler : &jack_data->output_resampler; if (!(*resampler = resample_open(RESAMPLE_QUALITY, *resample_factor, *resample_factor))) { ast_log(LOG_ERROR, "Failed to open %s resampler\n", input ? "input" : "output"); return -1; } return 0; }
Definition at line 340 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().
{ if (jack_data->input_port) { jack_port_unregister(jack_data->client, jack_data->input_port); jack_data->input_port = NULL; } if (jack_data->output_port) { jack_port_unregister(jack_data->client, jack_data->output_port); jack_data->output_port = NULL; } if (jack_data->client) { jack_client_close(jack_data->client); jack_data->client = NULL; } if (jack_data->input_rb) { jack_ringbuffer_free(jack_data->input_rb); jack_data->input_rb = NULL; } if (jack_data->output_rb) { jack_ringbuffer_free(jack_data->output_rb); jack_data->output_rb = NULL; } if (jack_data->output_resampler) { resample_close(jack_data->output_resampler); jack_data->output_resampler = NULL; } if (jack_data->input_resampler) { resample_close(jack_data->input_resampler); jack_data->input_resampler = NULL; } if (jack_data->has_audiohook) ast_audiohook_destroy(&jack_data->audiohook); ast_string_field_free_memory(jack_data); ast_free(jack_data); return NULL; }
static int disable_jack_hook | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 920 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().
{ struct ast_datastore *datastore; struct jack_data *jack_data; ast_channel_lock(chan); if (!(datastore = ast_channel_datastore_find(chan, &jack_hook_ds_info, NULL))) { ast_channel_unlock(chan); ast_log(LOG_WARNING, "No JACK_HOOK found to disable\n"); return -1; } ast_channel_datastore_remove(chan, datastore); jack_data = datastore->data; ast_audiohook_detach(&jack_data->audiohook); /* Keep the channel locked while we destroy the datastore, so that we can * ensure that all of the jack stuff is stopped just in case another frame * tries to come through the audiohook callback. */ ast_datastore_free(datastore); ast_channel_unlock(chan); return 0; }
static int enable_jack_hook | ( | struct ast_channel * | chan, |
char * | data | ||
) | [static] |
Definition at line 859 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, 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, ast_channel::name, and S_OR.
Referenced by jack_hook_write().
{ struct ast_datastore *datastore; struct jack_data *jack_data = NULL; AST_DECLARE_APP_ARGS(args, AST_APP_ARG(mode); AST_APP_ARG(options); ); AST_STANDARD_APP_ARGS(args, data); ast_channel_lock(chan); if ((datastore = ast_channel_datastore_find(chan, &jack_hook_ds_info, NULL))) { ast_log(LOG_ERROR, "JACK_HOOK already enabled for '%s'\n", chan->name); goto return_error; } if (ast_strlen_zero(args.mode) || strcasecmp(args.mode, "manipulate")) { ast_log(LOG_ERROR, "'%s' is not a supported mode. Only manipulate is supported.\n", S_OR(args.mode, "<none>")); goto return_error; } if (!(jack_data = jack_data_alloc())) goto return_error; if (!ast_strlen_zero(args.options) && handle_options(jack_data, args.options)) goto return_error; if (init_jack_data(chan, jack_data)) goto return_error; if (!(datastore = ast_datastore_alloc(&jack_hook_ds_info, NULL))) goto return_error; jack_data->has_audiohook = 1; ast_audiohook_init(&jack_data->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "JACK_HOOK"); jack_data->audiohook.manipulate_callback = jack_hook_callback; datastore->data = jack_data; if (ast_audiohook_attach(chan, &jack_data->audiohook)) goto return_error; if (ast_channel_datastore_add(chan, datastore)) goto return_error; ast_channel_unlock(chan); return 0; return_error: ast_channel_unlock(chan); if (jack_data) destroy_jack_data(jack_data); return -1; }
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 238 of file app_jack.c.
References ARRAY_LEN, ast_debug, ast_log(), buf, jack_data::input_rb, jack_data::input_resample_factor, jack_data::input_resampler, and LOG_ERROR.
Referenced by jack_process().
{ short s_buf[nframes]; float *in_buf = buf; size_t res; int i; size_t write_len = sizeof(s_buf); if (jack_data->input_resampler) { int total_in_buf_used = 0; int total_out_buf_used = 0; float f_buf[nframes + 1]; memset(f_buf, 0, sizeof(f_buf)); while (total_in_buf_used < nframes) { int in_buf_used; int out_buf_used; out_buf_used = resample_process(jack_data->input_resampler, jack_data->input_resample_factor, &in_buf[total_in_buf_used], nframes - total_in_buf_used, 0, &in_buf_used, &f_buf[total_out_buf_used], ARRAY_LEN(f_buf) - total_out_buf_used); if (out_buf_used < 0) break; total_out_buf_used += out_buf_used; total_in_buf_used += in_buf_used; if (total_out_buf_used == ARRAY_LEN(f_buf)) { ast_log(LOG_ERROR, "Output buffer filled ... need to increase its size, " "nframes '%d', total_out_buf_used '%d'\n", nframes, total_out_buf_used); break; } } for (i = 0; i < total_out_buf_used; i++) s_buf[i] = f_buf[i] * (SHRT_MAX / 1.0); write_len = total_out_buf_used * sizeof(int16_t); } else { /* No resampling needed */ for (i = 0; i < nframes; i++) s_buf[i] = in_buf[i] * (SHRT_MAX / 1.0); } res = jack_ringbuffer_write(jack_data->input_rb, (const char *) s_buf, write_len); if (res != write_len) { ast_debug(2, "Tried to write %d bytes to the ringbuffer, but only wrote %d\n", (int) sizeof(s_buf), (int) res); } }
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 600 of file app_jack.c.
References ARRAY_LEN, ast_debug, AST_FORMAT_SLINEAR, AST_FRAME_VOICE, ast_log(), ast_write(), buf, 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().
{ short buf[160]; struct ast_frame f = { .frametype = AST_FRAME_VOICE, .subclass = AST_FORMAT_SLINEAR, .src = "JACK", .data.ptr = buf, .datalen = sizeof(buf), .samples = ARRAY_LEN(buf), }; for (;;) { size_t res, read_len; char *read_buf; read_len = out_frame ? out_frame->datalen : sizeof(buf); read_buf = out_frame ? out_frame->data.ptr : buf; res = jack_ringbuffer_read_space(jack_data->input_rb); if (res < read_len) { /* Not enough data ready for another frame, move on ... */ if (out_frame) { ast_debug(1, "Sending an empty frame for the JACK_HOOK\n"); memset(out_frame->data.ptr, 0, out_frame->datalen); } break; } res = jack_ringbuffer_read(jack_data->input_rb, (char *) read_buf, read_len); if (res < read_len) { ast_log(LOG_ERROR, "Error reading from ringbuffer, even though it said there was enough data\n"); break; } if (out_frame) { /* If an output frame was provided, then we just want to fill up the * buffer in that frame and return. */ break; } ast_write(chan, &f); } }
static int handle_options | ( | struct jack_data * | jack_data, |
const char * | __options_str | ||
) | [static] |
Definition at line 692 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().
{ struct ast_flags options = { 0, }; char *option_args[OPT_ARG_ARRAY_SIZE]; char *options_str; options_str = ast_strdupa(__options_str); ast_app_parse_options(jack_exec_options, &options, option_args, options_str); if (ast_test_flag(&options, OPT_SERVER_NAME)) { if (!ast_strlen_zero(option_args[OPT_ARG_SERVER_NAME])) ast_string_field_set(jack_data, server_name, option_args[OPT_ARG_SERVER_NAME]); else { ast_log(LOG_ERROR, "A server name must be provided with the s() option\n"); return -1; } } if (ast_test_flag(&options, OPT_CLIENT_NAME)) { if (!ast_strlen_zero(option_args[OPT_ARG_CLIENT_NAME])) ast_string_field_set(jack_data, client_name, option_args[OPT_ARG_CLIENT_NAME]); else { ast_log(LOG_ERROR, "A client name must be provided with the c() option\n"); return -1; } } if (ast_test_flag(&options, OPT_INPUT_PORT)) { if (!ast_strlen_zero(option_args[OPT_ARG_INPUT_PORT])) ast_string_field_set(jack_data, connect_input_port, option_args[OPT_ARG_INPUT_PORT]); else { ast_log(LOG_ERROR, "A name must be provided with the i() option\n"); return -1; } } if (ast_test_flag(&options, OPT_OUTPUT_PORT)) { if (!ast_strlen_zero(option_args[OPT_ARG_OUTPUT_PORT])) ast_string_field_set(jack_data, connect_output_port, option_args[OPT_ARG_OUTPUT_PORT]); else { ast_log(LOG_ERROR, "A name must be provided with the o() option\n"); return -1; } } jack_data->no_start_server = ast_test_flag(&options, OPT_NOSTART_SERVER) ? 1 : 0; return 0; }
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 301 of file app_jack.c.
References ast_debug, len(), and jack_data::output_rb.
Referenced by jack_process().
static int init_jack_data | ( | struct ast_channel * | chan, |
struct jack_data * | jack_data | ||
) | [static] |
Definition at line 387 of file app_jack.c.
References ast_channel_lock, ast_channel_unlock, ast_debug, ast_log(), ast_strdupa, ast_strlen_zero(), jack_data::client, jack_data::client_name, jack_data::connect_input_port, jack_data::connect_output_port, free, jack_data::input_port, jack_data::input_rb, jack_process(), jack_shutdown(), LOG_ERROR, log_jack_status(), ast_channel::name, jack_data::no_start_server, jack_data::output_port, jack_data::output_rb, RINGBUFFER_SIZE, jack_data::server_name, and status.
Referenced by enable_jack_hook(), and jack_exec().
{ const char *client_name; jack_status_t status = 0; jack_options_t jack_options = JackNullOption; if (!ast_strlen_zero(jack_data->client_name)) { client_name = jack_data->client_name; } else { ast_channel_lock(chan); client_name = ast_strdupa(chan->name); ast_channel_unlock(chan); } if (!(jack_data->output_rb = jack_ringbuffer_create(RINGBUFFER_SIZE))) return -1; if (!(jack_data->input_rb = jack_ringbuffer_create(RINGBUFFER_SIZE))) return -1; if (jack_data->no_start_server) jack_options |= JackNoStartServer; if (!ast_strlen_zero(jack_data->server_name)) { jack_options |= JackServerName; jack_data->client = jack_client_open(client_name, jack_options, &status, jack_data->server_name); } else { jack_data->client = jack_client_open(client_name, jack_options, &status); } if (status) log_jack_status("Client Open Status", status); if (!jack_data->client) return -1; jack_data->input_port = jack_port_register(jack_data->client, "input", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput | JackPortIsTerminal, 0); if (!jack_data->input_port) { ast_log(LOG_ERROR, "Failed to create input port for jack port\n"); return -1; } jack_data->output_port = jack_port_register(jack_data->client, "output", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput | JackPortIsTerminal, 0); if (!jack_data->output_port) { ast_log(LOG_ERROR, "Failed to create output port for jack port\n"); return -1; } if (jack_set_process_callback(jack_data->client, jack_process, jack_data)) { ast_log(LOG_ERROR, "Failed to register process callback with jack client\n"); return -1; } jack_on_shutdown(jack_data->client, jack_shutdown, jack_data); if (jack_activate(jack_data->client)) { ast_log(LOG_ERROR, "Unable to activate jack client\n"); return -1; } while (!ast_strlen_zero(jack_data->connect_input_port)) { const char **ports; int i; ports = jack_get_ports(jack_data->client, jack_data->connect_input_port, NULL, JackPortIsInput); if (!ports) { ast_log(LOG_ERROR, "No input port matching '%s' was found\n", jack_data->connect_input_port); break; } for (i = 0; ports[i]; i++) { ast_debug(1, "Found port '%s' that matched specified input port '%s'\n", ports[i], jack_data->connect_input_port); } if (jack_connect(jack_data->client, jack_port_name(jack_data->output_port), ports[0])) { ast_log(LOG_ERROR, "Failed to connect '%s' to '%s'\n", ports[0], jack_port_name(jack_data->output_port)); } else { ast_debug(1, "Connected '%s' to '%s'\n", ports[0], jack_port_name(jack_data->output_port)); } free((void *) ports); break; } while (!ast_strlen_zero(jack_data->connect_output_port)) { const char **ports; int i; ports = jack_get_ports(jack_data->client, jack_data->connect_output_port, NULL, JackPortIsOutput); if (!ports) { ast_log(LOG_ERROR, "No output port matching '%s' was found\n", jack_data->connect_output_port); break; } for (i = 0; ports[i]; i++) { ast_debug(1, "Found port '%s' that matched specified output port '%s'\n", ports[i], jack_data->connect_output_port); } if (jack_connect(jack_data->client, ports[0], jack_port_name(jack_data->input_port))) { ast_log(LOG_ERROR, "Failed to connect '%s' to '%s'\n", ports[0], jack_port_name(jack_data->input_port)); } else { ast_debug(1, "Connected '%s' to '%s'\n", ports[0], jack_port_name(jack_data->input_port)); } free((void *) ports); break; } return 0; }
static struct jack_data* jack_data_alloc | ( | void | ) | [static, read] |
Definition at line 674 of file app_jack.c.
References ast_calloc, ast_free, and ast_string_field_init.
Referenced by enable_jack_hook(), and jack_exec().
{ struct jack_data *jack_data; if (!(jack_data = ast_calloc(1, sizeof(*jack_data)))) return NULL; if (ast_string_field_init(jack_data, 32)) { ast_free(jack_data); return NULL; } return jack_data; }
static int jack_exec | ( | struct ast_channel * | chan, |
void * | data | ||
) | [static] |
Definition at line 743 of file app_jack.c.
References AST_APP_ARG, AST_CONTROL_HANGUP, AST_DECLARE_APP_ARGS, 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(), jack_data_alloc(), queue_voice_frame(), jack_data::stop, and ast_frame::subclass.
Referenced by load_module().
{ struct jack_data *jack_data; AST_DECLARE_APP_ARGS(args, AST_APP_ARG(options); ); if (!(jack_data = jack_data_alloc())) return -1; args.options = data; if (!ast_strlen_zero(args.options) && handle_options(jack_data, args.options)) { destroy_jack_data(jack_data); return -1; } if (init_jack_data(chan, jack_data)) { destroy_jack_data(jack_data); return -1; } if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) { destroy_jack_data(jack_data); return -1; } if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) { destroy_jack_data(jack_data); return -1; } while (!jack_data->stop) { struct ast_frame *f; ast_waitfor(chan, -1); f = ast_read(chan); if (!f) { jack_data->stop = 1; continue; } switch (f->frametype) { case AST_FRAME_CONTROL: if (f->subclass == AST_CONTROL_HANGUP) jack_data->stop = 1; break; case AST_FRAME_VOICE: queue_voice_frame(jack_data, f); default: break; } ast_frfree(f); handle_jack_audio(chan, jack_data, NULL); } jack_data = destroy_jack_data(jack_data); return 0; }
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 819 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(), ast_datastore::data, ast_frame::frametype, handle_jack_audio(), LOG_ERROR, LOG_WARNING, ast_channel::name, queue_voice_frame(), ast_audiohook::status, and ast_frame::subclass.
Referenced by enable_jack_hook().
{ struct ast_datastore *datastore; struct jack_data *jack_data; if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE) return 0; if (direction != AST_AUDIOHOOK_DIRECTION_READ) return 0; if (frame->frametype != AST_FRAME_VOICE) return 0; if (frame->subclass != AST_FORMAT_SLINEAR) { ast_log(LOG_WARNING, "Expected frame in SLINEAR for the audiohook, but got format %d\n", frame->subclass); return 0; } ast_channel_lock(chan); if (!(datastore = ast_channel_datastore_find(chan, &jack_hook_ds_info, NULL))) { ast_log(LOG_ERROR, "JACK_HOOK datastore not found for '%s'\n", chan->name); ast_channel_unlock(chan); return -1; } jack_data = datastore->data; queue_voice_frame(jack_data, frame); handle_jack_audio(chan, jack_data, frame); ast_channel_unlock(chan); return 0; }
static void jack_hook_ds_destroy | ( | void * | data | ) | [static] |
Definition at line 807 of file app_jack.c.
References destroy_jack_data().
{ struct jack_data *jack_data = data; destroy_jack_data(jack_data); }
static int jack_hook_write | ( | struct ast_channel * | chan, |
const char * | cmd, | ||
char * | data, | ||
const char * | value | ||
) | [static] |
Definition at line 948 of file app_jack.c.
References ast_log(), disable_jack_hook(), enable_jack_hook(), and LOG_ERROR.
{ int res; if (!strcasecmp(value, "on")) res = enable_jack_hook(chan, data); else if (!strcasecmp(value, "off")) res = disable_jack_hook(chan); else { ast_log(LOG_ERROR, "'%s' is not a valid value for JACK_HOOK()\n", value); res = -1; } return res; }
static int jack_process | ( | jack_nframes_t | nframes, |
void * | arg | ||
) | [static] |
Definition at line 316 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().
{ struct jack_data *jack_data = arg; void *input_port_buf, *output_port_buf; if (!jack_data->input_resample_factor) alloc_resampler(jack_data, 1); input_port_buf = jack_port_get_buffer(jack_data->input_port, nframes); handle_input(input_port_buf, nframes, jack_data); output_port_buf = jack_port_get_buffer(jack_data->output_port, nframes); handle_output(output_port_buf, nframes, jack_data); return 0; }
static void jack_shutdown | ( | void * | arg | ) | [static] |
Definition at line 333 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 157 of file app_jack.c.
References ARRAY_LEN, and jack_status_table.
Referenced by log_jack_status().
{ int i; for (i = 0; i < ARRAY_LEN(jack_status_table); i++) { if (jack_status_table[i].status == status) return jack_status_table[i].str; } return "Unknown Error"; }
static int load_module | ( | void | ) | [static] |
Definition at line 1011 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().
{ if (ast_register_application_xml(jack_app, jack_exec)) { return AST_MODULE_LOAD_DECLINE; } if (ast_custom_function_register(&jack_hook_function)) { ast_unregister_application(jack_app); return AST_MODULE_LOAD_DECLINE; } return AST_MODULE_LOAD_SUCCESS; }
static void log_jack_status | ( | const char * | prefix, |
jack_status_t | status | ||
) | [static] |
Definition at line 169 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, status, and str.
Referenced by init_jack_data().
{ struct ast_str *str = ast_str_alloca(512); int i, first = 0; for (i = 0; i < (sizeof(status) * 8); i++) { if (!(status & (1 << i))) continue; if (!first) { ast_str_set(&str, 0, "%s", jack_status_to_str((1 << i))); first = 1; } else ast_str_append(&str, 0, ", %s", jack_status_to_str((1 << i))); } ast_log(LOG_NOTICE, "%s: %s\n", prefix, ast_str_buffer(str)); }
Definition at line 515 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().
{ float f_buf[f->samples * 8]; size_t f_buf_used = 0; int i; int16_t *s_buf = f->data.ptr; size_t res; memset(f_buf, 0, sizeof(f_buf)); if (!jack_data->output_resample_factor) alloc_resampler(jack_data, 0); if (jack_data->output_resampler) { float in_buf[f->samples]; int total_in_buf_used = 0; int total_out_buf_used = 0; memset(in_buf, 0, sizeof(in_buf)); for (i = 0; i < f->samples; i++) in_buf[i] = s_buf[i] * (1.0 / SHRT_MAX); while (total_in_buf_used < ARRAY_LEN(in_buf)) { int in_buf_used; int out_buf_used; out_buf_used = resample_process(jack_data->output_resampler, jack_data->output_resample_factor, &in_buf[total_in_buf_used], ARRAY_LEN(in_buf) - total_in_buf_used, 0, &in_buf_used, &f_buf[total_out_buf_used], ARRAY_LEN(f_buf) - total_out_buf_used); if (out_buf_used < 0) break; total_out_buf_used += out_buf_used; total_in_buf_used += in_buf_used; if (total_out_buf_used == ARRAY_LEN(f_buf)) { ast_log(LOG_ERROR, "Output buffer filled ... need to increase its size\n"); break; } } f_buf_used = total_out_buf_used; if (f_buf_used > ARRAY_LEN(f_buf)) f_buf_used = ARRAY_LEN(f_buf); } else { /* No resampling needed */ for (i = 0; i < f->samples; i++) f_buf[i] = s_buf[i] * (1.0 / SHRT_MAX); f_buf_used = f->samples; } res = jack_ringbuffer_write(jack_data->output_rb, (const char *) f_buf, f_buf_used * sizeof(float)); if (res != (f_buf_used * sizeof(float))) { ast_debug(2, "Tried to write %d bytes to the ringbuffer, but only wrote %d\n", (int) (f_buf_used * sizeof(float)), (int) res); } return 0; }
static int unload_module | ( | void | ) | [static] |
Definition at line 1001 of file app_jack.c.
References ast_custom_function_unregister(), and ast_unregister_application().
{ int res; res = ast_unregister_application(jack_app); res |= ast_custom_function_unregister(&jack_hook_function); return res; }
struct ast_module_info __MODULE_INFO_SECTION __mod_info = { __MODULE_INFO_GLOBALS .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "JACK Interface" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, } [static] |
Definition at line 1025 of file app_jack.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 1025 of file app_jack.c.
char* jack_app = "JACK" [static] |
Definition at line 115 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] |
Definition at line 672 of file app_jack.c.
Referenced by handle_options().
struct ast_datastore_info jack_hook_ds_info [static] |
{ .type = "JACK_HOOK", .destroy = jack_hook_ds_destroy, }
Definition at line 814 of file app_jack.c.
struct ast_custom_function jack_hook_function [static] |
Definition at line 965 of file app_jack.c.
struct { ... } jack_status_table[] [static] |
Referenced by jack_status_to_str().
jack_status_t status |
Definition at line 141 of file app_jack.c.
Referenced by __ast_pbx_run(), __iax2_show_peers(), _child_handler(), _sip_show_peer(), _sip_show_peers(), acf_odbc_read(), acf_odbc_write(), action_agents(), action_extensionstate(), agent_hangup(), agent_read(), agi_exec_full(), aji_handle_presence(), aji_handle_subscribe(), aji_show_clients(), aji_status_exec(), ast_audiohook_update_status(), ast_safe_system(), build_status(), build_timeout(), chanavail_exec(), change_favorite_icon(), complete_dpreply(), dundi_show_peers(), findmeexec(), 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(), log_jack_status(), 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(), send_favorite(), Sendicon(), sendtext_exec(), sendurl_exec(), shaun_of_the_dead(), show_entry_history(), transfer_exec(), update_status(), wait_for_answer(), and wait_our_turn().
const char* str |
Definition at line 142 of file app_jack.c.
Referenced by _free_port_cfg(), acf_curl_exec(), action_status(), add_publish_event(), add_subscribe_event(), amixer_max(), anti_injection(), ast_event_subscribe(), ast_hashtab_hash_string(), ast_hashtab_hash_string_nocase(), ast_hashtab_hash_string_sax(), ast_skip_blanks(), ast_trim_blanks(), check_mime(), do_magic_pickup(), find_realtime(), finddelim(), handle_link_data(), handle_playtones(), handle_statechange(), handle_tcptls_connection(), hash_string(), hid_device_init(), hid_device_mklist(), iax_parse_ies(), init_appendbuf(), jingle_new(), log_jack_status(), manager_rpt_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(), new_find_extension(), process_text_line(), pvalWordSetString(), regex(), remove_spaces_before_equals(), rpt(), send_link_dtmf(), send_link_keyquery(), setamixer(), statpost(), strsep(), usb_get_usbdev(), variable_count_cmp_fn(), write_html_escaped(), and yyparse().