Fri Aug 17 00:17:21 2018

Asterisk developer's documentation


app_jack.c File Reference

Jack Application. More...

#include "asterisk.h"
#include <limits.h>
#include <jack/jack.h>
#include <jack/ringbuffer.h>
#include <libresample.h>
#include "asterisk/module.h"
#include "asterisk/channel.h"
#include "asterisk/strings.h"
#include "asterisk/lock.h"
#include "asterisk/app.h"
#include "asterisk/pbx.h"
#include "asterisk/audiohook.h"

Go to the source code of this file.

Data Structures

struct  jack_data

Defines

#define COMMON_OPTIONS
 Common options between the Jack() app and JACK_HOOK() function.
#define RESAMPLE_QUALITY   1
#define RINGBUFFER_SIZE   16384

Enumerations

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

Functions

static int alloc_resampler (struct jack_data *jack_data, int input)
 AST_APP_OPTIONS (jack_exec_options, BEGIN_OPTIONS AST_APP_OPTION_ARG('s', OPT_SERVER_NAME, OPT_ARG_SERVER_NAME), AST_APP_OPTION_ARG('i', OPT_INPUT_PORT, OPT_ARG_INPUT_PORT), AST_APP_OPTION_ARG('o', OPT_OUTPUT_PORT, OPT_ARG_OUTPUT_PORT), AST_APP_OPTION('n', OPT_NOSTART_SERVER), AST_APP_OPTION_ARG('c', OPT_CLIENT_NAME, OPT_ARG_CLIENT_NAME), END_OPTIONS)
 AST_MODULE_INFO_STANDARD (ASTERISK_GPL_KEY,"JACK Interface")
static struct jack_datadestroy_jack_data (struct jack_data *jack_data)
static int disable_jack_hook (struct ast_channel *chan)
static int enable_jack_hook (struct ast_channel *chan, char *data)
static void handle_input (void *buf, jack_nframes_t nframes, struct jack_data *jack_data)
 Handle jack input port.
static void handle_jack_audio (struct ast_channel *chan, struct jack_data *jack_data, struct ast_frame *out_frame)
 handle jack audio
static int handle_options (struct jack_data *jack_data, const char *__options_str)
static void handle_output (void *buf, jack_nframes_t nframes, struct jack_data *jack_data)
 Handle jack output port.
static int init_jack_data (struct ast_channel *chan, struct jack_data *jack_data)
static struct jack_datajack_data_alloc (void)
static int jack_exec (struct ast_channel *chan, const char *data)
static int jack_hook_callback (struct ast_audiohook *audiohook, struct ast_channel *chan, struct ast_frame *frame, enum ast_audiohook_direction direction)
static void jack_hook_ds_destroy (void *data)
static int jack_hook_write (struct ast_channel *chan, const char *cmd, char *data, const char *value)
static int jack_process (jack_nframes_t nframes, void *arg)
static void jack_shutdown (void *arg)
static const char * jack_status_to_str (jack_status_t status)
static int load_module (void)
static void log_jack_status (const char *prefix, jack_status_t status)
static int queue_voice_frame (struct jack_data *jack_data, struct ast_frame *f)
static int unload_module (void)

Variables

static const char jack_app [] = "JACK"
static struct ast_datastore_info jack_hook_ds_info
static struct ast_custom_function jack_hook_function
struct {
   jack_status_t   status
   const char *   str
jack_status_table []

Detailed Description

Jack Application.

Author:
Russell Bryant <russell@digium.com>

This is an application to connect an Asterisk channel to an input and output jack port so that the audio can be processed through another application, or to play audio from another application.

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

Definition in file app_jack.c.


Define Documentation

#define COMMON_OPTIONS

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

Definition at line 67 of file app_jack.c.

#define RESAMPLE_QUALITY   1

Definition at line 62 of file app_jack.c.

Referenced by alloc_resampler().

#define RINGBUFFER_SIZE   16384

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

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

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

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


Function Documentation

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

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

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

AST_APP_OPTIONS ( jack_exec_options  ,
BEGIN_OPTIONS   AST_APP_OPTION_ARG's', OPT_SERVER_NAME, OPT_ARG_SERVER_NAME,
AST_APP_OPTION_ARG('i', OPT_INPUT_PORT, OPT_ARG_INPUT_PORT)  ,
AST_APP_OPTION_ARG('o', OPT_OUTPUT_PORT, OPT_ARG_OUTPUT_PORT)  ,
AST_APP_OPTION('n', OPT_NOSTART_SERVER)  ,
AST_APP_OPTION_ARG('c', OPT_CLIENT_NAME, OPT_ARG_CLIENT_NAME)  ,
END_OPTIONS   
)
AST_MODULE_INFO_STANDARD ( ASTERISK_GPL_KEY  ,
"JACK Interface"   
)
static struct jack_data* destroy_jack_data ( struct jack_data jack_data  )  [static, read]

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

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

static int disable_jack_hook ( struct ast_channel chan  )  [static]

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

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

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

Definition at line 854 of file app_jack.c.

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

Referenced by jack_hook_write().

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

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

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

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

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

Referenced by jack_exec(), and jack_hook_callback().

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

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

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

Referenced by enable_jack_hook(), and jack_exec().

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

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

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

Referenced by jack_process().

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

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

Definition at line 389 of file app_jack.c.

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

Referenced by enable_jack_hook(), and jack_exec().

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

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

Definition at line 676 of file app_jack.c.

References ast_calloc_with_stringfields.

Referenced by enable_jack_hook(), and jack_exec().

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

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

Definition at line 741 of file app_jack.c.

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

Referenced by load_module().

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

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

References AST_AUDIOHOOK_DIRECTION_READ, AST_AUDIOHOOK_STATUS_DONE, ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, AST_FORMAT_SLINEAR, AST_FRAME_VOICE, ast_getformatname(), ast_log(), ast_frame_subclass::codec, ast_datastore::data, ast_frame::frametype, handle_jack_audio(), LOG_ERROR, LOG_WARNING, queue_voice_frame(), ast_audiohook::status, and ast_frame::subclass.

Referenced by enable_jack_hook().

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

static void jack_hook_ds_destroy ( void *  data  )  [static]

Definition at line 802 of file app_jack.c.

References destroy_jack_data().

00803 {
00804    struct jack_data *jack_data = data;
00805 
00806    destroy_jack_data(jack_data);
00807 }

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

Definition at line 949 of file app_jack.c.

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

00951 {
00952    int res;
00953 
00954    if (!chan) {
00955       ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
00956       return -1;
00957    }
00958 
00959    if (!strcasecmp(value, "on"))
00960       res = enable_jack_hook(chan, data);
00961    else if (!strcasecmp(value, "off"))
00962       res = disable_jack_hook(chan);
00963    else {
00964       ast_log(LOG_ERROR, "'%s' is not a valid value for JACK_HOOK()\n", value);
00965       res = -1;
00966    }
00967 
00968    return res;
00969 }

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

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

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

static void jack_shutdown ( void *  arg  )  [static]

Definition at line 335 of file app_jack.c.

References jack_data::stop.

Referenced by init_jack_data().

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

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

Definition at line 159 of file app_jack.c.

References ARRAY_LEN, and jack_status_table.

Referenced by log_jack_status().

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

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

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

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

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

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

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

static int unload_module ( void   )  [static]

Definition at line 1007 of file app_jack.c.

References ast_custom_function_unregister(), and ast_unregister_application().

01008 {
01009    int res;
01010 
01011    res = ast_unregister_application(jack_app);
01012    res |= ast_custom_function_unregister(&jack_hook_function);
01013 
01014    return res;
01015 }


Variable Documentation

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

Definition at line 117 of file app_jack.c.

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

Definition at line 809 of file app_jack.c.

Definition at line 971 of file app_jack.c.

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

Referenced by jack_status_to_str().

jack_status_t status
const char* str

Definition at line 144 of file app_jack.c.

Referenced by _free_port_cfg(), acf_curl_helper(), acf_cut_exec(), action_status(), add_ie(), add_ipv4_ie(), add_publish_event(), add_required_respheader(), add_subscribe_event(), add_timeval_ie(), add_user_extension(), alloc_event(), aoc_charge_type_str(), aoc_charged_item_str(), aoc_rate_type_str(), aoc_scale_str(), aoc_type_of_totaling_str(), aoc_volume_unit_str(), aocmessage_get_unit_entry(), ast_cc_agent_set_interfaces_chanvar(), ast_event_subscribe(), ast_func_read(), ast_hashtab_hash_string(), ast_hashtab_hash_string_nocase(), ast_hashtab_hash_string_sax(), ast_include_rename(), ast_set_cc_interfaces_chanvar(), ast_sockaddr_stringify_fmt(), build_user_routes(), cc_extension_monitor_init(), cc_generic_agent_start_monitoring(), custom_log(), dial_handle_playtones(), do_magic_pickup(), find_realtime(), frame_trace_helper(), function_fieldnum_helper(), function_fieldqty_helper(), handle_cli_core_show_translation(), handle_getvariablefull(), handle_playtones(), handle_tcptls_connection(), hash_string(), iax_parse_ies(), init_appendbuf(), jingle_new(), log_jack_status(), mansession_cmp_fn(), match_ie_val(), misdn_cfg_get(), misdn_cfg_get_config_string(), misdn_cfg_get_next_port(), misdn_cfg_get_ports_string(), misdn_cfg_is_group_method(), misdn_cfg_is_port_valid(), misdn_to_str_plan(), misdn_to_str_pres(), misdn_to_str_screen(), misdn_to_str_ton(), parse_cdata(), pbx_retrieve_variable(), pp_each_extension_helper(), pp_each_user_helper(), process_text_line(), regex(), replace(), sdp_crypto_process(), security_event_cb(), sendtext_exec(), syslog_log(), transmit_info_with_aoc(), variable_count_cmp_fn(), and yyparse().


Generated on 17 Aug 2018 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1