app_jack.c File Reference

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"
#include "asterisk/format_cache.h"

Include dependency graph for app_jack.c:

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_FRAME_CAPACITY   100

Enumerations

enum  {
  OPT_SERVER_NAME = (1 << 0), OPT_INPUT_PORT = (1 << 1), OPT_OUTPUT_PORT = (1 << 2), OPT_NOSTART_SERVER = (1 << 3),
  OPT_CLIENT_NAME = (1 << 4)
}
enum  {
  OPT_ARG_SERVER_NAME, OPT_ARG_INPUT_PORT, OPT_ARG_OUTPUT_PORT, OPT_ARG_CLIENT_NAME,
  OPT_ARG_ARRAY_SIZE
}

Functions

static int alloc_resampler (struct jack_data *jack_data, int input)
 AST_MODULE_INFO_STANDARD_EXTENDED (ASTERISK_GPL_KEY,"JACK Interface")
static struct jack_datadestroy_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_datajack_data_alloc (void)
static int jack_exec (struct ast_channel *chan, const char *data)
static int jack_hook_callback (struct ast_audiohook *audiohook, struct ast_channel *chan, struct ast_frame *frame, enum ast_audiohook_direction direction)
static void jack_hook_ds_destroy (void *data)
static int jack_hook_write (struct ast_channel *chan, const char *cmd, char *data, const char *value)
static int jack_process (jack_nframes_t nframes, void *arg)
static void jack_shutdown (void *arg)
static const char * jack_status_to_str (jack_status_t status)
static int load_module (void)
static void log_jack_status (const char *prefix, jack_status_t status)
static int queue_voice_frame (struct jack_data *jack_data, struct ast_frame *f)
static int unload_module (void)

Variables

static const char jack_app [] = "JACK"
static struct ast_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 []


Detailed Description

Jack Application.

Author:
Russell Bryant <russell@digium.com>
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.

ExtRef:
http://www.jackaudio.org/
Note:
To install libresample, check it out of the following repository: $ svn co http://svn.digium.com/svn/thirdparty/libresample/trunk

Definition in file app_jack.c.


Define Documentation

#define COMMON_OPTIONS

Common options between the Jack() app and JACK_HOOK() function.

Definition at line 69 of file app_jack.c.

#define RESAMPLE_QUALITY   1

Definition at line 63 of file app_jack.c.

Referenced by alloc_resampler().

#define RINGBUFFER_FRAME_CAPACITY   100

Definition at line 66 of file app_jack.c.

Referenced by init_jack_data().


Enumeration Type Documentation

anonymous enum

Enumerator:
OPT_SERVER_NAME 
OPT_INPUT_PORT 
OPT_OUTPUT_PORT 
OPT_NOSTART_SERVER 
OPT_CLIENT_NAME 

Definition at line 671 of file app_jack.c.

00671      {
00672    OPT_SERVER_NAME =    (1 << 0),
00673    OPT_INPUT_PORT =     (1 << 1),
00674    OPT_OUTPUT_PORT =    (1 << 2),
00675    OPT_NOSTART_SERVER = (1 << 3),
00676    OPT_CLIENT_NAME =    (1 << 4),
00677 };

anonymous enum

Enumerator:
OPT_ARG_SERVER_NAME 
OPT_ARG_INPUT_PORT 
OPT_ARG_OUTPUT_PORT 
OPT_ARG_CLIENT_NAME 
OPT_ARG_ARRAY_SIZE 

Definition at line 679 of file app_jack.c.

00679      {
00680    OPT_ARG_SERVER_NAME,
00681    OPT_ARG_INPUT_PORT,
00682    OPT_ARG_OUTPUT_PORT,
00683    OPT_ARG_CLIENT_NAME,
00684 
00685    /* Must be the last element */
00686    OPT_ARG_ARRAY_SIZE,
00687 };


Function Documentation

static int alloc_resampler ( struct jack_data jack_data,
int  input 
) [static]

Definition at line 195 of file app_jack.c.

References ast_log, jack_data::audiohook_rate, 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().

00196 {
00197    double from_srate, to_srate, jack_srate;
00198    void **resampler;
00199    double *resample_factor;
00200 
00201    if (input && jack_data->input_resampler)
00202       return 0;
00203 
00204    if (!input && jack_data->output_resampler)
00205       return 0;
00206 
00207    jack_srate = jack_get_sample_rate(jack_data->client);
00208 
00209    to_srate = input ? jack_data->audiohook_rate : jack_srate;
00210    from_srate = input ? jack_srate : jack_data->audiohook_rate;
00211 
00212    resample_factor = input ? &jack_data->input_resample_factor :
00213       &jack_data->output_resample_factor;
00214 
00215    if (from_srate == to_srate) {
00216       /* Awesome!  The jack sample rate is the same as ours.
00217        * Resampling isn't needed. */
00218       *resample_factor = 1.0;
00219       return 0;
00220    }
00221 
00222    *resample_factor = to_srate / from_srate;
00223 
00224    resampler = input ? &jack_data->input_resampler :
00225       &jack_data->output_resampler;
00226 
00227    if (!(*resampler = resample_open(RESAMPLE_QUALITY,
00228       *resample_factor, *resample_factor))) {
00229       ast_log(LOG_ERROR, "Failed to open %s resampler\n",
00230          input ? "input" : "output");
00231       return -1;
00232    }
00233 
00234    return 0;
00235 }

AST_MODULE_INFO_STANDARD_EXTENDED ( ASTERISK_GPL_KEY  ,
"JACK Interface"   
)

static struct jack_data* destroy_jack_data ( struct jack_data jack_data  )  [static, read]

Definition at line 345 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, NULL, 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().

00346 {
00347    if (jack_data->input_port) {
00348       jack_port_unregister(jack_data->client, jack_data->input_port);
00349       jack_data->input_port = NULL;
00350    }
00351 
00352    if (jack_data->output_port) {
00353       jack_port_unregister(jack_data->client, jack_data->output_port);
00354       jack_data->output_port = NULL;
00355    }
00356 
00357    if (jack_data->client) {
00358       jack_client_close(jack_data->client);
00359       jack_data->client = NULL;
00360    }
00361 
00362    if (jack_data->input_rb) {
00363       jack_ringbuffer_free(jack_data->input_rb);
00364       jack_data->input_rb = NULL;
00365    }
00366 
00367    if (jack_data->output_rb) {
00368       jack_ringbuffer_free(jack_data->output_rb);
00369       jack_data->output_rb = NULL;
00370    }
00371 
00372    if (jack_data->output_resampler) {
00373       resample_close(jack_data->output_resampler);
00374       jack_data->output_resampler = NULL;
00375    }
00376 
00377    if (jack_data->input_resampler) {
00378       resample_close(jack_data->input_resampler);
00379       jack_data->input_resampler = NULL;
00380    }
00381 
00382    if (jack_data->has_audiohook)
00383       ast_audiohook_destroy(&jack_data->audiohook);
00384 
00385    ast_string_field_free_memory(jack_data);
00386 
00387    ast_free(jack_data);
00388 
00389    return NULL;
00390 }

static int disable_jack_hook ( struct ast_channel chan  )  [static]

Definition at line 944 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, LOG_WARNING, and NULL.

Referenced by jack_hook_write().

00945 {
00946    struct ast_datastore *datastore;
00947    struct jack_data *jack_data;
00948 
00949    ast_channel_lock(chan);
00950 
00951    if (!(datastore = ast_channel_datastore_find(chan, &jack_hook_ds_info, NULL))) {
00952       ast_channel_unlock(chan);
00953       ast_log(LOG_WARNING, "No JACK_HOOK found to disable\n");
00954       return -1;
00955    }
00956 
00957    ast_channel_datastore_remove(chan, datastore);
00958 
00959    jack_data = datastore->data;
00960    ast_audiohook_detach(&jack_data->audiohook);
00961 
00962    /* Keep the channel locked while we destroy the datastore, so that we can
00963     * ensure that all of the jack stuff is stopped just in case another frame
00964     * tries to come through the audiohook callback. */
00965    ast_datastore_free(datastore);
00966 
00967    ast_channel_unlock(chan);
00968 
00969    return 0;
00970 }

static int enable_jack_hook ( struct ast_channel chan,
char *  data 
) [static]

Definition at line 877 of file app_jack.c.

References args, AST_APP_ARG, ast_audiohook_attach(), ast_audiohook_init(), AST_AUDIOHOOK_MANIPULATE_ALL_RATES, AST_AUDIOHOOK_TYPE_MANIPULATE, ast_channel_datastore_add(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_name(), ast_channel_unlock, ast_datastore_alloc, ast_datastore_free(), AST_DECLARE_APP_ARGS, ast_log, AST_STANDARD_APP_ARGS, ast_strlen_zero, jack_data::audiohook, ast_datastore::data, destroy_jack_data(), handle_options(), jack_data::has_audiohook, init_jack_data(), jack_data_alloc(), jack_hook_callback(), LOG_ERROR, ast_audiohook::manipulate_callback, NULL, and S_OR.

Referenced by jack_hook_write().

00878 {
00879    struct ast_datastore *datastore;
00880    struct jack_data *jack_data = NULL;
00881    AST_DECLARE_APP_ARGS(args,
00882       AST_APP_ARG(mode);
00883       AST_APP_ARG(options);
00884    );
00885 
00886    AST_STANDARD_APP_ARGS(args, data);
00887 
00888    ast_channel_lock(chan);
00889 
00890    if ((datastore = ast_channel_datastore_find(chan, &jack_hook_ds_info, NULL))) {
00891       ast_log(LOG_ERROR, "JACK_HOOK already enabled for '%s'\n", ast_channel_name(chan));
00892       goto return_error;
00893    }
00894 
00895    if (ast_strlen_zero(args.mode) || strcasecmp(args.mode, "manipulate")) {
00896       ast_log(LOG_ERROR, "'%s' is not a supported mode.  Only manipulate is supported.\n",
00897          S_OR(args.mode, "<none>"));
00898       goto return_error;
00899    }
00900 
00901    if (!(jack_data = jack_data_alloc()))
00902       goto return_error;
00903 
00904    if (!ast_strlen_zero(args.options) && handle_options(jack_data, args.options))
00905       goto return_error;
00906 
00907    if (init_jack_data(chan, jack_data))
00908       goto return_error;
00909 
00910    if (!(datastore = ast_datastore_alloc(&jack_hook_ds_info, NULL)))
00911       goto return_error;
00912 
00913    jack_data->has_audiohook = 1;
00914    ast_audiohook_init(&jack_data->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "JACK_HOOK", AST_AUDIOHOOK_MANIPULATE_ALL_RATES);
00915    jack_data->audiohook.manipulate_callback = jack_hook_callback;
00916 
00917    datastore->data = jack_data;
00918 
00919    if (ast_audiohook_attach(chan, &jack_data->audiohook))
00920       goto return_error;
00921 
00922    if (ast_channel_datastore_add(chan, datastore))
00923       goto return_error;
00924 
00925    ast_channel_unlock(chan);
00926 
00927    return 0;
00928 
00929 return_error:
00930    ast_channel_unlock(chan);
00931 
00932    if (jack_data) {
00933       destroy_jack_data(jack_data);
00934    }
00935 
00936    if (datastore) {
00937       datastore->data = NULL;
00938       ast_datastore_free(datastore);
00939    }
00940 
00941    return -1;
00942 }

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 243 of file app_jack.c.

References ARRAY_LEN, ast_log, jack_data::input_rb, jack_data::input_resample_factor, jack_data::input_resampler, LOG_ERROR, and LOG_WARNING.

Referenced by jack_process().

00245 {
00246    short s_buf[nframes];
00247    float *in_buf = buf;
00248    size_t res;
00249    int i;
00250    size_t write_len = sizeof(s_buf);
00251 
00252    if (jack_data->input_resampler) {
00253       int total_in_buf_used = 0;
00254       int total_out_buf_used = 0;
00255       float f_buf[nframes + 1];
00256 
00257       memset(f_buf, 0, sizeof(f_buf));
00258 
00259       while (total_in_buf_used < nframes) {
00260          int in_buf_used;
00261          int out_buf_used;
00262 
00263          out_buf_used = resample_process(jack_data->input_resampler,
00264             jack_data->input_resample_factor,
00265             &in_buf[total_in_buf_used], nframes - total_in_buf_used,
00266             0, &in_buf_used,
00267             &f_buf[total_out_buf_used], ARRAY_LEN(f_buf) - total_out_buf_used);
00268 
00269          if (out_buf_used < 0)
00270             break;
00271 
00272          total_out_buf_used += out_buf_used;
00273          total_in_buf_used += in_buf_used;
00274 
00275          if (total_out_buf_used == ARRAY_LEN(f_buf)) {
00276             ast_log(LOG_ERROR, "Output buffer filled ... need to increase its size, "
00277                "nframes '%d', total_out_buf_used '%d'\n", nframes, total_out_buf_used);
00278             break;
00279          }
00280       }
00281 
00282       for (i = 0; i < total_out_buf_used; i++)
00283          s_buf[i] = f_buf[i] * (SHRT_MAX / 1.0);
00284 
00285       write_len = total_out_buf_used * sizeof(int16_t);
00286    } else {
00287       /* No resampling needed */
00288 
00289       for (i = 0; i < nframes; i++)
00290          s_buf[i] = in_buf[i] * (SHRT_MAX / 1.0);
00291    }
00292 
00293    res = jack_ringbuffer_write(jack_data->input_rb, (const char *) s_buf, write_len);
00294    if (res != write_len) {
00295       ast_log(LOG_WARNING, "Tried to write %d bytes to the ringbuffer, but only wrote %d\n",
00296          (int) sizeof(s_buf), (int) res);
00297    }
00298 }

static void handle_jack_audio ( struct ast_channel chan,
struct jack_data jack_data,
struct ast_frame out_frame 
) [static]

handle jack audio

Parameters:
[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.

Returns:
Nothing.

Definition at line 623 of file app_jack.c.

References ARRAY_LEN, ast_debug, AST_FRAME_VOICE, ast_log, ast_write(), jack_data::audiohook_format, buf, ast_frame::data, ast_frame::datalen, jack_data::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().

00625 {
00626    short buf[jack_data->frame_datalen];
00627    struct ast_frame f = {
00628       .frametype = AST_FRAME_VOICE,
00629       .subclass.format = jack_data->audiohook_format,
00630       .src = "JACK",
00631       .data.ptr = buf,
00632       .datalen = sizeof(buf),
00633       .samples = ARRAY_LEN(buf),
00634    };
00635 
00636    for (;;) {
00637       size_t res, read_len;
00638       char *read_buf;
00639 
00640       read_len = out_frame ? out_frame->datalen : sizeof(buf);
00641       read_buf = out_frame ? out_frame->data.ptr : buf;
00642 
00643       res = jack_ringbuffer_read_space(jack_data->input_rb);
00644 
00645       if (res < read_len) {
00646          /* Not enough data ready for another frame, move on ... */
00647          if (out_frame) {
00648             ast_debug(1, "Sending an empty frame for the JACK_HOOK\n");
00649             memset(out_frame->data.ptr, 0, out_frame->datalen);
00650          }
00651          break;
00652       }
00653 
00654       res = jack_ringbuffer_read(jack_data->input_rb, (char *) read_buf, read_len);
00655 
00656       if (res < read_len) {
00657          ast_log(LOG_ERROR, "Error reading from ringbuffer, even though it said there was enough data\n");
00658          break;
00659       }
00660 
00661       if (out_frame) {
00662          /* If an output frame was provided, then we just want to fill up the
00663           * buffer in that frame and return. */
00664          break;
00665       }
00666 
00667       ast_write(chan, &f);
00668    }
00669 }

static int handle_options ( struct jack_data jack_data,
const char *  __options_str 
) [static]

Note:
This must be done before calling init_jack_data().

Definition at line 711 of file app_jack.c.

References ast_app_parse_options(), ast_log, ast_strdupa, ast_string_field_set, ast_strlen_zero, ast_test_flag, jack_exec_options, LOG_ERROR, jack_data::no_start_server, OPT_ARG_ARRAY_SIZE, OPT_ARG_CLIENT_NAME, OPT_ARG_INPUT_PORT, OPT_ARG_OUTPUT_PORT, OPT_ARG_SERVER_NAME, OPT_CLIENT_NAME, OPT_INPUT_PORT, OPT_NOSTART_SERVER, OPT_OUTPUT_PORT, and OPT_SERVER_NAME.

Referenced by ast_ari_invoke(), enable_jack_hook(), and jack_exec().

00712 {
00713    struct ast_flags options = { 0, };
00714    char *option_args[OPT_ARG_ARRAY_SIZE];
00715    char *options_str;
00716 
00717    options_str = ast_strdupa(__options_str);
00718 
00719    ast_app_parse_options(jack_exec_options, &options, option_args, options_str);
00720 
00721    if (ast_test_flag(&options, OPT_SERVER_NAME)) {
00722       if (!ast_strlen_zero(option_args[OPT_ARG_SERVER_NAME]))
00723          ast_string_field_set(jack_data, server_name, option_args[OPT_ARG_SERVER_NAME]);
00724       else {
00725          ast_log(LOG_ERROR, "A server name must be provided with the s() option\n");
00726          return -1;
00727       }
00728    }
00729 
00730    if (ast_test_flag(&options, OPT_CLIENT_NAME)) {
00731       if (!ast_strlen_zero(option_args[OPT_ARG_CLIENT_NAME]))
00732          ast_string_field_set(jack_data, client_name, option_args[OPT_ARG_CLIENT_NAME]);
00733       else {
00734          ast_log(LOG_ERROR, "A client name must be provided with the c() option\n");
00735          return -1;
00736       }
00737    }
00738 
00739    if (ast_test_flag(&options, OPT_INPUT_PORT)) {
00740       if (!ast_strlen_zero(option_args[OPT_ARG_INPUT_PORT]))
00741          ast_string_field_set(jack_data, connect_input_port, option_args[OPT_ARG_INPUT_PORT]);
00742       else {
00743          ast_log(LOG_ERROR, "A name must be provided with the i() option\n");
00744          return -1;
00745       }
00746    }
00747 
00748    if (ast_test_flag(&options, OPT_OUTPUT_PORT)) {
00749       if (!ast_strlen_zero(option_args[OPT_ARG_OUTPUT_PORT]))
00750          ast_string_field_set(jack_data, connect_output_port, option_args[OPT_ARG_OUTPUT_PORT]);
00751       else {
00752          ast_log(LOG_ERROR, "A name must be provided with the o() option\n");
00753          return -1;
00754       }
00755    }
00756 
00757    jack_data->no_start_server = ast_test_flag(&options, OPT_NOSTART_SERVER) ? 1 : 0;
00758 
00759    return 0;
00760 }

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 306 of file app_jack.c.

References ast_debug, len(), and jack_data::output_rb.

Referenced by jack_process().

00308 {
00309    size_t res, len;
00310 
00311    len = nframes * sizeof(float);
00312 
00313    res = jack_ringbuffer_read(jack_data->output_rb, buf, len);
00314 
00315    if (len != res) {
00316       ast_debug(2, "Wanted %d bytes to send to the output port, "
00317          "but only got %d\n", (int) len, (int) res);
00318    }
00319 }

static int init_jack_data ( struct ast_channel chan,
struct jack_data jack_data 
) [static]

Definition at line 392 of file app_jack.c.

References ast_channel_lock, ast_channel_name(), ast_channel_readformat(), ast_channel_unlock, ast_debug, ast_format_cache_get_slin_by_rate(), ast_format_get_name(), ast_format_get_sample_rate(), ast_log, ast_strdupa, ast_strlen_zero, jack_data::audiohook_format, jack_data::audiohook_rate, jack_data::client, jack_data::client_name, jack_data::connect_input_port, jack_data::connect_output_port, jack_data::frame_datalen, jack_data::input_port, jack_data::input_rb, jack_process(), jack_shutdown(), LOG_ERROR, log_jack_status(), jack_data::no_start_server, NULL, jack_data::output_port, jack_data::output_rb, RINGBUFFER_FRAME_CAPACITY, jack_data::server_name, and status.

Referenced by enable_jack_hook(), and jack_exec().

00393 {
00394    const char *client_name;
00395    jack_status_t status = 0;
00396    jack_options_t jack_options = JackNullOption;
00397 
00398    unsigned int channel_rate;
00399 
00400    unsigned int ringbuffer_size;
00401 
00402    /* Deducing audiohook sample rate from channel format
00403       ATTENTION: Might be problematic, if channel has different sampling than used by audiohook!
00404    */
00405    channel_rate = ast_format_get_sample_rate(ast_channel_readformat(chan));
00406    jack_data->audiohook_format = ast_format_cache_get_slin_by_rate(channel_rate);
00407    jack_data->audiohook_rate = ast_format_get_sample_rate(jack_data->audiohook_format);
00408 
00409    /* Guessing frame->datalen assuming a ptime of 20ms */
00410    jack_data->frame_datalen = jack_data->audiohook_rate / 50;
00411 
00412    ringbuffer_size = jack_data->frame_datalen * RINGBUFFER_FRAME_CAPACITY;
00413 
00414    ast_debug(1, "Audiohook parameters: slin-format:%s, rate:%d, frame-len:%d, ringbuffer_size: %d\n",
00415        ast_format_get_name(jack_data->audiohook_format), jack_data->audiohook_rate, jack_data->frame_datalen, ringbuffer_size);
00416 
00417    if (!ast_strlen_zero(jack_data->client_name)) {
00418       client_name = jack_data->client_name;
00419    } else {
00420       ast_channel_lock(chan);
00421       client_name = ast_strdupa(ast_channel_name(chan));
00422       ast_channel_unlock(chan);
00423    }
00424 
00425    if (!(jack_data->output_rb = jack_ringbuffer_create(ringbuffer_size)))
00426       return -1;
00427 
00428    if (!(jack_data->input_rb = jack_ringbuffer_create(ringbuffer_size)))
00429       return -1;
00430 
00431    if (jack_data->no_start_server)
00432       jack_options |= JackNoStartServer;
00433 
00434    if (!ast_strlen_zero(jack_data->server_name)) {
00435       jack_options |= JackServerName;
00436       jack_data->client = jack_client_open(client_name, jack_options, &status,
00437          jack_data->server_name);
00438    } else {
00439       jack_data->client = jack_client_open(client_name, jack_options, &status);
00440    }
00441 
00442    if (status)
00443       log_jack_status("Client Open Status", status);
00444 
00445    if (!jack_data->client)
00446       return -1;
00447 
00448    jack_data->input_port = jack_port_register(jack_data->client, "input",
00449       JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput | JackPortIsTerminal, 0);
00450    if (!jack_data->input_port) {
00451       ast_log(LOG_ERROR, "Failed to create input port for jack port\n");
00452       return -1;
00453    }
00454 
00455    jack_data->output_port = jack_port_register(jack_data->client, "output",
00456       JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput | JackPortIsTerminal, 0);
00457    if (!jack_data->output_port) {
00458       ast_log(LOG_ERROR, "Failed to create output port for jack port\n");
00459       return -1;
00460    }
00461 
00462    if (jack_set_process_callback(jack_data->client, jack_process, jack_data)) {
00463       ast_log(LOG_ERROR, "Failed to register process callback with jack client\n");
00464       return -1;
00465    }
00466 
00467    jack_on_shutdown(jack_data->client, jack_shutdown, jack_data);
00468 
00469    if (jack_activate(jack_data->client)) {
00470       ast_log(LOG_ERROR, "Unable to activate jack client\n");
00471       return -1;
00472    }
00473 
00474    while (!ast_strlen_zero(jack_data->connect_input_port)) {
00475       const char **ports;
00476       int i;
00477 
00478       ports = jack_get_ports(jack_data->client, jack_data->connect_input_port,
00479          NULL, JackPortIsInput);
00480 
00481       if (!ports) {
00482          ast_log(LOG_ERROR, "No input port matching '%s' was found\n",
00483             jack_data->connect_input_port);
00484          break;
00485       }
00486 
00487       for (i = 0; ports[i]; i++) {
00488          ast_debug(1, "Found port '%s' that matched specified input port '%s'\n",
00489             ports[i], jack_data->connect_input_port);
00490       }
00491 
00492       if (jack_connect(jack_data->client, jack_port_name(jack_data->output_port), ports[0])) {
00493          ast_log(LOG_ERROR, "Failed to connect '%s' to '%s'\n", ports[0],
00494             jack_port_name(jack_data->output_port));
00495       } else {
00496          ast_debug(1, "Connected '%s' to '%s'\n", ports[0],
00497             jack_port_name(jack_data->output_port));
00498       }
00499 
00500       jack_free(ports);
00501 
00502       break;
00503    }
00504 
00505    while (!ast_strlen_zero(jack_data->connect_output_port)) {
00506       const char **ports;
00507       int i;
00508 
00509       ports = jack_get_ports(jack_data->client, jack_data->connect_output_port,
00510          NULL, JackPortIsOutput);
00511 
00512       if (!ports) {
00513          ast_log(LOG_ERROR, "No output port matching '%s' was found\n",
00514             jack_data->connect_output_port);
00515          break;
00516       }
00517 
00518       for (i = 0; ports[i]; i++) {
00519          ast_debug(1, "Found port '%s' that matched specified output port '%s'\n",
00520             ports[i], jack_data->connect_output_port);
00521       }
00522 
00523       if (jack_connect(jack_data->client, ports[0], jack_port_name(jack_data->input_port))) {
00524          ast_log(LOG_ERROR, "Failed to connect '%s' to '%s'\n", ports[0],
00525             jack_port_name(jack_data->input_port));
00526       } else {
00527          ast_debug(1, "Connected '%s' to '%s'\n", ports[0],
00528             jack_port_name(jack_data->input_port));
00529       }
00530 
00531       jack_free(ports);
00532 
00533       break;
00534    }
00535 
00536    return 0;
00537 }

static struct jack_data* jack_data_alloc ( void   )  [static, read]

Definition at line 697 of file app_jack.c.

References ast_calloc_with_stringfields, and NULL.

Referenced by enable_jack_hook(), and jack_exec().

00698 {
00699    struct jack_data *jack_data;
00700 
00701    if (!(jack_data = ast_calloc_with_stringfields(1, struct jack_data, 32))) {
00702       return NULL;
00703    }
00704 
00705    return jack_data;
00706 }

static int jack_exec ( struct ast_channel chan,
const char *  data 
) [static]

Definition at line 762 of file app_jack.c.

References AST_CONTROL_HANGUP, AST_FRAME_CONTROL, AST_FRAME_VOICE, ast_frfree, ast_read(), ast_set_read_format(), ast_set_write_format(), ast_strlen_zero, ast_waitfor(), jack_data::audiohook_format, destroy_jack_data(), f, ast_frame::frametype, handle_jack_audio(), handle_options(), init_jack_data(), ast_frame_subclass::integer, jack_data_alloc(), NULL, queue_voice_frame(), jack_data::stop, and ast_frame::subclass.

Referenced by load_module().

00763 {
00764    struct jack_data *jack_data;
00765 
00766    if (!(jack_data = jack_data_alloc()))
00767       return -1;
00768 
00769    if (!ast_strlen_zero(data) && handle_options(jack_data, data)) {
00770       destroy_jack_data(jack_data);
00771       return -1;
00772    }
00773 
00774    if (init_jack_data(chan, jack_data)) {
00775       destroy_jack_data(jack_data);
00776       return -1;
00777    }
00778 
00779    if (ast_set_read_format(chan, jack_data->audiohook_format)) {
00780       destroy_jack_data(jack_data);
00781       return -1;
00782    }
00783 
00784    if (ast_set_write_format(chan, jack_data->audiohook_format)) {
00785       destroy_jack_data(jack_data);
00786       return -1;
00787    }
00788 
00789    while (!jack_data->stop) {
00790       struct ast_frame *f;
00791 
00792       if (ast_waitfor(chan, -1) < 0) {
00793          break;
00794       }
00795 
00796       f = ast_read(chan);
00797       if (!f) {
00798          jack_data->stop = 1;
00799          continue;
00800       }
00801 
00802       switch (f->frametype) {
00803       case AST_FRAME_CONTROL:
00804          if (f->subclass.integer == AST_CONTROL_HANGUP)
00805             jack_data->stop = 1;
00806          break;
00807       case AST_FRAME_VOICE:
00808          queue_voice_frame(jack_data, f);
00809       default:
00810          break;
00811       }
00812 
00813       ast_frfree(f);
00814 
00815       handle_jack_audio(chan, jack_data, NULL);
00816    }
00817 
00818    jack_data = destroy_jack_data(jack_data);
00819 
00820    return 0;
00821 }

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 835 of file app_jack.c.

References AST_AUDIOHOOK_DIRECTION_READ, AST_AUDIOHOOK_STATUS_DONE, ast_channel_datastore_find(), ast_channel_lock, ast_channel_name(), ast_channel_unlock, ast_format_cmp(), AST_FORMAT_CMP_NOT_EQUAL, ast_format_get_name(), AST_FRAME_VOICE, ast_log, jack_data::audiohook_format, ast_datastore::data, ast_frame_subclass::format, ast_frame::frametype, handle_jack_audio(), LOG_ERROR, LOG_WARNING, NULL, queue_voice_frame(), ast_audiohook::status, and ast_frame::subclass.

Referenced by enable_jack_hook().

00837 {
00838    struct ast_datastore *datastore;
00839    struct jack_data *jack_data;
00840 
00841    if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE)
00842       return 0;
00843 
00844    if (direction != AST_AUDIOHOOK_DIRECTION_READ)
00845       return 0;
00846 
00847    if (frame->frametype != AST_FRAME_VOICE)
00848       return 0;
00849 
00850    ast_channel_lock(chan);
00851 
00852    if (!(datastore = ast_channel_datastore_find(chan, &jack_hook_ds_info, NULL))) {
00853       ast_log(LOG_ERROR, "JACK_HOOK datastore not found for '%s'\n", ast_channel_name(chan));
00854       ast_channel_unlock(chan);
00855       return -1;
00856    }
00857 
00858    jack_data = datastore->data;
00859 
00860    if (ast_format_cmp(frame->subclass.format, jack_data->audiohook_format) == AST_FORMAT_CMP_NOT_EQUAL) {
00861       ast_log(LOG_WARNING, "Expected frame in %s for the audiohook, but got format %s\n",
00862          ast_format_get_name(jack_data->audiohook_format),
00863          ast_format_get_name(frame->subclass.format));
00864       ast_channel_unlock(chan);
00865       return 0;
00866    }
00867 
00868    queue_voice_frame(jack_data, frame);
00869 
00870    handle_jack_audio(chan, jack_data, frame);
00871 
00872    ast_channel_unlock(chan);
00873 
00874    return 0;
00875 }

static void jack_hook_ds_destroy ( void *  data  )  [static]

Definition at line 823 of file app_jack.c.

References destroy_jack_data().

00824 {
00825    struct jack_data *jack_data = data;
00826 
00827    destroy_jack_data(jack_data);
00828 }

static int jack_hook_write ( struct ast_channel chan,
const char *  cmd,
char *  data,
const char *  value 
) [static]

Definition at line 972 of file app_jack.c.

References ast_log, disable_jack_hook(), enable_jack_hook(), LOG_ERROR, and LOG_WARNING.

00974 {
00975    int res;
00976 
00977    if (!chan) {
00978       ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
00979       return -1;
00980    }
00981 
00982    if (!strcasecmp(value, "on"))
00983       res = enable_jack_hook(chan, data);
00984    else if (!strcasecmp(value, "off"))
00985       res = disable_jack_hook(chan);
00986    else {
00987       ast_log(LOG_ERROR, "'%s' is not a valid value for JACK_HOOK()\n", value);
00988       res = -1;
00989    }
00990 
00991    return res;
00992 }

static int jack_process ( jack_nframes_t  nframes,
void *  arg 
) [static]

Definition at line 321 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().

00322 {
00323    struct jack_data *jack_data = arg;
00324    void *input_port_buf, *output_port_buf;
00325 
00326    if (!jack_data->input_resample_factor)
00327       alloc_resampler(jack_data, 1);
00328 
00329    input_port_buf = jack_port_get_buffer(jack_data->input_port, nframes);
00330    handle_input(input_port_buf, nframes, jack_data);
00331 
00332    output_port_buf = jack_port_get_buffer(jack_data->output_port, nframes);
00333    handle_output(output_port_buf, nframes, jack_data);
00334 
00335    return 0;
00336 }

static void jack_shutdown ( void *  arg  )  [static]

Definition at line 338 of file app_jack.c.

References jack_data::stop.

Referenced by init_jack_data().

00339 {
00340    struct jack_data *jack_data = arg;
00341 
00342    jack_data->stop = 1;
00343 }

static const char* jack_status_to_str ( jack_status_t  status  )  [static]

Definition at line 164 of file app_jack.c.

References ARRAY_LEN, and jack_status_table.

Referenced by log_jack_status().

00165 {
00166    int i;
00167 
00168    for (i = 0; i < ARRAY_LEN(jack_status_table); i++) {
00169       if (jack_status_table[i].status == status)
00170          return jack_status_table[i].str;
00171    }
00172 
00173    return "Unknown Error";
00174 }

static int load_module ( void   )  [static]

static void log_jack_status ( const char *  prefix,
jack_status_t  status 
) [static]

Definition at line 176 of file app_jack.c.

References ast_log, ast_str_alloca, ast_str_append(), ast_str_buffer(), ast_str_set(), first, jack_status_to_str(), LOG_NOTICE, and str.

Referenced by init_jack_data().

00177 {
00178    struct ast_str *str = ast_str_alloca(512);
00179    int i, first = 0;
00180 
00181    for (i = 0; i < (sizeof(status) * 8); i++) {
00182       if (!(status & (1 << i)))
00183          continue;
00184 
00185       if (!first) {
00186          ast_str_set(&str, 0, "%s", jack_status_to_str((1 << i)));
00187          first = 1;
00188       } else
00189          ast_str_append(&str, 0, ", %s", jack_status_to_str((1 << i)));
00190    }
00191 
00192    ast_log(LOG_NOTICE, "%s: %s\n", prefix, ast_str_buffer(str));
00193 }

static int queue_voice_frame ( struct jack_data jack_data,
struct ast_frame f 
) [static]

Definition at line 539 of file app_jack.c.

References alloc_resampler(), ARRAY_LEN, ast_log, ast_frame::data, LOG_ERROR, LOG_WARNING, 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().

00540 {
00541    float f_buf[f->samples * 8];
00542    size_t f_buf_used = 0;
00543    int i;
00544    int16_t *s_buf = f->data.ptr;
00545    size_t res;
00546 
00547    memset(f_buf, 0, sizeof(f_buf));
00548 
00549    if (!jack_data->output_resample_factor)
00550       alloc_resampler(jack_data, 0);
00551 
00552    if (jack_data->output_resampler) {
00553       float in_buf[f->samples];
00554       int total_in_buf_used = 0;
00555       int total_out_buf_used = 0;
00556 
00557       memset(in_buf, 0, sizeof(in_buf));
00558 
00559       for (i = 0; i < f->samples; i++)
00560          in_buf[i] = s_buf[i] * (1.0 / SHRT_MAX);
00561 
00562       while (total_in_buf_used < ARRAY_LEN(in_buf)) {
00563          int in_buf_used;
00564          int out_buf_used;
00565 
00566          out_buf_used = resample_process(jack_data->output_resampler,
00567             jack_data->output_resample_factor,
00568             &in_buf[total_in_buf_used], ARRAY_LEN(in_buf) - total_in_buf_used,
00569             0, &in_buf_used,
00570             &f_buf[total_out_buf_used], ARRAY_LEN(f_buf) - total_out_buf_used);
00571 
00572          if (out_buf_used < 0)
00573             break;
00574 
00575          total_out_buf_used += out_buf_used;
00576          total_in_buf_used += in_buf_used;
00577 
00578          if (total_out_buf_used == ARRAY_LEN(f_buf)) {
00579             ast_log(LOG_ERROR, "Output buffer filled ... need to increase its size\n");
00580             break;
00581          }
00582       }
00583 
00584       f_buf_used = total_out_buf_used;
00585       if (f_buf_used > ARRAY_LEN(f_buf))
00586          f_buf_used = ARRAY_LEN(f_buf);
00587    } else {
00588       /* No resampling needed */
00589 
00590       for (i = 0; i < f->samples; i++)
00591          f_buf[i] = s_buf[i] * (1.0 / SHRT_MAX);
00592 
00593       f_buf_used = f->samples;
00594    }
00595 
00596    res = jack_ringbuffer_write(jack_data->output_rb, (const char *) f_buf, f_buf_used * sizeof(float));
00597    if (res != (f_buf_used * sizeof(float))) {
00598       ast_log(LOG_WARNING, "Tried to write %d bytes to the ringbuffer, but only wrote %d\n",
00599          (int) (f_buf_used * sizeof(float)), (int) res);
00600    }
00601    return 0;
00602 }

static int unload_module ( void   )  [static]

Definition at line 1030 of file app_jack.c.

References ast_custom_function_unregister(), and ast_unregister_application().

01031 {
01032    int res;
01033 
01034    res = ast_unregister_application(jack_app);
01035    res |= ast_custom_function_unregister(&jack_hook_function);
01036 
01037    return res;
01038 }


Variable Documentation

const char jack_app[] = "JACK" [static]

Definition at line 119 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 695 of file app_jack.c.

Referenced by handle_options().

Initial value:

 {
   .type = "JACK_HOOK",
   .destroy = jack_hook_ds_destroy,
}

Definition at line 830 of file app_jack.c.

Definition at line 994 of file app_jack.c.

struct { ... } jack_status_table[] [static]

Referenced by jack_status_to_str().

jack_status_t status

Examples:
/tmp/asterisk-trunk/trunk/main/app.c.

Definition at line 148 of file app_jack.c.

Referenced by __ast_pbx_run(), __bt_curdel(), __bt_delete(), __bt_get(), __bt_put(), __bt_seq(), __bt_sync(), __rec_close(), __rec_delete(), __rec_get(), __rec_iput(), __rec_put(), __rec_seq(), __rec_sync(), _child_handler(), _iax2_show_peers_one(), _sip_show_peer(), _sip_show_peers_one(), _stun_show_status(), acf_odbc_read(), acf_odbc_write(), action_extensionstate(), add_eyebeam(), agent_function_read(), agi_exec_full(), answer(), ast_named_acl_reload(), ast_safe_system(), ast_sip_initialize_sorcery_qualify(), ast_sip_session_terminate(), ast_srtp_change_source(), ast_unreal_hangup(), callerid_read(), callerid_write(), chanavail_exec(), channel_fax_cb(), cli_contact_print_body(), complete_dpreply(), connectedline_read(), connectedline_write(), contact_deleted(), contact_status_alloc(), dbm_delete(), dbm_fetch(), dbm_firstkey(), dbm_nextkey(), delete_contact_status(), diversion_incoming_response(), dundi_show_peers(), filestream_destructor(), find_or_create_contact_status(), format_contact_status(), handle_cc_notify(), handle_cdr_pgsql_status(), handle_cli_cdr_mysql_status(), handle_cli_iax2_show_peer(), handle_cli_realtime_mysql_status(), handle_cli_realtime_pgsql_status(), handle_open_receive_channel_ack_message(), handle_outgoing_response(), hsearch(), init_jack_data(), init_start_time(), join_queue(), load_module(), mbl_status_exec(), meetme_stasis_cb(), options_incoming_request(), ospauth_exec(), ospfinished_exec(), osplookup_exec(), ospnext_exec(), parse_status(), party_id_read(), party_id_write(), party_name_read(), party_name_write(), party_number_read(), party_number_write(), party_subaddress_read(), party_subaddress_write(), peers_data_provider_get(), queue_exec(), read_exec(), readexten_exec(), realtime_ldap_status(), rec_rdelete(), redirecting_read(), redirecting_write(), refresh_all_favorite(), ring_entry(), run_ras(), sdp_search(), send_manager_peer_status(), send_options_response(), send_response(), sendtext_exec(), sendurl_exec(), shaun_of_the_dead(), show_entry_history(), sip_outbound_publish_client_alloc(), sip_publication_respond(), sip_publish_client_service_queue(), system_create_resolver_and_set_nameservers(), system_registry_to_ami(), transfer_exec(), update_contact_status(), wait_for_answer(), wait_our_turn(), xmpp_pak_presence(), xmpp_pak_s10n(), xmpp_status_exec(), and xpidf_generate_body_content().

const char* str

Examples:
/tmp/asterisk-trunk/trunk/main/app.c.

Definition at line 149 of file app_jack.c.

Referenced by _free_port_cfg(), acf_curl_helper(), acf_cut_exec(), add_hintdevice(), add_json_object(), add_required_respheader(), add_user_extension(), aoc_charge_type_str(), aoc_charged_item_str(), aoc_rate_type_str(), aoc_scale_str(), aoc_type_of_totaling_str(), aoc_volume_unit_str(), aocmessage_get_unit_entry(), ast_ari_validate_date(), ast_ari_websocket_session_write(), ast_category_get_templates(), ast_cc_agent_set_interfaces_chanvar(), ast_func_read(), ast_hashtab_hash_string(), ast_hashtab_hash_string_nocase(), ast_hashtab_hash_string_sax(), ast_include_rename(), ast_json_vstringf(), ast_sdp_crypto_process(), ast_set_cc_interfaces_chanvar(), ast_sip_global_default_outbound_endpoint(), ast_sockaddr_stringify_fmt(), AST_TEST_DEFINE(), build_nonce(), build_user_routes(), cc_extension_monitor_init(), cc_generic_agent_start_monitoring(), cipher_to_str(), cli_print_body(), collect_names_cb(), contacts_to_str(), custom_log(), dbl_list_expect_reverse(), delayed_method2str(), dial_handle_playtones(), do_magic_pickup(), find_realtime(), format_str_append_auth(), frame_trace_helper(), function_fieldnum_helper(), function_fieldqty_helper(), get_content(), handle_getvariablefull(), handle_playtones(), handle_show_translation_path(), handle_tcptls_connection(), hash_string(), hist_list(), history(), iax_parse_ies(), init_appendbuf(), jack_str(), jingle_new(), list_item_to_str(), localnet_to_str(), localnet_to_vl(), log_jack_status(), mansession_cmp_fn(), match_to_str(), match_to_var_list(), misdn_cfg_get(), misdn_cfg_get_config_string(), misdn_cfg_get_next_port(), misdn_cfg_get_ports_string(), misdn_cfg_is_group_method(), misdn_cfg_is_port_valid(), misdn_to_str_plan(), misdn_to_str_pres(), misdn_to_str_screen(), misdn_to_str_ton(), named_callgroups_to_str(), named_pickupgroups_to_str(), parse_cdata(), pbx_retrieve_variable(), pp_each_extension_helper(), pp_each_user_helper(), process_text_line(), pvt_cause_cmp_fn(), readwavheader(), regex(), replace(), security_event_stasis_cb(), security_event_to_ami_blob(), sendtext_exec(), set_var_to_str(), sip_subscription_to_ami(), smdi_ifaces_cmp_fn(), smdi_mwi_q_cmp_fn(), strreplace(), syslog_log(), term_alloc(), test_2way_function(), test_chan_function(), test_chan_integer(), test_chan_integer_accessor(), test_chan_string(), test_chan_variable(), test_expected_result(), transmit_info_with_aoc(), variable_count_cmp_fn(), and yyparse().


Generated on Thu Apr 16 06:28:31 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6