Wed Oct 28 11:45:45 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) }
enum  { OPT_ARG_SERVER_NAME, OPT_ARG_INPUT_PORT, OPT_ARG_OUTPUT_PORT, 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 const struct
ast_module_info
ast_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 }, }
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 

Definition at line 613 of file app_jack.c.

00613      {
00614    OPT_SERVER_NAME =    (1 << 0),
00615    OPT_INPUT_PORT =     (1 << 1),
00616    OPT_OUTPUT_PORT =    (1 << 2),
00617    OPT_NOSTART_SERVER = (1 << 3),
00618 };

anonymous enum

Enumerator:
OPT_ARG_SERVER_NAME 
OPT_ARG_INPUT_PORT 
OPT_ARG_OUTPUT_PORT 
OPT_ARG_ARRAY_SIZE 

Definition at line 620 of file app_jack.c.

00620      {
00621    OPT_ARG_SERVER_NAME,
00622    OPT_ARG_INPUT_PORT,
00623    OPT_ARG_OUTPUT_PORT,
00624    /* Must be the last element */
00625    OPT_ARG_ARRAY_SIZE,
00626 };


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 976 of file app_jack.c.

static void __unreg_module ( void   )  [static]

Definition at line 976 of file app_jack.c.

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

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

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

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

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

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

static int disable_jack_hook ( struct ast_channel chan  )  [static]

Definition at line 872 of file app_jack.c.

References ast_audiohook_detach(), ast_channel_datastore_find(), ast_channel_datastore_free(), ast_channel_datastore_remove(), ast_channel_lock, ast_channel_unlock, ast_log(), jack_data::audiohook, ast_datastore::data, and LOG_WARNING.

Referenced by jack_hook_write().

00873 {
00874    struct ast_datastore *datastore;
00875    struct jack_data *jack_data;
00876 
00877    ast_channel_lock(chan);
00878 
00879    if (!(datastore = ast_channel_datastore_find(chan, &jack_hook_ds_info, NULL))) {
00880       ast_channel_unlock(chan);
00881       ast_log(LOG_WARNING, "No JACK_HOOK found to disable\n");
00882       return -1;
00883    }
00884 
00885    ast_channel_datastore_remove(chan, datastore);
00886 
00887    jack_data = datastore->data;
00888    ast_audiohook_detach(&jack_data->audiohook);
00889 
00890    /* Keep the channel locked while we destroy the datastore, so that we can
00891     * ensure that all of the jack stuff is stopped just in case another frame
00892     * tries to come through the audiohook callback. */
00893    ast_channel_datastore_free(datastore);
00894 
00895    ast_channel_unlock(chan);
00896 
00897    return 0;
00898 }

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

Definition at line 811 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_alloc(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, 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().

00812 {
00813    struct ast_datastore *datastore;
00814    struct jack_data *jack_data = NULL;
00815    AST_DECLARE_APP_ARGS(args,
00816       AST_APP_ARG(mode);
00817       AST_APP_ARG(options);
00818    );
00819 
00820    AST_STANDARD_APP_ARGS(args, data);
00821 
00822    ast_channel_lock(chan);
00823 
00824    if ((datastore = ast_channel_datastore_find(chan, &jack_hook_ds_info, NULL))) {
00825       ast_log(LOG_ERROR, "JACK_HOOK already enabled for '%s'\n", chan->name);
00826       goto return_error;
00827    }
00828 
00829    if (ast_strlen_zero(args.mode) || strcasecmp(args.mode, "manipulate")) {
00830       ast_log(LOG_ERROR, "'%s' is not a supported mode.  Only manipulate is supported.\n", 
00831          S_OR(args.mode, "<none>"));
00832       goto return_error;
00833    }
00834 
00835    if (!(jack_data = jack_data_alloc()))
00836       goto return_error;
00837 
00838    if (!ast_strlen_zero(args.options) && handle_options(jack_data, args.options))
00839       goto return_error;
00840 
00841    if (init_jack_data(chan, jack_data))
00842       goto return_error;
00843 
00844    if (!(datastore = ast_channel_datastore_alloc(&jack_hook_ds_info, NULL)))
00845       goto return_error;
00846 
00847    jack_data->has_audiohook = 1;
00848    ast_audiohook_init(&jack_data->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "JACK_HOOK");
00849    jack_data->audiohook.manipulate_callback = jack_hook_callback;
00850 
00851    datastore->data = jack_data;
00852 
00853    if (ast_audiohook_attach(chan, &jack_data->audiohook))
00854       goto return_error;
00855 
00856    if (ast_channel_datastore_add(chan, datastore))
00857       goto return_error;
00858 
00859    ast_channel_unlock(chan);
00860 
00861    return 0;
00862 
00863 return_error:
00864    ast_channel_unlock(chan);
00865 
00866    if (jack_data)
00867       destroy_jack_data(jack_data);
00868 
00869    return -1;
00870 }

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

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

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 565 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, and ast_frame::samples.

Referenced by jack_exec(), and jack_hook_callback().

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

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 653 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_INPUT_PORT, OPT_ARG_OUTPUT_PORT, OPT_ARG_SERVER_NAME, OPT_INPUT_PORT, OPT_NOSTART_SERVER, OPT_OUTPUT_PORT, OPT_SERVER_NAME, and option_args.

Referenced by enable_jack_hook(), and jack_exec().

00654 {
00655    struct ast_flags options = { 0, };
00656    char *option_args[OPT_ARG_ARRAY_SIZE];
00657    char *options_str;
00658 
00659    options_str = ast_strdupa(__options_str);
00660 
00661    ast_app_parse_options(jack_exec_options, &options, option_args, options_str);
00662 
00663    if (ast_test_flag(&options, OPT_SERVER_NAME)) {
00664       if (!ast_strlen_zero(option_args[OPT_ARG_SERVER_NAME]))
00665          ast_string_field_set(jack_data, server_name, option_args[OPT_ARG_SERVER_NAME]);
00666       else {
00667          ast_log(LOG_ERROR, "A server name must be provided with the s() option\n");
00668          return -1;
00669       }
00670    }
00671 
00672    if (ast_test_flag(&options, OPT_INPUT_PORT)) {
00673       if (!ast_strlen_zero(option_args[OPT_ARG_INPUT_PORT]))
00674          ast_string_field_set(jack_data, connect_input_port, option_args[OPT_ARG_INPUT_PORT]);
00675       else {
00676          ast_log(LOG_ERROR, "A name must be provided with the i() option\n");
00677          return -1;
00678       }
00679    }
00680 
00681    if (ast_test_flag(&options, OPT_OUTPUT_PORT)) {
00682       if (!ast_strlen_zero(option_args[OPT_ARG_OUTPUT_PORT]))
00683          ast_string_field_set(jack_data, connect_output_port, option_args[OPT_ARG_OUTPUT_PORT]);
00684       else {
00685          ast_log(LOG_ERROR, "A name must be provided with the o() option\n");
00686          return -1;
00687       }
00688    }
00689 
00690    jack_data->no_start_server = ast_test_flag(&options, OPT_NOSTART_SERVER) ? 1 : 0;
00691 
00692    return 0;
00693 }

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

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

Referenced by jack_process().

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

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

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

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

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

Definition at line 635 of file app_jack.c.

References ast_calloc, ast_free, and ast_string_field_init.

Referenced by enable_jack_hook(), and jack_exec().

00636 {
00637    struct jack_data *jack_data;
00638 
00639    if (!(jack_data = ast_calloc(1, sizeof(*jack_data))))
00640       return NULL;
00641    
00642    if (ast_string_field_init(jack_data, 32)) {
00643       ast_free(jack_data);
00644       return NULL;
00645    }
00646 
00647    return jack_data;
00648 }

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

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

00696 {
00697    struct jack_data *jack_data;
00698    AST_DECLARE_APP_ARGS(args,
00699       AST_APP_ARG(options);
00700    );
00701 
00702    if (!(jack_data = jack_data_alloc()))
00703       return -1;
00704 
00705    args.options = data;
00706 
00707    if (!ast_strlen_zero(args.options) && handle_options(jack_data, args.options)) {
00708       destroy_jack_data(jack_data);
00709       return -1;
00710    }
00711 
00712    if (init_jack_data(chan, jack_data)) {
00713       destroy_jack_data(jack_data);
00714       return -1;
00715    }
00716 
00717    if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
00718       destroy_jack_data(jack_data);
00719       return -1;
00720    }
00721 
00722    if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
00723       destroy_jack_data(jack_data);
00724       return -1;
00725    }
00726 
00727    while (!jack_data->stop) {
00728       struct ast_frame *f;
00729 
00730       ast_waitfor(chan, -1);
00731 
00732       f = ast_read(chan);
00733       if (!f) {
00734          jack_data->stop = 1;
00735          continue;
00736       }
00737 
00738       switch (f->frametype) {
00739       case AST_FRAME_CONTROL:
00740          if (f->subclass == AST_CONTROL_HANGUP)
00741             jack_data->stop = 1;
00742          break;
00743       case AST_FRAME_VOICE:
00744          queue_voice_frame(jack_data, f);
00745       default:
00746          break;
00747       }
00748 
00749       ast_frfree(f);
00750 
00751       handle_jack_audio(chan, jack_data, NULL);
00752    }
00753 
00754    jack_data = destroy_jack_data(jack_data);
00755 
00756    return 0;
00757 }

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

00773 {
00774    struct ast_datastore *datastore;
00775    struct jack_data *jack_data;
00776 
00777    if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE)
00778       return 0;
00779 
00780    if (direction != AST_AUDIOHOOK_DIRECTION_READ)
00781       return 0;
00782 
00783    if (frame->frametype != AST_FRAME_VOICE)
00784       return 0;
00785 
00786    if (frame->subclass != AST_FORMAT_SLINEAR) {
00787       ast_log(LOG_WARNING, "Expected frame in SLINEAR for the audiohook, but got format %d\n",
00788          frame->subclass);
00789       return 0;
00790    }
00791 
00792    ast_channel_lock(chan);
00793 
00794    if (!(datastore = ast_channel_datastore_find(chan, &jack_hook_ds_info, NULL))) {
00795       ast_log(LOG_ERROR, "JACK_HOOK datastore not found for '%s'\n", chan->name);
00796       ast_channel_unlock(chan);
00797       return -1;
00798    }
00799 
00800    jack_data = datastore->data;
00801 
00802    queue_voice_frame(jack_data, frame);
00803 
00804    handle_jack_audio(chan, jack_data, frame);
00805 
00806    ast_channel_unlock(chan);
00807 
00808    return 0;
00809 }

static void jack_hook_ds_destroy ( void *  data  )  [static]

Definition at line 759 of file app_jack.c.

References destroy_jack_data().

00760 {
00761    struct jack_data *jack_data = data;
00762 
00763    destroy_jack_data(jack_data);
00764 }

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

Definition at line 900 of file app_jack.c.

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

00902 {
00903    int res;
00904 
00905    if (!strcasecmp(value, "on"))
00906       res = enable_jack_hook(chan, data);
00907    else if (!strcasecmp(value, "off"))
00908       res = disable_jack_hook(chan);
00909    else {
00910       ast_log(LOG_ERROR, "'%s' is not a valid value for JACK_HOOK()\n", value);  
00911       res = -1;
00912    }
00913 
00914    return res;
00915 }

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

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

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

static void jack_shutdown ( void *  arg  )  [static]

Definition at line 302 of file app_jack.c.

References jack_data::stop.

Referenced by init_jack_data().

00303 {
00304    struct jack_data *jack_data = arg;
00305 
00306    jack_data->stop = 1;
00307 }

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

Definition at line 126 of file app_jack.c.

References ARRAY_LEN, and jack_status_table.

Referenced by log_jack_status().

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

static int load_module ( void   )  [static]

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

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

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

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

Definition at line 480 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, and ast_frame::samples.

Referenced by jack_exec(), and jack_hook_callback().

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

static int unload_module ( void   )  [static]

Definition at line 953 of file app_jack.c.

References ast_custom_function_unregister(), and ast_unregister_application().

00954 {
00955    int res;
00956 
00957    res = ast_unregister_application(jack_app);
00958    res |= ast_custom_function_unregister(&jack_hook_function);
00959 
00960    return res;
00961 }


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

const struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 976 of file app_jack.c.

char* jack_app = "JACK" [static]

Definition at line 75 of file app_jack.c.

char* jack_desc [static]

Definition at line 78 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 }, } [static]

Definition at line 633 of file app_jack.c.

Referenced by handle_options().

Initial value:

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

Definition at line 766 of file app_jack.c.

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

jack_status_t status

const char* str


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