Fri Nov 12 11:49:56 2010

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

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "JACK Interface" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "0901e4e500243c855563a2d78b0c03e4" , .load = load_module, .unload = unload_module, }
static struct ast_module_infoast_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 []

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.

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

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

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

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


Function Documentation

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

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

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

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

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

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

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

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

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

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(), jack_data::input_rb, jack_data::input_resample_factor, jack_data::input_resampler, and LOG_ERROR.

Referenced by jack_process().

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

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

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

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

References ast_app_parse_options(), ast_log(), 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().

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

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

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

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

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

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

00675 {
00676    struct jack_data *jack_data;
00677 
00678    if (!(jack_data = ast_calloc(1, sizeof(*jack_data))))
00679       return NULL;
00680    
00681    if (ast_string_field_init(jack_data, 32)) {
00682       ast_free(jack_data);
00683       return NULL;
00684    }
00685 
00686    return jack_data;
00687 }

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

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

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

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

static void jack_hook_ds_destroy ( void *  data  )  [static]

Definition at line 807 of file app_jack.c.

References destroy_jack_data().

00808 {
00809    struct jack_data *jack_data = data;
00810 
00811    destroy_jack_data(jack_data);
00812 }

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.

00950 {
00951    int res;
00952 
00953    if (!strcasecmp(value, "on"))
00954       res = enable_jack_hook(chan, data);
00955    else if (!strcasecmp(value, "off"))
00956       res = disable_jack_hook(chan);
00957    else {
00958       ast_log(LOG_ERROR, "'%s' is not a valid value for JACK_HOOK()\n", value);  
00959       res = -1;
00960    }
00961 
00962    return res;
00963 }

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

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

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

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

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

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

static int load_module ( void   )  [static]
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, and str.

Referenced by init_jack_data().

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

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

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

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

static int unload_module ( void   )  [static]

Definition at line 1001 of file app_jack.c.

References ast_custom_function_unregister(), and ast_unregister_application().

01002 {
01003    int res;
01004 
01005    res = ast_unregister_application(jack_app);
01006    res |= ast_custom_function_unregister(&jack_hook_function);
01007 
01008    return res;
01009 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "JACK Interface" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "0901e4e500243c855563a2d78b0c03e4" , .load = load_module, .unload = unload_module, } [static]

Definition at line 1025 of file app_jack.c.

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

Initial value:
 {
   .type = "JACK_HOOK",
   .destroy = jack_hook_ds_destroy,
}

Definition at line 814 of file app_jack.c.

Definition at line 965 of file app_jack.c.

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

Referenced by jack_status_to_str().

jack_status_t status
const char* str

Generated by  doxygen 1.6.2