Wed Oct 28 11:51:23 2009

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 = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, }
static struct ast_module_infoast_module_info = &__mod_info
static char * jack_app = "JACK"
static char * jack_desc
static struct ast_app_option jack_exec_options [128] = { [ 's' ] = { .flag = OPT_SERVER_NAME , .arg_index = OPT_ARG_SERVER_NAME + 1 }, [ 'i' ] = { .flag = OPT_INPUT_PORT , .arg_index = OPT_ARG_INPUT_PORT + 1 }, [ 'o' ] = { .flag = OPT_OUTPUT_PORT , .arg_index = OPT_ARG_OUTPUT_PORT + 1 }, [ 'n' ] = { .flag = OPT_NOSTART_SERVER }, [ '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 []
static char * jack_synopsis


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

00620      {
00621    OPT_SERVER_NAME =    (1 << 0),
00622    OPT_INPUT_PORT =     (1 << 1),
00623    OPT_OUTPUT_PORT =    (1 << 2),
00624    OPT_NOSTART_SERVER = (1 << 3),
00625    OPT_CLIENT_NAME =    (1 << 4),
00626 };

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

00628      {
00629    OPT_ARG_SERVER_NAME,
00630    OPT_ARG_INPUT_PORT,
00631    OPT_ARG_OUTPUT_PORT,
00632    OPT_ARG_CLIENT_NAME,
00633 
00634    /* Must be the last element */
00635    OPT_ARG_ARRAY_SIZE,
00636 };


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 997 of file app_jack.c.

static void __unreg_module ( void   )  [static]

Definition at line 997 of file app_jack.c.

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

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

00161 {
00162    double from_srate, to_srate, jack_srate;
00163    void **resampler;
00164    double *resample_factor;
00165 
00166    if (input && jack_data->input_resampler)
00167       return 0;
00168 
00169    if (!input && jack_data->output_resampler)
00170       return 0;
00171 
00172    jack_srate = jack_get_sample_rate(jack_data->client);
00173 
00174    /* XXX Hard coded 8 kHz */
00175 
00176    to_srate = input ? 8000.0 : jack_srate; 
00177    from_srate = input ? jack_srate : 8000.0;
00178 
00179    resample_factor = input ? &jack_data->input_resample_factor : 
00180       &jack_data->output_resample_factor;
00181 
00182    if (from_srate == to_srate) {
00183       /* Awesome!  The jack sample rate is the same as ours.
00184        * Resampling isn't needed. */
00185       *resample_factor = 1.0;
00186       return 0;
00187    }
00188 
00189    *resample_factor = to_srate / from_srate;
00190 
00191    resampler = input ? &jack_data->input_resampler :
00192       &jack_data->output_resampler;
00193 
00194    if (!(*resampler = resample_open(RESAMPLE_QUALITY, 
00195       *resample_factor, *resample_factor))) {
00196       ast_log(LOG_ERROR, "Failed to open %s resampler\n", 
00197          input ? "input" : "output");
00198       return -1;
00199    }
00200 
00201    return 0;
00202 }

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

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

00313 {
00314    if (jack_data->input_port) {
00315       jack_port_unregister(jack_data->client, jack_data->input_port);
00316       jack_data->input_port = NULL;
00317    }
00318 
00319    if (jack_data->output_port) {
00320       jack_port_unregister(jack_data->client, jack_data->output_port);
00321       jack_data->output_port = NULL;
00322    }
00323 
00324    if (jack_data->client) {
00325       jack_client_close(jack_data->client);
00326       jack_data->client = NULL;
00327    }
00328 
00329    if (jack_data->input_rb) {
00330       jack_ringbuffer_free(jack_data->input_rb);
00331       jack_data->input_rb = NULL;
00332    }
00333 
00334    if (jack_data->output_rb) {
00335       jack_ringbuffer_free(jack_data->output_rb);
00336       jack_data->output_rb = NULL;
00337    }
00338 
00339    if (jack_data->output_resampler) {
00340       resample_close(jack_data->output_resampler);
00341       jack_data->output_resampler = NULL;
00342    }
00343    
00344    if (jack_data->input_resampler) {
00345       resample_close(jack_data->input_resampler);
00346       jack_data->input_resampler = NULL;
00347    }
00348 
00349    if (jack_data->has_audiohook)
00350       ast_audiohook_destroy(&jack_data->audiohook);
00351 
00352    ast_string_field_free_memory(jack_data);
00353 
00354    ast_free(jack_data);
00355 
00356    return NULL;
00357 }

static int disable_jack_hook ( struct ast_channel chan  )  [static]

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

00893 {
00894    struct ast_datastore *datastore;
00895    struct jack_data *jack_data;
00896 
00897    ast_channel_lock(chan);
00898 
00899    if (!(datastore = ast_channel_datastore_find(chan, &jack_hook_ds_info, NULL))) {
00900       ast_channel_unlock(chan);
00901       ast_log(LOG_WARNING, "No JACK_HOOK found to disable\n");
00902       return -1;
00903    }
00904 
00905    ast_channel_datastore_remove(chan, datastore);
00906 
00907    jack_data = datastore->data;
00908    ast_audiohook_detach(&jack_data->audiohook);
00909 
00910    /* Keep the channel locked while we destroy the datastore, so that we can
00911     * ensure that all of the jack stuff is stopped just in case another frame
00912     * tries to come through the audiohook callback. */
00913    ast_datastore_free(datastore);
00914 
00915    ast_channel_unlock(chan);
00916 
00917    return 0;
00918 }

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

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

00832 {
00833    struct ast_datastore *datastore;
00834    struct jack_data *jack_data = NULL;
00835    AST_DECLARE_APP_ARGS(args,
00836       AST_APP_ARG(mode);
00837       AST_APP_ARG(options);
00838    );
00839 
00840    AST_STANDARD_APP_ARGS(args, data);
00841 
00842    ast_channel_lock(chan);
00843 
00844    if ((datastore = ast_channel_datastore_find(chan, &jack_hook_ds_info, NULL))) {
00845       ast_log(LOG_ERROR, "JACK_HOOK already enabled for '%s'\n", chan->name);
00846       goto return_error;
00847    }
00848 
00849    if (ast_strlen_zero(args.mode) || strcasecmp(args.mode, "manipulate")) {
00850       ast_log(LOG_ERROR, "'%s' is not a supported mode.  Only manipulate is supported.\n", 
00851          S_OR(args.mode, "<none>"));
00852       goto return_error;
00853    }
00854 
00855    if (!(jack_data = jack_data_alloc()))
00856       goto return_error;
00857 
00858    if (!ast_strlen_zero(args.options) && handle_options(jack_data, args.options))
00859       goto return_error;
00860 
00861    if (init_jack_data(chan, jack_data))
00862       goto return_error;
00863 
00864    if (!(datastore = ast_datastore_alloc(&jack_hook_ds_info, NULL)))
00865       goto return_error;
00866 
00867    jack_data->has_audiohook = 1;
00868    ast_audiohook_init(&jack_data->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "JACK_HOOK");
00869    jack_data->audiohook.manipulate_callback = jack_hook_callback;
00870 
00871    datastore->data = jack_data;
00872 
00873    if (ast_audiohook_attach(chan, &jack_data->audiohook))
00874       goto return_error;
00875 
00876    if (ast_channel_datastore_add(chan, datastore))
00877       goto return_error;
00878 
00879    ast_channel_unlock(chan);
00880 
00881    return 0;
00882 
00883 return_error:
00884    ast_channel_unlock(chan);
00885 
00886    if (jack_data)
00887       destroy_jack_data(jack_data);
00888 
00889    return -1;
00890 }

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

00212 {
00213    short s_buf[nframes];
00214    float *in_buf = buf;
00215    size_t res;
00216    int i;
00217    size_t write_len = sizeof(s_buf);
00218 
00219    if (jack_data->input_resampler) {
00220       int total_in_buf_used = 0;
00221       int total_out_buf_used = 0;
00222       float f_buf[nframes + 1];
00223 
00224       memset(f_buf, 0, sizeof(f_buf));
00225 
00226       while (total_in_buf_used < nframes) {
00227          int in_buf_used;
00228          int out_buf_used;
00229 
00230          out_buf_used = resample_process(jack_data->input_resampler,
00231             jack_data->input_resample_factor,
00232             &in_buf[total_in_buf_used], nframes - total_in_buf_used,
00233             0, &in_buf_used,
00234             &f_buf[total_out_buf_used], ARRAY_LEN(f_buf) - total_out_buf_used);
00235 
00236          if (out_buf_used < 0)
00237             break;
00238 
00239          total_out_buf_used += out_buf_used;
00240          total_in_buf_used += in_buf_used;
00241    
00242          if (total_out_buf_used == ARRAY_LEN(f_buf)) {
00243             ast_log(LOG_ERROR, "Output buffer filled ... need to increase its size, "
00244                "nframes '%d', total_out_buf_used '%d'\n", nframes, total_out_buf_used);
00245             break;
00246          }
00247       }
00248 
00249       for (i = 0; i < total_out_buf_used; i++)
00250          s_buf[i] = f_buf[i] * (SHRT_MAX / 1.0);
00251       
00252       write_len = total_out_buf_used * sizeof(int16_t);
00253    } else {
00254       /* No resampling needed */
00255 
00256       for (i = 0; i < nframes; i++)
00257          s_buf[i] = in_buf[i] * (SHRT_MAX / 1.0);
00258    }
00259 
00260    res = jack_ringbuffer_write(jack_data->input_rb, (const char *) s_buf, write_len);
00261    if (res != write_len) {
00262       ast_debug(2, "Tried to write %d bytes to the ringbuffer, but only wrote %d\n",
00263          (int) sizeof(s_buf), (int) res);
00264    }
00265 }

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

00574 {  
00575    short buf[160];
00576    struct ast_frame f = {
00577       .frametype = AST_FRAME_VOICE,
00578       .subclass = AST_FORMAT_SLINEAR,
00579       .src = "JACK",
00580       .data.ptr = buf,
00581       .datalen = sizeof(buf),
00582       .samples = ARRAY_LEN(buf),
00583    };
00584 
00585    for (;;) {
00586       size_t res, read_len;
00587       char *read_buf;
00588 
00589       read_len = out_frame ? out_frame->datalen : sizeof(buf);
00590       read_buf = out_frame ? out_frame->data.ptr : buf;
00591 
00592       res = jack_ringbuffer_read_space(jack_data->input_rb);
00593 
00594       if (res < read_len) {
00595          /* Not enough data ready for another frame, move on ... */
00596          if (out_frame) {
00597             ast_debug(1, "Sending an empty frame for the JACK_HOOK\n");
00598             memset(out_frame->data.ptr, 0, out_frame->datalen);
00599          }
00600          break;
00601       }
00602 
00603       res = jack_ringbuffer_read(jack_data->input_rb, (char *) read_buf, read_len);
00604 
00605       if (res < read_len) {
00606          ast_log(LOG_ERROR, "Error reading from ringbuffer, even though it said there was enough data\n");
00607          break;
00608       }
00609 
00610       if (out_frame) {
00611          /* If an output frame was provided, then we just want to fill up the
00612           * buffer in that frame and return. */
00613          break;
00614       }
00615 
00616       ast_write(chan, &f);
00617    }
00618 }

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

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

Referenced by enable_jack_hook(), and jack_exec().

00665 {
00666    struct ast_flags options = { 0, };
00667    char *option_args[OPT_ARG_ARRAY_SIZE];
00668    char *options_str;
00669 
00670    options_str = ast_strdupa(__options_str);
00671 
00672    ast_app_parse_options(jack_exec_options, &options, option_args, options_str);
00673 
00674    if (ast_test_flag(&options, OPT_SERVER_NAME)) {
00675       if (!ast_strlen_zero(option_args[OPT_ARG_SERVER_NAME]))
00676          ast_string_field_set(jack_data, server_name, option_args[OPT_ARG_SERVER_NAME]);
00677       else {
00678          ast_log(LOG_ERROR, "A server name must be provided with the s() option\n");
00679          return -1;
00680       }
00681    }
00682 
00683    if (ast_test_flag(&options, OPT_CLIENT_NAME)) {
00684       if (!ast_strlen_zero(option_args[OPT_ARG_CLIENT_NAME]))
00685          ast_string_field_set(jack_data, client_name, option_args[OPT_ARG_CLIENT_NAME]);
00686       else {
00687          ast_log(LOG_ERROR, "A client name must be provided with the c() option\n");
00688          return -1;
00689       }
00690    }
00691 
00692    if (ast_test_flag(&options, OPT_INPUT_PORT)) {
00693       if (!ast_strlen_zero(option_args[OPT_ARG_INPUT_PORT]))
00694          ast_string_field_set(jack_data, connect_input_port, option_args[OPT_ARG_INPUT_PORT]);
00695       else {
00696          ast_log(LOG_ERROR, "A name must be provided with the i() option\n");
00697          return -1;
00698       }
00699    }
00700 
00701    if (ast_test_flag(&options, OPT_OUTPUT_PORT)) {
00702       if (!ast_strlen_zero(option_args[OPT_ARG_OUTPUT_PORT]))
00703          ast_string_field_set(jack_data, connect_output_port, option_args[OPT_ARG_OUTPUT_PORT]);
00704       else {
00705          ast_log(LOG_ERROR, "A name must be provided with the o() option\n");
00706          return -1;
00707       }
00708    }
00709 
00710    jack_data->no_start_server = ast_test_flag(&options, OPT_NOSTART_SERVER) ? 1 : 0;
00711 
00712    return 0;
00713 }

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

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

Referenced by jack_process().

00275 {
00276    size_t res, len;
00277 
00278    len = nframes * sizeof(float);
00279 
00280    res = jack_ringbuffer_read(jack_data->output_rb, buf, len);
00281 
00282    if (len != res) {
00283       ast_debug(2, "Wanted %d bytes to send to the output port, "
00284          "but only got %d\n", (int) len, (int) res);
00285    }
00286 }

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

Definition at line 359 of file app_jack.c.

References ast_channel_lock, ast_channel_unlock, ast_debug, ast_log(), ast_strdupa, ast_strlen_zero(), jack_data::client, jack_data::client_name, jack_data::connect_input_port, jack_data::connect_output_port, free, jack_data::input_port, jack_data::input_rb, jack_process(), jack_shutdown(), LOG_ERROR, log_jack_status(), ast_channel::name, jack_data::no_start_server, jack_data::output_port, jack_data::output_rb, RINGBUFFER_SIZE, jack_data::server_name, and status.

Referenced by enable_jack_hook(), and jack_exec().

00360 {
00361    const char *client_name;
00362    jack_status_t status = 0;
00363    jack_options_t jack_options = JackNullOption;
00364 
00365    if (!ast_strlen_zero(jack_data->client_name)) {
00366       client_name = jack_data->client_name;
00367    } else {
00368       ast_channel_lock(chan);
00369       client_name = ast_strdupa(chan->name);
00370       ast_channel_unlock(chan);
00371    }
00372 
00373    if (!(jack_data->output_rb = jack_ringbuffer_create(RINGBUFFER_SIZE)))
00374       return -1;
00375 
00376    if (!(jack_data->input_rb = jack_ringbuffer_create(RINGBUFFER_SIZE)))
00377       return -1;
00378 
00379    if (jack_data->no_start_server)
00380       jack_options |= JackNoStartServer;
00381 
00382    if (!ast_strlen_zero(jack_data->server_name)) {
00383       jack_options |= JackServerName;
00384       jack_data->client = jack_client_open(client_name, jack_options, &status,
00385          jack_data->server_name);
00386    } else {
00387       jack_data->client = jack_client_open(client_name, jack_options, &status);
00388    }
00389 
00390    if (status)
00391       log_jack_status("Client Open Status", status);
00392 
00393    if (!jack_data->client)
00394       return -1;
00395 
00396    jack_data->input_port = jack_port_register(jack_data->client, "input",
00397       JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput | JackPortIsTerminal, 0);
00398    if (!jack_data->input_port) {
00399       ast_log(LOG_ERROR, "Failed to create input port for jack port\n");
00400       return -1;
00401    }
00402 
00403    jack_data->output_port = jack_port_register(jack_data->client, "output",
00404       JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput | JackPortIsTerminal, 0);
00405    if (!jack_data->output_port) {
00406       ast_log(LOG_ERROR, "Failed to create output port for jack port\n");
00407       return -1;
00408    }
00409 
00410    if (jack_set_process_callback(jack_data->client, jack_process, jack_data)) {
00411       ast_log(LOG_ERROR, "Failed to register process callback with jack client\n");
00412       return -1;
00413    }
00414 
00415    jack_on_shutdown(jack_data->client, jack_shutdown, jack_data);
00416 
00417    if (jack_activate(jack_data->client)) {
00418       ast_log(LOG_ERROR, "Unable to activate jack client\n");
00419       return -1;
00420    }
00421 
00422    while (!ast_strlen_zero(jack_data->connect_input_port)) {
00423       const char **ports;
00424       int i;
00425 
00426       ports = jack_get_ports(jack_data->client, jack_data->connect_input_port,
00427          NULL, JackPortIsInput);
00428 
00429       if (!ports) {
00430          ast_log(LOG_ERROR, "No input port matching '%s' was found\n",
00431             jack_data->connect_input_port);
00432          break;
00433       }
00434 
00435       for (i = 0; ports[i]; i++) {
00436          ast_debug(1, "Found port '%s' that matched specified input port '%s'\n",
00437             ports[i], jack_data->connect_input_port);
00438       }
00439 
00440       if (jack_connect(jack_data->client, jack_port_name(jack_data->output_port), ports[0])) {
00441          ast_log(LOG_ERROR, "Failed to connect '%s' to '%s'\n", ports[0],
00442             jack_port_name(jack_data->output_port));
00443       } else {
00444          ast_debug(1, "Connected '%s' to '%s'\n", ports[0],
00445             jack_port_name(jack_data->output_port));
00446       }
00447 
00448       free((void *) ports);
00449 
00450       break;
00451    }
00452 
00453    while (!ast_strlen_zero(jack_data->connect_output_port)) {
00454       const char **ports;
00455       int i;
00456 
00457       ports = jack_get_ports(jack_data->client, jack_data->connect_output_port,
00458          NULL, JackPortIsOutput);
00459 
00460       if (!ports) {
00461          ast_log(LOG_ERROR, "No output port matching '%s' was found\n",
00462             jack_data->connect_output_port);
00463          break;
00464       }
00465 
00466       for (i = 0; ports[i]; i++) {
00467          ast_debug(1, "Found port '%s' that matched specified output port '%s'\n",
00468             ports[i], jack_data->connect_output_port);
00469       }
00470 
00471       if (jack_connect(jack_data->client, ports[0], jack_port_name(jack_data->input_port))) {
00472          ast_log(LOG_ERROR, "Failed to connect '%s' to '%s'\n", ports[0],
00473             jack_port_name(jack_data->input_port));
00474       } else {
00475          ast_debug(1, "Connected '%s' to '%s'\n", ports[0],
00476             jack_port_name(jack_data->input_port));
00477       }
00478 
00479       free((void *) ports);
00480 
00481       break;
00482    }
00483 
00484    return 0;
00485 }

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

Definition at line 646 of file app_jack.c.

References ast_calloc, ast_free, and ast_string_field_init.

Referenced by enable_jack_hook(), and jack_exec().

00647 {
00648    struct jack_data *jack_data;
00649 
00650    if (!(jack_data = ast_calloc(1, sizeof(*jack_data))))
00651       return NULL;
00652    
00653    if (ast_string_field_init(jack_data, 32)) {
00654       ast_free(jack_data);
00655       return NULL;
00656    }
00657 
00658    return jack_data;
00659 }

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

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

00716 {
00717    struct jack_data *jack_data;
00718    AST_DECLARE_APP_ARGS(args,
00719       AST_APP_ARG(options);
00720    );
00721 
00722    if (!(jack_data = jack_data_alloc()))
00723       return -1;
00724 
00725    args.options = data;
00726 
00727    if (!ast_strlen_zero(args.options) && handle_options(jack_data, args.options)) {
00728       destroy_jack_data(jack_data);
00729       return -1;
00730    }
00731 
00732    if (init_jack_data(chan, jack_data)) {
00733       destroy_jack_data(jack_data);
00734       return -1;
00735    }
00736 
00737    if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
00738       destroy_jack_data(jack_data);
00739       return -1;
00740    }
00741 
00742    if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
00743       destroy_jack_data(jack_data);
00744       return -1;
00745    }
00746 
00747    while (!jack_data->stop) {
00748       struct ast_frame *f;
00749 
00750       ast_waitfor(chan, -1);
00751 
00752       f = ast_read(chan);
00753       if (!f) {
00754          jack_data->stop = 1;
00755          continue;
00756       }
00757 
00758       switch (f->frametype) {
00759       case AST_FRAME_CONTROL:
00760          if (f->subclass == AST_CONTROL_HANGUP)
00761             jack_data->stop = 1;
00762          break;
00763       case AST_FRAME_VOICE:
00764          queue_voice_frame(jack_data, f);
00765       default:
00766          break;
00767       }
00768 
00769       ast_frfree(f);
00770 
00771       handle_jack_audio(chan, jack_data, NULL);
00772    }
00773 
00774    jack_data = destroy_jack_data(jack_data);
00775 
00776    return 0;
00777 }

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

00793 {
00794    struct ast_datastore *datastore;
00795    struct jack_data *jack_data;
00796 
00797    if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE)
00798       return 0;
00799 
00800    if (direction != AST_AUDIOHOOK_DIRECTION_READ)
00801       return 0;
00802 
00803    if (frame->frametype != AST_FRAME_VOICE)
00804       return 0;
00805 
00806    if (frame->subclass != AST_FORMAT_SLINEAR) {
00807       ast_log(LOG_WARNING, "Expected frame in SLINEAR for the audiohook, but got format %d\n",
00808          frame->subclass);
00809       return 0;
00810    }
00811 
00812    ast_channel_lock(chan);
00813 
00814    if (!(datastore = ast_channel_datastore_find(chan, &jack_hook_ds_info, NULL))) {
00815       ast_log(LOG_ERROR, "JACK_HOOK datastore not found for '%s'\n", chan->name);
00816       ast_channel_unlock(chan);
00817       return -1;
00818    }
00819 
00820    jack_data = datastore->data;
00821 
00822    queue_voice_frame(jack_data, frame);
00823 
00824    handle_jack_audio(chan, jack_data, frame);
00825 
00826    ast_channel_unlock(chan);
00827 
00828    return 0;
00829 }

static void jack_hook_ds_destroy ( void *  data  )  [static]

Definition at line 779 of file app_jack.c.

References destroy_jack_data().

00780 {
00781    struct jack_data *jack_data = data;
00782 
00783    destroy_jack_data(jack_data);
00784 }

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

Definition at line 920 of file app_jack.c.

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

00922 {
00923    int res;
00924 
00925    if (!strcasecmp(value, "on"))
00926       res = enable_jack_hook(chan, data);
00927    else if (!strcasecmp(value, "off"))
00928       res = disable_jack_hook(chan);
00929    else {
00930       ast_log(LOG_ERROR, "'%s' is not a valid value for JACK_HOOK()\n", value);  
00931       res = -1;
00932    }
00933 
00934    return res;
00935 }

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

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

00289 {
00290    struct jack_data *jack_data = arg;
00291    void *input_port_buf, *output_port_buf;
00292 
00293    if (!jack_data->input_resample_factor)
00294       alloc_resampler(jack_data, 1);
00295 
00296    input_port_buf = jack_port_get_buffer(jack_data->input_port, nframes);
00297    handle_input(input_port_buf, nframes, jack_data);
00298 
00299    output_port_buf = jack_port_get_buffer(jack_data->output_port, nframes);
00300    handle_output(output_port_buf, nframes, jack_data);
00301 
00302    return 0;
00303 }

static void jack_shutdown ( void *  arg  )  [static]

Definition at line 305 of file app_jack.c.

References jack_data::stop.

Referenced by init_jack_data().

00306 {
00307    struct jack_data *jack_data = arg;
00308 
00309    jack_data->stop = 1;
00310 }

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

Definition at line 129 of file app_jack.c.

References ARRAY_LEN, and jack_status_table.

Referenced by log_jack_status().

00130 {
00131    int i;
00132 
00133    for (i = 0; i < ARRAY_LEN(jack_status_table); i++) {
00134       if (jack_status_table[i].status == status)
00135          return jack_status_table[i].str;
00136    }
00137 
00138    return "Unknown Error";
00139 }

static int load_module ( void   )  [static]

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

Definition at line 141 of file app_jack.c.

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

Referenced by init_jack_data().

00142 {
00143    struct ast_str *str = ast_str_alloca(512);
00144    int i, first = 0;
00145 
00146    for (i = 0; i < (sizeof(status) * 8); i++) {
00147       if (!(status & (1 << i)))
00148          continue;
00149 
00150       if (!first) {
00151          ast_str_set(&str, 0, "%s", jack_status_to_str((1 << i)));
00152          first = 1;
00153       } else
00154          ast_str_append(&str, 0, ", %s", jack_status_to_str((1 << i)));
00155    }
00156    
00157    ast_log(LOG_NOTICE, "%s: %s\n", prefix, str->str);
00158 }

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

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

00488 {
00489    float f_buf[f->samples * 8];
00490    size_t f_buf_used = 0;
00491    int i;
00492    int16_t *s_buf = f->data.ptr;
00493    size_t res;
00494 
00495    memset(f_buf, 0, sizeof(f_buf));
00496 
00497    if (!jack_data->output_resample_factor)
00498       alloc_resampler(jack_data, 0);
00499 
00500    if (jack_data->output_resampler) {
00501       float in_buf[f->samples];
00502       int total_in_buf_used = 0;
00503       int total_out_buf_used = 0;
00504 
00505       memset(in_buf, 0, sizeof(in_buf));
00506 
00507       for (i = 0; i < f->samples; i++)
00508          in_buf[i] = s_buf[i] * (1.0 / SHRT_MAX);
00509 
00510       while (total_in_buf_used < ARRAY_LEN(in_buf)) {
00511          int in_buf_used;
00512          int out_buf_used;
00513 
00514          out_buf_used = resample_process(jack_data->output_resampler, 
00515             jack_data->output_resample_factor,
00516             &in_buf[total_in_buf_used], ARRAY_LEN(in_buf) - total_in_buf_used, 
00517             0, &in_buf_used, 
00518             &f_buf[total_out_buf_used], ARRAY_LEN(f_buf) - total_out_buf_used);
00519 
00520          if (out_buf_used < 0)
00521             break;
00522 
00523          total_out_buf_used += out_buf_used;
00524          total_in_buf_used += in_buf_used;
00525 
00526          if (total_out_buf_used == ARRAY_LEN(f_buf)) {
00527             ast_log(LOG_ERROR, "Output buffer filled ... need to increase its size\n");
00528             break;
00529          }
00530       }
00531 
00532       f_buf_used = total_out_buf_used;
00533       if (f_buf_used > ARRAY_LEN(f_buf))
00534          f_buf_used = ARRAY_LEN(f_buf);
00535    } else {
00536       /* No resampling needed */
00537 
00538       for (i = 0; i < f->samples; i++)
00539          f_buf[i] = s_buf[i] * (1.0 / SHRT_MAX);
00540 
00541       f_buf_used = f->samples;
00542    }
00543 
00544    res = jack_ringbuffer_write(jack_data->output_rb, (const char *) f_buf, f_buf_used * sizeof(float));
00545    if (res != (f_buf_used * sizeof(float))) {
00546       ast_debug(2, "Tried to write %d bytes to the ringbuffer, but only wrote %d\n",
00547          (int) (f_buf_used * sizeof(float)), (int) res);
00548    }
00549 
00550    return 0;
00551 }

static int unload_module ( void   )  [static]

Definition at line 973 of file app_jack.c.

References ast_custom_function_unregister(), and ast_unregister_application().

00974 {
00975    int res;
00976 
00977    res = ast_unregister_application(jack_app);
00978    res |= ast_custom_function_unregister(&jack_hook_function);
00979 
00980    return res;
00981 }


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 = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, } [static]

Definition at line 997 of file app_jack.c.

Definition at line 997 of file app_jack.c.

char* jack_app = "JACK" [static]

Definition at line 77 of file app_jack.c.

char* jack_desc [static]

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

Referenced by handle_options().

Initial value:

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

Definition at line 786 of file app_jack.c.

Definition at line 937 of file app_jack.c.

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

Referenced by jack_status_to_str().

char* jack_synopsis [static]

Initial value:

 
"JACK (Jack Audio Connection Kit) Application"

Definition at line 78 of file app_jack.c.

jack_status_t status

const char* str


Generated on Wed Oct 28 11:51:23 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6