Mon Jun 27 16:50:58 2011

Asterisk developer's documentation


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"

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_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 struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .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 = "8586c2a7d357cb591cc3a6607a8f62d1" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, }
static struct ast_module_infoast_module_info = &__mod_info
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 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().


Enumeration Type Documentation

anonymous enum

Enumerator:
OPT_SERVER_NAME 
OPT_INPUT_PORT 
OPT_OUTPUT_PORT 
OPT_NOSTART_SERVER 
OPT_CLIENT_NAME 

Definition at line 649 of file app_jack.c.

00649      {
00650    OPT_SERVER_NAME =    (1 << 0),
00651    OPT_INPUT_PORT =     (1 << 1),
00652    OPT_OUTPUT_PORT =    (1 << 2),
00653    OPT_NOSTART_SERVER = (1 << 3),
00654    OPT_CLIENT_NAME =    (1 << 4),
00655 };

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

00657      {
00658    OPT_ARG_SERVER_NAME,
00659    OPT_ARG_INPUT_PORT,
00660    OPT_ARG_OUTPUT_PORT,
00661    OPT_ARG_CLIENT_NAME,
00662 
00663    /* Must be the last element */
00664    OPT_ARG_ARRAY_SIZE,
00665 };


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 1017 of file app_jack.c.

static void __unreg_module ( void   )  [static]

Definition at line 1017 of file app_jack.c.

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

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

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

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

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

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

static int disable_jack_hook ( struct ast_channel chan  )  [static]

Definition at line 912 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, jack_hook_ds_info, and LOG_WARNING.

Referenced by jack_hook_write().

00913 {
00914    struct ast_datastore *datastore;
00915    struct jack_data *jack_data;
00916 
00917    ast_channel_lock(chan);
00918 
00919    if (!(datastore = ast_channel_datastore_find(chan, &jack_hook_ds_info, NULL))) {
00920       ast_channel_unlock(chan);
00921       ast_log(LOG_WARNING, "No JACK_HOOK found to disable\n");
00922       return -1;
00923    }
00924 
00925    ast_channel_datastore_remove(chan, datastore);
00926 
00927    jack_data = datastore->data;
00928    ast_audiohook_detach(&jack_data->audiohook);
00929 
00930    /* Keep the channel locked while we destroy the datastore, so that we can
00931     * ensure that all of the jack stuff is stopped just in case another frame
00932     * tries to come through the audiohook callback. */
00933    ast_datastore_free(datastore);
00934 
00935    ast_channel_unlock(chan);
00936 
00937    return 0;
00938 }

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

Definition at line 851 of file app_jack.c.

References args, AST_APP_ARG, ast_audiohook_attach(), ast_audiohook_init(), AST_AUDIOHOOK_TYPE_MANIPULATE, ast_channel_datastore_add(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_datastore_alloc, AST_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(), jack_hook_ds_info, LOG_ERROR, ast_audiohook::manipulate_callback, ast_channel::name, and S_OR.

Referenced by jack_hook_write().

00852 {
00853    struct ast_datastore *datastore;
00854    struct jack_data *jack_data = NULL;
00855    AST_DECLARE_APP_ARGS(args,
00856       AST_APP_ARG(mode);
00857       AST_APP_ARG(options);
00858    );
00859 
00860    AST_STANDARD_APP_ARGS(args, data);
00861 
00862    ast_channel_lock(chan);
00863 
00864    if ((datastore = ast_channel_datastore_find(chan, &jack_hook_ds_info, NULL))) {
00865       ast_log(LOG_ERROR, "JACK_HOOK already enabled for '%s'\n", chan->name);
00866       goto return_error;
00867    }
00868 
00869    if (ast_strlen_zero(args.mode) || strcasecmp(args.mode, "manipulate")) {
00870       ast_log(LOG_ERROR, "'%s' is not a supported mode.  Only manipulate is supported.\n",
00871          S_OR(args.mode, "<none>"));
00872       goto return_error;
00873    }
00874 
00875    if (!(jack_data = jack_data_alloc()))
00876       goto return_error;
00877 
00878    if (!ast_strlen_zero(args.options) && handle_options(jack_data, args.options))
00879       goto return_error;
00880 
00881    if (init_jack_data(chan, jack_data))
00882       goto return_error;
00883 
00884    if (!(datastore = ast_datastore_alloc(&jack_hook_ds_info, NULL)))
00885       goto return_error;
00886 
00887    jack_data->has_audiohook = 1;
00888    ast_audiohook_init(&jack_data->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "JACK_HOOK");
00889    jack_data->audiohook.manipulate_callback = jack_hook_callback;
00890 
00891    datastore->data = jack_data;
00892 
00893    if (ast_audiohook_attach(chan, &jack_data->audiohook))
00894       goto return_error;
00895 
00896    if (ast_channel_datastore_add(chan, datastore))
00897       goto return_error;
00898 
00899    ast_channel_unlock(chan);
00900 
00901    return 0;
00902 
00903 return_error:
00904    ast_channel_unlock(chan);
00905 
00906    if (jack_data)
00907       destroy_jack_data(jack_data);
00908 
00909    return -1;
00910 }

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 239 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().

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

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

References ARRAY_LEN, ast_debug, AST_FORMAT_SLINEAR, AST_FRAME_VOICE, ast_log(), ast_write(), ast_frame::data, ast_frame::datalen, f, jack_data::input_rb, LOG_ERROR, ast_frame::ptr, and ast_frame::samples.

Referenced by jack_exec(), and jack_hook_callback().

00603 {
00604    short buf[160];
00605    struct ast_frame f = {
00606       .frametype = AST_FRAME_VOICE,
00607       .subclass.codec = AST_FORMAT_SLINEAR,
00608       .src = "JACK",
00609       .data.ptr = buf,
00610       .datalen = sizeof(buf),
00611       .samples = ARRAY_LEN(buf),
00612    };
00613 
00614    for (;;) {
00615       size_t res, read_len;
00616       char *read_buf;
00617 
00618       read_len = out_frame ? out_frame->datalen : sizeof(buf);
00619       read_buf = out_frame ? out_frame->data.ptr : buf;
00620 
00621       res = jack_ringbuffer_read_space(jack_data->input_rb);
00622 
00623       if (res < read_len) {
00624          /* Not enough data ready for another frame, move on ... */
00625          if (out_frame) {
00626             ast_debug(1, "Sending an empty frame for the JACK_HOOK\n");
00627             memset(out_frame->data.ptr, 0, out_frame->datalen);
00628          }
00629          break;
00630       }
00631 
00632       res = jack_ringbuffer_read(jack_data->input_rb, (char *) read_buf, read_len);
00633 
00634       if (res < read_len) {
00635          ast_log(LOG_ERROR, "Error reading from ringbuffer, even though it said there was enough data\n");
00636          break;
00637       }
00638 
00639       if (out_frame) {
00640          /* If an output frame was provided, then we just want to fill up the
00641           * buffer in that frame and return. */
00642          break;
00643       }
00644 
00645       ast_write(chan, &f);
00646    }
00647 }

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 689 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 enable_jack_hook(), and jack_exec().

00690 {
00691    struct ast_flags options = { 0, };
00692    char *option_args[OPT_ARG_ARRAY_SIZE];
00693    char *options_str;
00694 
00695    options_str = ast_strdupa(__options_str);
00696 
00697    ast_app_parse_options(jack_exec_options, &options, option_args, options_str);
00698 
00699    if (ast_test_flag(&options, OPT_SERVER_NAME)) {
00700       if (!ast_strlen_zero(option_args[OPT_ARG_SERVER_NAME]))
00701          ast_string_field_set(jack_data, server_name, option_args[OPT_ARG_SERVER_NAME]);
00702       else {
00703          ast_log(LOG_ERROR, "A server name must be provided with the s() option\n");
00704          return -1;
00705       }
00706    }
00707 
00708    if (ast_test_flag(&options, OPT_CLIENT_NAME)) {
00709       if (!ast_strlen_zero(option_args[OPT_ARG_CLIENT_NAME]))
00710          ast_string_field_set(jack_data, client_name, option_args[OPT_ARG_CLIENT_NAME]);
00711       else {
00712          ast_log(LOG_ERROR, "A client name must be provided with the c() option\n");
00713          return -1;
00714       }
00715    }
00716 
00717    if (ast_test_flag(&options, OPT_INPUT_PORT)) {
00718       if (!ast_strlen_zero(option_args[OPT_ARG_INPUT_PORT]))
00719          ast_string_field_set(jack_data, connect_input_port, option_args[OPT_ARG_INPUT_PORT]);
00720       else {
00721          ast_log(LOG_ERROR, "A name must be provided with the i() option\n");
00722          return -1;
00723       }
00724    }
00725 
00726    if (ast_test_flag(&options, OPT_OUTPUT_PORT)) {
00727       if (!ast_strlen_zero(option_args[OPT_ARG_OUTPUT_PORT]))
00728          ast_string_field_set(jack_data, connect_output_port, option_args[OPT_ARG_OUTPUT_PORT]);
00729       else {
00730          ast_log(LOG_ERROR, "A name must be provided with the o() option\n");
00731          return -1;
00732       }
00733    }
00734 
00735    jack_data->no_start_server = ast_test_flag(&options, OPT_NOSTART_SERVER) ? 1 : 0;
00736 
00737    return 0;
00738 }

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

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

Referenced by jack_process().

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

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

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

00389 {
00390    const char *client_name;
00391    jack_status_t status = 0;
00392    jack_options_t jack_options = JackNullOption;
00393 
00394    if (!ast_strlen_zero(jack_data->client_name)) {
00395       client_name = jack_data->client_name;
00396    } else {
00397       ast_channel_lock(chan);
00398       client_name = ast_strdupa(chan->name);
00399       ast_channel_unlock(chan);
00400    }
00401 
00402    if (!(jack_data->output_rb = jack_ringbuffer_create(RINGBUFFER_SIZE)))
00403       return -1;
00404 
00405    if (!(jack_data->input_rb = jack_ringbuffer_create(RINGBUFFER_SIZE)))
00406       return -1;
00407 
00408    if (jack_data->no_start_server)
00409       jack_options |= JackNoStartServer;
00410 
00411    if (!ast_strlen_zero(jack_data->server_name)) {
00412       jack_options |= JackServerName;
00413       jack_data->client = jack_client_open(client_name, jack_options, &status,
00414          jack_data->server_name);
00415    } else {
00416       jack_data->client = jack_client_open(client_name, jack_options, &status);
00417    }
00418 
00419    if (status)
00420       log_jack_status("Client Open Status", status);
00421 
00422    if (!jack_data->client)
00423       return -1;
00424 
00425    jack_data->input_port = jack_port_register(jack_data->client, "input",
00426       JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput | JackPortIsTerminal, 0);
00427    if (!jack_data->input_port) {
00428       ast_log(LOG_ERROR, "Failed to create input port for jack port\n");
00429       return -1;
00430    }
00431 
00432    jack_data->output_port = jack_port_register(jack_data->client, "output",
00433       JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput | JackPortIsTerminal, 0);
00434    if (!jack_data->output_port) {
00435       ast_log(LOG_ERROR, "Failed to create output port for jack port\n");
00436       return -1;
00437    }
00438 
00439    if (jack_set_process_callback(jack_data->client, jack_process, jack_data)) {
00440       ast_log(LOG_ERROR, "Failed to register process callback with jack client\n");
00441       return -1;
00442    }
00443 
00444    jack_on_shutdown(jack_data->client, jack_shutdown, jack_data);
00445 
00446    if (jack_activate(jack_data->client)) {
00447       ast_log(LOG_ERROR, "Unable to activate jack client\n");
00448       return -1;
00449    }
00450 
00451    while (!ast_strlen_zero(jack_data->connect_input_port)) {
00452       const char **ports;
00453       int i;
00454 
00455       ports = jack_get_ports(jack_data->client, jack_data->connect_input_port,
00456          NULL, JackPortIsInput);
00457 
00458       if (!ports) {
00459          ast_log(LOG_ERROR, "No input port matching '%s' was found\n",
00460             jack_data->connect_input_port);
00461          break;
00462       }
00463 
00464       for (i = 0; ports[i]; i++) {
00465          ast_debug(1, "Found port '%s' that matched specified input port '%s'\n",
00466             ports[i], jack_data->connect_input_port);
00467       }
00468 
00469       if (jack_connect(jack_data->client, jack_port_name(jack_data->output_port), ports[0])) {
00470          ast_log(LOG_ERROR, "Failed to connect '%s' to '%s'\n", ports[0],
00471             jack_port_name(jack_data->output_port));
00472       } else {
00473          ast_debug(1, "Connected '%s' to '%s'\n", ports[0],
00474             jack_port_name(jack_data->output_port));
00475       }
00476 
00477       free((void *) ports);
00478 
00479       break;
00480    }
00481 
00482    while (!ast_strlen_zero(jack_data->connect_output_port)) {
00483       const char **ports;
00484       int i;
00485 
00486       ports = jack_get_ports(jack_data->client, jack_data->connect_output_port,
00487          NULL, JackPortIsOutput);
00488 
00489       if (!ports) {
00490          ast_log(LOG_ERROR, "No output port matching '%s' was found\n",
00491             jack_data->connect_output_port);
00492          break;
00493       }
00494 
00495       for (i = 0; ports[i]; i++) {
00496          ast_debug(1, "Found port '%s' that matched specified output port '%s'\n",
00497             ports[i], jack_data->connect_output_port);
00498       }
00499 
00500       if (jack_connect(jack_data->client, ports[0], jack_port_name(jack_data->input_port))) {
00501          ast_log(LOG_ERROR, "Failed to connect '%s' to '%s'\n", ports[0],
00502             jack_port_name(jack_data->input_port));
00503       } else {
00504          ast_debug(1, "Connected '%s' to '%s'\n", ports[0],
00505             jack_port_name(jack_data->input_port));
00506       }
00507 
00508       free((void *) ports);
00509 
00510       break;
00511    }
00512 
00513    return 0;
00514 }

static struct jack_data* jack_data_alloc ( void   )  [static]

Definition at line 675 of file app_jack.c.

References ast_calloc_with_stringfields.

Referenced by enable_jack_hook(), and jack_exec().

00676 {
00677    struct jack_data *jack_data;
00678 
00679    if (!(jack_data = ast_calloc_with_stringfields(1, struct jack_data, 32))) {
00680       return NULL;
00681    }
00682 
00683    return jack_data;
00684 }

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

Definition at line 740 of file app_jack.c.

References AST_CONTROL_HANGUP, AST_FORMAT_SLINEAR, AST_FRAME_CONTROL, AST_FRAME_VOICE, ast_frfree, ast_read(), ast_set_read_format(), ast_set_write_format(), ast_strlen_zero(), ast_waitfor(), destroy_jack_data(), f, handle_jack_audio(), handle_options(), init_jack_data(), jack_data_alloc(), queue_voice_frame(), and jack_data::stop.

Referenced by load_module().

00741 {
00742    struct jack_data *jack_data;
00743 
00744    if (!(jack_data = jack_data_alloc()))
00745       return -1;
00746 
00747    if (!ast_strlen_zero(data) && handle_options(jack_data, data)) {
00748       destroy_jack_data(jack_data);
00749       return -1;
00750    }
00751 
00752    if (init_jack_data(chan, jack_data)) {
00753       destroy_jack_data(jack_data);
00754       return -1;
00755    }
00756 
00757    if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
00758       destroy_jack_data(jack_data);
00759       return -1;
00760    }
00761 
00762    if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
00763       destroy_jack_data(jack_data);
00764       return -1;
00765    }
00766 
00767    while (!jack_data->stop) {
00768       struct ast_frame *f;
00769 
00770       ast_waitfor(chan, -1);
00771 
00772       f = ast_read(chan);
00773       if (!f) {
00774          jack_data->stop = 1;
00775          continue;
00776       }
00777 
00778       switch (f->frametype) {
00779       case AST_FRAME_CONTROL:
00780          if (f->subclass.integer == AST_CONTROL_HANGUP)
00781             jack_data->stop = 1;
00782          break;
00783       case AST_FRAME_VOICE:
00784          queue_voice_frame(jack_data, f);
00785       default:
00786          break;
00787       }
00788 
00789       ast_frfree(f);
00790 
00791       handle_jack_audio(chan, jack_data, NULL);
00792    }
00793 
00794    jack_data = destroy_jack_data(jack_data);
00795 
00796    return 0;
00797 }

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

References AST_AUDIOHOOK_DIRECTION_READ, AST_AUDIOHOOK_STATUS_DONE, ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, AST_FORMAT_SLINEAR, AST_FRAME_VOICE, ast_getformatname(), ast_log(), jack_data::audiohook, ast_frame_subclass::codec, 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().

00813 {
00814    struct ast_datastore *datastore;
00815    struct jack_data *jack_data;
00816 
00817    if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE)
00818       return 0;
00819 
00820    if (direction != AST_AUDIOHOOK_DIRECTION_READ)
00821       return 0;
00822 
00823    if (frame->frametype != AST_FRAME_VOICE)
00824       return 0;
00825 
00826    if (frame->subclass.codec != AST_FORMAT_SLINEAR) {
00827       ast_log(LOG_WARNING, "Expected frame in SLINEAR for the audiohook, but got format %s\n",
00828          ast_getformatname(frame->subclass.codec));
00829       return 0;
00830    }
00831 
00832    ast_channel_lock(chan);
00833 
00834    if (!(datastore = ast_channel_datastore_find(chan, &jack_hook_ds_info, NULL))) {
00835       ast_log(LOG_ERROR, "JACK_HOOK datastore not found for '%s'\n", chan->name);
00836       ast_channel_unlock(chan);
00837       return -1;
00838    }
00839 
00840    jack_data = datastore->data;
00841 
00842    queue_voice_frame(jack_data, frame);
00843 
00844    handle_jack_audio(chan, jack_data, frame);
00845 
00846    ast_channel_unlock(chan);
00847 
00848    return 0;
00849 }

static void jack_hook_ds_destroy ( void *  data  )  [static]

Definition at line 799 of file app_jack.c.

References destroy_jack_data().

00800 {
00801    struct jack_data *jack_data = data;
00802 
00803    destroy_jack_data(jack_data);
00804 }

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

Definition at line 940 of file app_jack.c.

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

00942 {
00943    int res;
00944 
00945    if (!strcasecmp(value, "on"))
00946       res = enable_jack_hook(chan, data);
00947    else if (!strcasecmp(value, "off"))
00948       res = disable_jack_hook(chan);
00949    else {
00950       ast_log(LOG_ERROR, "'%s' is not a valid value for JACK_HOOK()\n", value);
00951       res = -1;
00952    }
00953 
00954    return res;
00955 }

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

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

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

static void jack_shutdown ( void *  arg  )  [static]

Definition at line 334 of file app_jack.c.

References jack_data::stop.

Referenced by init_jack_data().

00335 {
00336    struct jack_data *jack_data = arg;
00337 
00338    jack_data->stop = 1;
00339 }

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

Definition at line 158 of file app_jack.c.

References ARRAY_LEN, and jack_status_table.

Referenced by log_jack_status().

00159 {
00160    int i;
00161 
00162    for (i = 0; i < ARRAY_LEN(jack_status_table); i++) {
00163       if (jack_status_table[i].status == status)
00164          return jack_status_table[i].str;
00165    }
00166 
00167    return "Unknown Error";
00168 }

static int load_module ( void   )  [static]

Definition at line 1003 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(), jack_exec(), and jack_hook_function.

01004 {
01005    if (ast_register_application_xml(jack_app, jack_exec)) {
01006       return AST_MODULE_LOAD_DECLINE;
01007    }
01008 
01009    if (ast_custom_function_register(&jack_hook_function)) {
01010       ast_unregister_application(jack_app);
01011       return AST_MODULE_LOAD_DECLINE;
01012    }
01013 
01014    return AST_MODULE_LOAD_SUCCESS;
01015 }

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

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

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

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

Definition at line 516 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_exec(), and jack_hook_callback().

00517 {
00518    float f_buf[f->samples * 8];
00519    size_t f_buf_used = 0;
00520    int i;
00521    int16_t *s_buf = f->data.ptr;
00522    size_t res;
00523 
00524    memset(f_buf, 0, sizeof(f_buf));
00525 
00526    if (!jack_data->output_resample_factor)
00527       alloc_resampler(jack_data, 0);
00528 
00529    if (jack_data->output_resampler) {
00530       float in_buf[f->samples];
00531       int total_in_buf_used = 0;
00532       int total_out_buf_used = 0;
00533 
00534       memset(in_buf, 0, sizeof(in_buf));
00535 
00536       for (i = 0; i < f->samples; i++)
00537          in_buf[i] = s_buf[i] * (1.0 / SHRT_MAX);
00538 
00539       while (total_in_buf_used < ARRAY_LEN(in_buf)) {
00540          int in_buf_used;
00541          int out_buf_used;
00542 
00543          out_buf_used = resample_process(jack_data->output_resampler,
00544             jack_data->output_resample_factor,
00545             &in_buf[total_in_buf_used], ARRAY_LEN(in_buf) - total_in_buf_used,
00546             0, &in_buf_used,
00547             &f_buf[total_out_buf_used], ARRAY_LEN(f_buf) - total_out_buf_used);
00548 
00549          if (out_buf_used < 0)
00550             break;
00551 
00552          total_out_buf_used += out_buf_used;
00553          total_in_buf_used += in_buf_used;
00554 
00555          if (total_out_buf_used == ARRAY_LEN(f_buf)) {
00556             ast_log(LOG_ERROR, "Output buffer filled ... need to increase its size\n");
00557             break;
00558          }
00559       }
00560 
00561       f_buf_used = total_out_buf_used;
00562       if (f_buf_used > ARRAY_LEN(f_buf))
00563          f_buf_used = ARRAY_LEN(f_buf);
00564    } else {
00565       /* No resampling needed */
00566 
00567       for (i = 0; i < f->samples; i++)
00568          f_buf[i] = s_buf[i] * (1.0 / SHRT_MAX);
00569 
00570       f_buf_used = f->samples;
00571    }
00572 
00573    res = jack_ringbuffer_write(jack_data->output_rb, (const char *) f_buf, f_buf_used * sizeof(float));
00574    if (res != (f_buf_used * sizeof(float))) {
00575       ast_debug(2, "Tried to write %d bytes to the ringbuffer, but only wrote %d\n",
00576          (int) (f_buf_used * sizeof(float)), (int) res);
00577    }
00578 
00579    return 0;
00580 }

static int unload_module ( void   )  [static]

Definition at line 993 of file app_jack.c.

References ast_custom_function_unregister(), ast_unregister_application(), and jack_hook_function.

00994 {
00995    int res;
00996 
00997    res = ast_unregister_application(jack_app);
00998    res |= ast_custom_function_unregister(&jack_hook_function);
00999 
01000    return res;
01001 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .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 = "8586c2a7d357cb591cc3a6607a8f62d1" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, } [static]

Definition at line 1017 of file app_jack.c.

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 1017 of file app_jack.c.

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

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

Referenced by handle_options().

struct ast_datastore_info jack_hook_ds_info [static]

Initial value:

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

Definition at line 806 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]

Definition at line 957 of file app_jack.c.

Referenced by load_module(), and unload_module().

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

Referenced by jack_status_to_str().

jack_status_t status

Definition at line 142 of file app_jack.c.

Referenced by __iax2_show_peers(), _child_handler(), _sip_show_peer(), _sip_show_peers(), acf_odbc_read(), acf_odbc_write(), action_agents(), action_extensionstate(), agi_exec_full(), aji_handle_presence(), aji_handle_subscribe(), aji_show_clients(), aji_status_exec(), ast_safe_system(), ast_srtp_change_source(), build_status(), build_timeout(), callerid_read(), callerid_write(), chanavail_exec(), complete_dpreply(), connectedline_read(), connectedline_write(), dundi_show_peers(), function_agent(), handle_cc_notify(), handle_cli_iax2_show_peer(), handle_cli_realtime_pgsql_status(), handle_open_receive_channel_ack_message(), init_jack_data(), join_queue(), local_hangup(), manager_iax2_show_peer_list(), ospauth_exec(), ospfinished_exec(), osplookup_exec(), ospnext_exec(), parse_status(), party_id_read(), party_id_write(), party_name_read(), party_name_write(), party_number_read(), party_number_write(), party_subaddress_read(), party_subaddress_write(), peers_data_provider_get(), queue_exec(), read_exec(), readexten_exec(), realtime_ldap_status(), redirecting_read(), redirecting_write(), ring_entry(), rpt(), run_ras(), sendtext_exec(), sendurl_exec(), shaun_of_the_dead(), show_entry_history(), sig_pri_cli_show_span(), sig_pri_cli_show_spans(), transfer_exec(), wait_for_answer(), and wait_our_turn().

const char* str

Definition at line 143 of file app_jack.c.

Referenced by _free_port_cfg(), acf_curl_helper(), acf_cut_exec(), action_status(), add_ie(), add_ipv4_ie(), add_publish_event(), add_subscribe_event(), add_timeval_ie(), add_user_extension(), alloc_event(), amixer_max(), 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(), append_backtrace_information(), append_ie(), append_ies(), append_lock_information(), ast_cc_agent_set_interfaces_chanvar(), ast_event_subscribe(), ast_func_read(), ast_func_read2(), ast_hashtab_hash_string(), ast_hashtab_hash_string_nocase(), ast_hashtab_hash_string_sax(), ast_parse_digest(), ast_set_cc_interfaces_chanvar(), ast_sockaddr_stringify_fmt(), ast_str_expr(), ast_str_get_encoded_str(), ast_str_retrieve_variable(), ast_term_color_code(), ast_translate_path_to_str(), base64_helper(), blacklist_read2(), build_cc_interfaces_chanvar(), build_user_routes(), cc_extension_monitor_init(), cc_generic_agent_start_monitoring(), cc_unique_append(), custom_log(), dial_handle_playtones(), do_magic_pickup(), encode_timestamp(), find_realtime(), frame_trace_helper(), function_fieldnum_helper(), function_fieldqty_helper(), get_pidf_body(), handle_cli_core_show_translation(), handle_getvariablefull(), handle_playtones(), handle_show_locks(), handle_statechange(), handle_tcptls_connection(), hash_string(), hid_device_init(), hid_device_mklist(), iax_parse_ies(), import_helper(), import_read2(), init_appendbuf(), jingle_new(), log_jack_status(), log_show_lock(), mansession_cmp_fn(), match_ie_val(), misdn_cfg_get(), misdn_cfg_get_config_string(), misdn_cfg_get_next_port(), misdn_cfg_get_ports_string(), misdn_cfg_is_group_method(), misdn_cfg_is_port_valid(), misdn_to_str_plan(), misdn_to_str_pres(), misdn_to_str_screen(), misdn_to_str_ton(), parse_cdata(), pbx_retrieve_variable(), pp_each_extension_helper(), pp_each_user_helper(), process_text_line(), regex(), replace(), security_event_cb(), sendtext_exec(), set2(), setamixer(), substitute_escapes(), syslog_log(), transmit_info_with_aoc(), usb_get_usbdev(), variable_count_cmp_fn(), and yyparse().


Generated on Mon Jun 27 16:50:58 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7