app_jack.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 2007 - 2008, Russell Bryant
00005  *
00006  * Russell Bryant <russell@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*!
00020  * \file
00021  * \brief Jack Application
00022  *
00023  * \author Russell Bryant <russell@digium.com>
00024  *
00025  * This is an application to connect an Asterisk channel to an input
00026  * and output jack port so that the audio can be processed through
00027  * another application, or to play audio from another application.
00028  *
00029  * \extref http://www.jackaudio.org/
00030  *
00031  * \note To install libresample, check it out of the following repository:
00032  * <code>$ svn co http://svn.digium.com/svn/thirdparty/libresample/trunk</code>
00033  *
00034  * \ingroup applications
00035  */
00036 
00037 /*** MODULEINFO
00038    <depend>jack</depend>
00039    <depend>resample</depend>
00040    <support_level>extended</support_level>
00041  ***/
00042 
00043 #include "asterisk.h"
00044 
00045 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 423978 $")
00046 
00047 #include <limits.h>
00048 
00049 #include <jack/jack.h>
00050 #include <jack/ringbuffer.h>
00051 
00052 #include <libresample.h>
00053 
00054 #include "asterisk/module.h"
00055 #include "asterisk/channel.h"
00056 #include "asterisk/strings.h"
00057 #include "asterisk/lock.h"
00058 #include "asterisk/app.h"
00059 #include "asterisk/pbx.h"
00060 #include "asterisk/audiohook.h"
00061 #include "asterisk/format_cache.h"
00062 
00063 #define RESAMPLE_QUALITY 1
00064 
00065 /* The number of frames the ringbuffers can store. The actual size is RINGBUFFER_FRAME_CAPACITY * jack_data->frame_datalen */
00066 #define RINGBUFFER_FRAME_CAPACITY 100
00067 
00068 /*! \brief Common options between the Jack() app and JACK_HOOK() function */
00069 #define COMMON_OPTIONS \
00070 "    s(<name>) - Connect to the specified jack server name.\n" \
00071 "    i(<name>) - Connect the output port that gets created to the specified\n" \
00072 "                jack input port.\n" \
00073 "    o(<name>) - Connect the input port that gets created to the specified\n" \
00074 "                jack output port.\n" \
00075 "    n         - Do not automatically start the JACK server if it is not already\n" \
00076 "                running.\n" \
00077 "    c(<name>) - By default, Asterisk will use the channel name for the jack client\n" \
00078 "                name.  Use this option to specify a custom client name.\n"
00079 /*** DOCUMENTATION
00080    <application name="JACK" language="en_US">
00081       <synopsis>
00082          Jack Audio Connection Kit
00083       </synopsis>
00084       <syntax>
00085          <parameter name="options" required="false">
00086             <optionlist>
00087                <option name="s">
00088                   <argument name="name" required="true">
00089                      <para>Connect to the specified jack server name</para>
00090                   </argument>
00091                </option>
00092                <option name="i">
00093                   <argument name="name" required="true">
00094                      <para>Connect the output port that gets created to the specified jack input port</para>
00095                   </argument>
00096                </option>
00097                <option name="o">
00098                   <argument name="name" required="true">
00099                      <para>Connect the input port that gets created to the specified jack output port</para>
00100                   </argument>
00101                </option>
00102                <option name="c">
00103                   <argument name="name" required="true">
00104                      <para>By default, Asterisk will use the channel name for the jack client name.</para>
00105                      <para>Use this option to specify a custom client name.</para>
00106                   </argument>
00107                </option>
00108             </optionlist>
00109          </parameter>
00110       </syntax>
00111       <description>
00112          <para>When executing this application, two jack ports will be created;
00113          one input and one output. Other applications can be hooked up to
00114          these ports to access audio coming from, or being send to the channel.</para>
00115       </description>
00116    </application>
00117  ***/
00118 
00119 static const char jack_app[] = "JACK";
00120 
00121 struct jack_data {
00122    AST_DECLARE_STRING_FIELDS(
00123       AST_STRING_FIELD(server_name);
00124       AST_STRING_FIELD(client_name);
00125       AST_STRING_FIELD(connect_input_port);
00126       AST_STRING_FIELD(connect_output_port);
00127    );
00128    jack_client_t *client;
00129    jack_port_t *input_port;
00130    jack_port_t *output_port;
00131    jack_ringbuffer_t *input_rb;
00132    jack_ringbuffer_t *output_rb;
00133    struct ast_format *audiohook_format;
00134    unsigned int audiohook_rate;
00135    unsigned int frame_datalen;
00136    void *output_resampler;
00137    double output_resample_factor;
00138    void *input_resampler;
00139    double input_resample_factor;
00140    unsigned int stop:1;
00141    unsigned int has_audiohook:1;
00142    unsigned int no_start_server:1;
00143    /*! Only used with JACK_HOOK */
00144    struct ast_audiohook audiohook;
00145 };
00146 
00147 static const struct {
00148    jack_status_t status;
00149    const char *str;
00150 } jack_status_table[] = {
00151    { JackFailure,        "Failure" },
00152    { JackInvalidOption,  "Invalid Option" },
00153    { JackNameNotUnique,  "Name Not Unique" },
00154    { JackServerStarted,  "Server Started" },
00155    { JackServerFailed,   "Server Failed" },
00156    { JackServerError,    "Server Error" },
00157    { JackNoSuchClient,   "No Such Client" },
00158    { JackLoadFailure,    "Load Failure" },
00159    { JackInitFailure,    "Init Failure" },
00160    { JackShmFailure,     "Shared Memory Access Failure" },
00161    { JackVersionError,   "Version Mismatch" },
00162 };
00163 
00164 static const char *jack_status_to_str(jack_status_t status)
00165 {
00166    int i;
00167 
00168    for (i = 0; i < ARRAY_LEN(jack_status_table); i++) {
00169       if (jack_status_table[i].status == status)
00170          return jack_status_table[i].str;
00171    }
00172 
00173    return "Unknown Error";
00174 }
00175 
00176 static void log_jack_status(const char *prefix, jack_status_t status)
00177 {
00178    struct ast_str *str = ast_str_alloca(512);
00179    int i, first = 0;
00180 
00181    for (i = 0; i < (sizeof(status) * 8); i++) {
00182       if (!(status & (1 << i)))
00183          continue;
00184 
00185       if (!first) {
00186          ast_str_set(&str, 0, "%s", jack_status_to_str((1 << i)));
00187          first = 1;
00188       } else
00189          ast_str_append(&str, 0, ", %s", jack_status_to_str((1 << i)));
00190    }
00191 
00192    ast_log(LOG_NOTICE, "%s: %s\n", prefix, ast_str_buffer(str));
00193 }
00194 
00195 static int alloc_resampler(struct jack_data *jack_data, int input)
00196 {
00197    double from_srate, to_srate, jack_srate;
00198    void **resampler;
00199    double *resample_factor;
00200 
00201    if (input && jack_data->input_resampler)
00202       return 0;
00203 
00204    if (!input && jack_data->output_resampler)
00205       return 0;
00206 
00207    jack_srate = jack_get_sample_rate(jack_data->client);
00208 
00209    to_srate = input ? jack_data->audiohook_rate : jack_srate;
00210    from_srate = input ? jack_srate : jack_data->audiohook_rate;
00211 
00212    resample_factor = input ? &jack_data->input_resample_factor :
00213       &jack_data->output_resample_factor;
00214 
00215    if (from_srate == to_srate) {
00216       /* Awesome!  The jack sample rate is the same as ours.
00217        * Resampling isn't needed. */
00218       *resample_factor = 1.0;
00219       return 0;
00220    }
00221 
00222    *resample_factor = to_srate / from_srate;
00223 
00224    resampler = input ? &jack_data->input_resampler :
00225       &jack_data->output_resampler;
00226 
00227    if (!(*resampler = resample_open(RESAMPLE_QUALITY,
00228       *resample_factor, *resample_factor))) {
00229       ast_log(LOG_ERROR, "Failed to open %s resampler\n",
00230          input ? "input" : "output");
00231       return -1;
00232    }
00233 
00234    return 0;
00235 }
00236 
00237 /*!
00238  * \brief Handle jack input port
00239  *
00240  * Read nframes number of samples from the input buffer, resample it
00241  * if necessary, and write it into the appropriate ringbuffer.
00242  */
00243 static void handle_input(void *buf, jack_nframes_t nframes,
00244    struct jack_data *jack_data)
00245 {
00246    short s_buf[nframes];
00247    float *in_buf = buf;
00248    size_t res;
00249    int i;
00250    size_t write_len = sizeof(s_buf);
00251 
00252    if (jack_data->input_resampler) {
00253       int total_in_buf_used = 0;
00254       int total_out_buf_used = 0;
00255       float f_buf[nframes + 1];
00256 
00257       memset(f_buf, 0, sizeof(f_buf));
00258 
00259       while (total_in_buf_used < nframes) {
00260          int in_buf_used;
00261          int out_buf_used;
00262 
00263          out_buf_used = resample_process(jack_data->input_resampler,
00264             jack_data->input_resample_factor,
00265             &in_buf[total_in_buf_used], nframes - total_in_buf_used,
00266             0, &in_buf_used,
00267             &f_buf[total_out_buf_used], ARRAY_LEN(f_buf) - total_out_buf_used);
00268 
00269          if (out_buf_used < 0)
00270             break;
00271 
00272          total_out_buf_used += out_buf_used;
00273          total_in_buf_used += in_buf_used;
00274 
00275          if (total_out_buf_used == ARRAY_LEN(f_buf)) {
00276             ast_log(LOG_ERROR, "Output buffer filled ... need to increase its size, "
00277                "nframes '%d', total_out_buf_used '%d'\n", nframes, total_out_buf_used);
00278             break;
00279          }
00280       }
00281 
00282       for (i = 0; i < total_out_buf_used; i++)
00283          s_buf[i] = f_buf[i] * (SHRT_MAX / 1.0);
00284 
00285       write_len = total_out_buf_used * sizeof(int16_t);
00286    } else {
00287       /* No resampling needed */
00288 
00289       for (i = 0; i < nframes; i++)
00290          s_buf[i] = in_buf[i] * (SHRT_MAX / 1.0);
00291    }
00292 
00293    res = jack_ringbuffer_write(jack_data->input_rb, (const char *) s_buf, write_len);
00294    if (res != write_len) {
00295       ast_log(LOG_WARNING, "Tried to write %d bytes to the ringbuffer, but only wrote %d\n",
00296          (int) sizeof(s_buf), (int) res);
00297    }
00298 }
00299 
00300 /*!
00301  * \brief Handle jack output port
00302  *
00303  * Read nframes number of samples from the ringbuffer and write it out to the
00304  * output port buffer.
00305  */
00306 static void handle_output(void *buf, jack_nframes_t nframes,
00307    struct jack_data *jack_data)
00308 {
00309    size_t res, len;
00310 
00311    len = nframes * sizeof(float);
00312 
00313    res = jack_ringbuffer_read(jack_data->output_rb, buf, len);
00314 
00315    if (len != res) {
00316       ast_debug(2, "Wanted %d bytes to send to the output port, "
00317          "but only got %d\n", (int) len, (int) res);
00318    }
00319 }
00320 
00321 static int jack_process(jack_nframes_t nframes, void *arg)
00322 {
00323    struct jack_data *jack_data = arg;
00324    void *input_port_buf, *output_port_buf;
00325 
00326    if (!jack_data->input_resample_factor)
00327       alloc_resampler(jack_data, 1);
00328 
00329    input_port_buf = jack_port_get_buffer(jack_data->input_port, nframes);
00330    handle_input(input_port_buf, nframes, jack_data);
00331 
00332    output_port_buf = jack_port_get_buffer(jack_data->output_port, nframes);
00333    handle_output(output_port_buf, nframes, jack_data);
00334 
00335    return 0;
00336 }
00337 
00338 static void jack_shutdown(void *arg)
00339 {
00340    struct jack_data *jack_data = arg;
00341 
00342    jack_data->stop = 1;
00343 }
00344 
00345 static struct jack_data *destroy_jack_data(struct jack_data *jack_data)
00346 {
00347    if (jack_data->input_port) {
00348       jack_port_unregister(jack_data->client, jack_data->input_port);
00349       jack_data->input_port = NULL;
00350    }
00351 
00352    if (jack_data->output_port) {
00353       jack_port_unregister(jack_data->client, jack_data->output_port);
00354       jack_data->output_port = NULL;
00355    }
00356 
00357    if (jack_data->client) {
00358       jack_client_close(jack_data->client);
00359       jack_data->client = NULL;
00360    }
00361 
00362    if (jack_data->input_rb) {
00363       jack_ringbuffer_free(jack_data->input_rb);
00364       jack_data->input_rb = NULL;
00365    }
00366 
00367    if (jack_data->output_rb) {
00368       jack_ringbuffer_free(jack_data->output_rb);
00369       jack_data->output_rb = NULL;
00370    }
00371 
00372    if (jack_data->output_resampler) {
00373       resample_close(jack_data->output_resampler);
00374       jack_data->output_resampler = NULL;
00375    }
00376 
00377    if (jack_data->input_resampler) {
00378       resample_close(jack_data->input_resampler);
00379       jack_data->input_resampler = NULL;
00380    }
00381 
00382    if (jack_data->has_audiohook)
00383       ast_audiohook_destroy(&jack_data->audiohook);
00384 
00385    ast_string_field_free_memory(jack_data);
00386 
00387    ast_free(jack_data);
00388 
00389    return NULL;
00390 }
00391 
00392 static int init_jack_data(struct ast_channel *chan, struct jack_data *jack_data)
00393 {
00394    const char *client_name;
00395    jack_status_t status = 0;
00396    jack_options_t jack_options = JackNullOption;
00397 
00398    unsigned int channel_rate;
00399 
00400    unsigned int ringbuffer_size;
00401 
00402    /* Deducing audiohook sample rate from channel format
00403       ATTENTION: Might be problematic, if channel has different sampling than used by audiohook!
00404    */
00405    channel_rate = ast_format_get_sample_rate(ast_channel_readformat(chan));
00406    jack_data->audiohook_format = ast_format_cache_get_slin_by_rate(channel_rate);
00407    jack_data->audiohook_rate = ast_format_get_sample_rate(jack_data->audiohook_format);
00408 
00409    /* Guessing frame->datalen assuming a ptime of 20ms */
00410    jack_data->frame_datalen = jack_data->audiohook_rate / 50;
00411 
00412    ringbuffer_size = jack_data->frame_datalen * RINGBUFFER_FRAME_CAPACITY;
00413 
00414    ast_debug(1, "Audiohook parameters: slin-format:%s, rate:%d, frame-len:%d, ringbuffer_size: %d\n",
00415        ast_format_get_name(jack_data->audiohook_format), jack_data->audiohook_rate, jack_data->frame_datalen, ringbuffer_size);
00416 
00417    if (!ast_strlen_zero(jack_data->client_name)) {
00418       client_name = jack_data->client_name;
00419    } else {
00420       ast_channel_lock(chan);
00421       client_name = ast_strdupa(ast_channel_name(chan));
00422       ast_channel_unlock(chan);
00423    }
00424 
00425    if (!(jack_data->output_rb = jack_ringbuffer_create(ringbuffer_size)))
00426       return -1;
00427 
00428    if (!(jack_data->input_rb = jack_ringbuffer_create(ringbuffer_size)))
00429       return -1;
00430 
00431    if (jack_data->no_start_server)
00432       jack_options |= JackNoStartServer;
00433 
00434    if (!ast_strlen_zero(jack_data->server_name)) {
00435       jack_options |= JackServerName;
00436       jack_data->client = jack_client_open(client_name, jack_options, &status,
00437          jack_data->server_name);
00438    } else {
00439       jack_data->client = jack_client_open(client_name, jack_options, &status);
00440    }
00441 
00442    if (status)
00443       log_jack_status("Client Open Status", status);
00444 
00445    if (!jack_data->client)
00446       return -1;
00447 
00448    jack_data->input_port = jack_port_register(jack_data->client, "input",
00449       JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput | JackPortIsTerminal, 0);
00450    if (!jack_data->input_port) {
00451       ast_log(LOG_ERROR, "Failed to create input port for jack port\n");
00452       return -1;
00453    }
00454 
00455    jack_data->output_port = jack_port_register(jack_data->client, "output",
00456       JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput | JackPortIsTerminal, 0);
00457    if (!jack_data->output_port) {
00458       ast_log(LOG_ERROR, "Failed to create output port for jack port\n");
00459       return -1;
00460    }
00461 
00462    if (jack_set_process_callback(jack_data->client, jack_process, jack_data)) {
00463       ast_log(LOG_ERROR, "Failed to register process callback with jack client\n");
00464       return -1;
00465    }
00466 
00467    jack_on_shutdown(jack_data->client, jack_shutdown, jack_data);
00468 
00469    if (jack_activate(jack_data->client)) {
00470       ast_log(LOG_ERROR, "Unable to activate jack client\n");
00471       return -1;
00472    }
00473 
00474    while (!ast_strlen_zero(jack_data->connect_input_port)) {
00475       const char **ports;
00476       int i;
00477 
00478       ports = jack_get_ports(jack_data->client, jack_data->connect_input_port,
00479          NULL, JackPortIsInput);
00480 
00481       if (!ports) {
00482          ast_log(LOG_ERROR, "No input port matching '%s' was found\n",
00483             jack_data->connect_input_port);
00484          break;
00485       }
00486 
00487       for (i = 0; ports[i]; i++) {
00488          ast_debug(1, "Found port '%s' that matched specified input port '%s'\n",
00489             ports[i], jack_data->connect_input_port);
00490       }
00491 
00492       if (jack_connect(jack_data->client, jack_port_name(jack_data->output_port), ports[0])) {
00493          ast_log(LOG_ERROR, "Failed to connect '%s' to '%s'\n", ports[0],
00494             jack_port_name(jack_data->output_port));
00495       } else {
00496          ast_debug(1, "Connected '%s' to '%s'\n", ports[0],
00497             jack_port_name(jack_data->output_port));
00498       }
00499 
00500       jack_free(ports);
00501 
00502       break;
00503    }
00504 
00505    while (!ast_strlen_zero(jack_data->connect_output_port)) {
00506       const char **ports;
00507       int i;
00508 
00509       ports = jack_get_ports(jack_data->client, jack_data->connect_output_port,
00510          NULL, JackPortIsOutput);
00511 
00512       if (!ports) {
00513          ast_log(LOG_ERROR, "No output port matching '%s' was found\n",
00514             jack_data->connect_output_port);
00515          break;
00516       }
00517 
00518       for (i = 0; ports[i]; i++) {
00519          ast_debug(1, "Found port '%s' that matched specified output port '%s'\n",
00520             ports[i], jack_data->connect_output_port);
00521       }
00522 
00523       if (jack_connect(jack_data->client, ports[0], jack_port_name(jack_data->input_port))) {
00524          ast_log(LOG_ERROR, "Failed to connect '%s' to '%s'\n", ports[0],
00525             jack_port_name(jack_data->input_port));
00526       } else {
00527          ast_debug(1, "Connected '%s' to '%s'\n", ports[0],
00528             jack_port_name(jack_data->input_port));
00529       }
00530 
00531       jack_free(ports);
00532 
00533       break;
00534    }
00535 
00536    return 0;
00537 }
00538 
00539 static int queue_voice_frame(struct jack_data *jack_data, struct ast_frame *f)
00540 {
00541    float f_buf[f->samples * 8];
00542    size_t f_buf_used = 0;
00543    int i;
00544    int16_t *s_buf = f->data.ptr;
00545    size_t res;
00546 
00547    memset(f_buf, 0, sizeof(f_buf));
00548 
00549    if (!jack_data->output_resample_factor)
00550       alloc_resampler(jack_data, 0);
00551 
00552    if (jack_data->output_resampler) {
00553       float in_buf[f->samples];
00554       int total_in_buf_used = 0;
00555       int total_out_buf_used = 0;
00556 
00557       memset(in_buf, 0, sizeof(in_buf));
00558 
00559       for (i = 0; i < f->samples; i++)
00560          in_buf[i] = s_buf[i] * (1.0 / SHRT_MAX);
00561 
00562       while (total_in_buf_used < ARRAY_LEN(in_buf)) {
00563          int in_buf_used;
00564          int out_buf_used;
00565 
00566          out_buf_used = resample_process(jack_data->output_resampler,
00567             jack_data->output_resample_factor,
00568             &in_buf[total_in_buf_used], ARRAY_LEN(in_buf) - total_in_buf_used,
00569             0, &in_buf_used,
00570             &f_buf[total_out_buf_used], ARRAY_LEN(f_buf) - total_out_buf_used);
00571 
00572          if (out_buf_used < 0)
00573             break;
00574 
00575          total_out_buf_used += out_buf_used;
00576          total_in_buf_used += in_buf_used;
00577 
00578          if (total_out_buf_used == ARRAY_LEN(f_buf)) {
00579             ast_log(LOG_ERROR, "Output buffer filled ... need to increase its size\n");
00580             break;
00581          }
00582       }
00583 
00584       f_buf_used = total_out_buf_used;
00585       if (f_buf_used > ARRAY_LEN(f_buf))
00586          f_buf_used = ARRAY_LEN(f_buf);
00587    } else {
00588       /* No resampling needed */
00589 
00590       for (i = 0; i < f->samples; i++)
00591          f_buf[i] = s_buf[i] * (1.0 / SHRT_MAX);
00592 
00593       f_buf_used = f->samples;
00594    }
00595 
00596    res = jack_ringbuffer_write(jack_data->output_rb, (const char *) f_buf, f_buf_used * sizeof(float));
00597    if (res != (f_buf_used * sizeof(float))) {
00598       ast_log(LOG_WARNING, "Tried to write %d bytes to the ringbuffer, but only wrote %d\n",
00599          (int) (f_buf_used * sizeof(float)), (int) res);
00600    }
00601    return 0;
00602 }
00603 
00604 /*!
00605  * \brief handle jack audio
00606  *
00607  * \param[in]  chan The Asterisk channel to write the frames to if no output frame
00608  *             is provided.
00609  * \param[in]  jack_data This is the jack_data struct that contains the input
00610  *             ringbuffer that audio will be read from.
00611  * \param[out] out_frame If this argument is non-NULL, then assuming there is
00612  *             enough data avilable in the ringbuffer, the audio in this frame
00613  *             will get replaced with audio from the input buffer.  If there is
00614  *             not enough data available to read at this time, then the frame
00615  *             data gets zeroed out.
00616  *
00617  * Read data from the input ringbuffer, which is the properly resampled audio
00618  * that was read from the jack input port.  Write it to the channel in 20 ms frames,
00619  * or fill up an output frame instead if one is provided.
00620  *
00621  * \return Nothing.
00622  */
00623 static void handle_jack_audio(struct ast_channel *chan, struct jack_data *jack_data,
00624    struct ast_frame *out_frame)
00625 {
00626    short buf[jack_data->frame_datalen];
00627    struct ast_frame f = {
00628       .frametype = AST_FRAME_VOICE,
00629       .subclass.format = jack_data->audiohook_format,
00630       .src = "JACK",
00631       .data.ptr = buf,
00632       .datalen = sizeof(buf),
00633       .samples = ARRAY_LEN(buf),
00634    };
00635 
00636    for (;;) {
00637       size_t res, read_len;
00638       char *read_buf;
00639 
00640       read_len = out_frame ? out_frame->datalen : sizeof(buf);
00641       read_buf = out_frame ? out_frame->data.ptr : buf;
00642 
00643       res = jack_ringbuffer_read_space(jack_data->input_rb);
00644 
00645       if (res < read_len) {
00646          /* Not enough data ready for another frame, move on ... */
00647          if (out_frame) {
00648             ast_debug(1, "Sending an empty frame for the JACK_HOOK\n");
00649             memset(out_frame->data.ptr, 0, out_frame->datalen);
00650          }
00651          break;
00652       }
00653 
00654       res = jack_ringbuffer_read(jack_data->input_rb, (char *) read_buf, read_len);
00655 
00656       if (res < read_len) {
00657          ast_log(LOG_ERROR, "Error reading from ringbuffer, even though it said there was enough data\n");
00658          break;
00659       }
00660 
00661       if (out_frame) {
00662          /* If an output frame was provided, then we just want to fill up the
00663           * buffer in that frame and return. */
00664          break;
00665       }
00666 
00667       ast_write(chan, &f);
00668    }
00669 }
00670 
00671 enum {
00672    OPT_SERVER_NAME =    (1 << 0),
00673    OPT_INPUT_PORT =     (1 << 1),
00674    OPT_OUTPUT_PORT =    (1 << 2),
00675    OPT_NOSTART_SERVER = (1 << 3),
00676    OPT_CLIENT_NAME =    (1 << 4),
00677 };
00678 
00679 enum {
00680    OPT_ARG_SERVER_NAME,
00681    OPT_ARG_INPUT_PORT,
00682    OPT_ARG_OUTPUT_PORT,
00683    OPT_ARG_CLIENT_NAME,
00684 
00685    /* Must be the last element */
00686    OPT_ARG_ARRAY_SIZE,
00687 };
00688 
00689 AST_APP_OPTIONS(jack_exec_options, BEGIN_OPTIONS
00690    AST_APP_OPTION_ARG('s', OPT_SERVER_NAME, OPT_ARG_SERVER_NAME),
00691    AST_APP_OPTION_ARG('i', OPT_INPUT_PORT, OPT_ARG_INPUT_PORT),
00692    AST_APP_OPTION_ARG('o', OPT_OUTPUT_PORT, OPT_ARG_OUTPUT_PORT),
00693    AST_APP_OPTION('n', OPT_NOSTART_SERVER),
00694    AST_APP_OPTION_ARG('c', OPT_CLIENT_NAME, OPT_ARG_CLIENT_NAME),
00695 END_OPTIONS );
00696 
00697 static struct jack_data *jack_data_alloc(void)
00698 {
00699    struct jack_data *jack_data;
00700 
00701    if (!(jack_data = ast_calloc_with_stringfields(1, struct jack_data, 32))) {
00702       return NULL;
00703    }
00704 
00705    return jack_data;
00706 }
00707 
00708 /*!
00709  * \note This must be done before calling init_jack_data().
00710  */
00711 static int handle_options(struct jack_data *jack_data, const char *__options_str)
00712 {
00713    struct ast_flags options = { 0, };
00714    char *option_args[OPT_ARG_ARRAY_SIZE];
00715    char *options_str;
00716 
00717    options_str = ast_strdupa(__options_str);
00718 
00719    ast_app_parse_options(jack_exec_options, &options, option_args, options_str);
00720 
00721    if (ast_test_flag(&options, OPT_SERVER_NAME)) {
00722       if (!ast_strlen_zero(option_args[OPT_ARG_SERVER_NAME]))
00723          ast_string_field_set(jack_data, server_name, option_args[OPT_ARG_SERVER_NAME]);
00724       else {
00725          ast_log(LOG_ERROR, "A server name must be provided with the s() option\n");
00726          return -1;
00727       }
00728    }
00729 
00730    if (ast_test_flag(&options, OPT_CLIENT_NAME)) {
00731       if (!ast_strlen_zero(option_args[OPT_ARG_CLIENT_NAME]))
00732          ast_string_field_set(jack_data, client_name, option_args[OPT_ARG_CLIENT_NAME]);
00733       else {
00734          ast_log(LOG_ERROR, "A client name must be provided with the c() option\n");
00735          return -1;
00736       }
00737    }
00738 
00739    if (ast_test_flag(&options, OPT_INPUT_PORT)) {
00740       if (!ast_strlen_zero(option_args[OPT_ARG_INPUT_PORT]))
00741          ast_string_field_set(jack_data, connect_input_port, option_args[OPT_ARG_INPUT_PORT]);
00742       else {
00743          ast_log(LOG_ERROR, "A name must be provided with the i() option\n");
00744          return -1;
00745       }
00746    }
00747 
00748    if (ast_test_flag(&options, OPT_OUTPUT_PORT)) {
00749       if (!ast_strlen_zero(option_args[OPT_ARG_OUTPUT_PORT]))
00750          ast_string_field_set(jack_data, connect_output_port, option_args[OPT_ARG_OUTPUT_PORT]);
00751       else {
00752          ast_log(LOG_ERROR, "A name must be provided with the o() option\n");
00753          return -1;
00754       }
00755    }
00756 
00757    jack_data->no_start_server = ast_test_flag(&options, OPT_NOSTART_SERVER) ? 1 : 0;
00758 
00759    return 0;
00760 }
00761 
00762 static int jack_exec(struct ast_channel *chan, const char *data)
00763 {
00764    struct jack_data *jack_data;
00765 
00766    if (!(jack_data = jack_data_alloc()))
00767       return -1;
00768 
00769    if (!ast_strlen_zero(data) && handle_options(jack_data, data)) {
00770       destroy_jack_data(jack_data);
00771       return -1;
00772    }
00773 
00774    if (init_jack_data(chan, jack_data)) {
00775       destroy_jack_data(jack_data);
00776       return -1;
00777    }
00778 
00779    if (ast_set_read_format(chan, jack_data->audiohook_format)) {
00780       destroy_jack_data(jack_data);
00781       return -1;
00782    }
00783 
00784    if (ast_set_write_format(chan, jack_data->audiohook_format)) {
00785       destroy_jack_data(jack_data);
00786       return -1;
00787    }
00788 
00789    while (!jack_data->stop) {
00790       struct ast_frame *f;
00791 
00792       if (ast_waitfor(chan, -1) < 0) {
00793          break;
00794       }
00795 
00796       f = ast_read(chan);
00797       if (!f) {
00798          jack_data->stop = 1;
00799          continue;
00800       }
00801 
00802       switch (f->frametype) {
00803       case AST_FRAME_CONTROL:
00804          if (f->subclass.integer == AST_CONTROL_HANGUP)
00805             jack_data->stop = 1;
00806          break;
00807       case AST_FRAME_VOICE:
00808          queue_voice_frame(jack_data, f);
00809       default:
00810          break;
00811       }
00812 
00813       ast_frfree(f);
00814 
00815       handle_jack_audio(chan, jack_data, NULL);
00816    }
00817 
00818    jack_data = destroy_jack_data(jack_data);
00819 
00820    return 0;
00821 }
00822 
00823 static void jack_hook_ds_destroy(void *data)
00824 {
00825    struct jack_data *jack_data = data;
00826 
00827    destroy_jack_data(jack_data);
00828 }
00829 
00830 static const struct ast_datastore_info jack_hook_ds_info = {
00831    .type = "JACK_HOOK",
00832    .destroy = jack_hook_ds_destroy,
00833 };
00834 
00835 static int jack_hook_callback(struct ast_audiohook *audiohook, struct ast_channel *chan,
00836    struct ast_frame *frame, enum ast_audiohook_direction direction)
00837 {
00838    struct ast_datastore *datastore;
00839    struct jack_data *jack_data;
00840 
00841    if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE)
00842       return 0;
00843 
00844    if (direction != AST_AUDIOHOOK_DIRECTION_READ)
00845       return 0;
00846 
00847    if (frame->frametype != AST_FRAME_VOICE)
00848       return 0;
00849 
00850    ast_channel_lock(chan);
00851 
00852    if (!(datastore = ast_channel_datastore_find(chan, &jack_hook_ds_info, NULL))) {
00853       ast_log(LOG_ERROR, "JACK_HOOK datastore not found for '%s'\n", ast_channel_name(chan));
00854       ast_channel_unlock(chan);
00855       return -1;
00856    }
00857 
00858    jack_data = datastore->data;
00859 
00860    if (ast_format_cmp(frame->subclass.format, jack_data->audiohook_format) == AST_FORMAT_CMP_NOT_EQUAL) {
00861       ast_log(LOG_WARNING, "Expected frame in %s for the audiohook, but got format %s\n",
00862          ast_format_get_name(jack_data->audiohook_format),
00863          ast_format_get_name(frame->subclass.format));
00864       ast_channel_unlock(chan);
00865       return 0;
00866    }
00867 
00868    queue_voice_frame(jack_data, frame);
00869 
00870    handle_jack_audio(chan, jack_data, frame);
00871 
00872    ast_channel_unlock(chan);
00873 
00874    return 0;
00875 }
00876 
00877 static int enable_jack_hook(struct ast_channel *chan, char *data)
00878 {
00879    struct ast_datastore *datastore;
00880    struct jack_data *jack_data = NULL;
00881    AST_DECLARE_APP_ARGS(args,
00882       AST_APP_ARG(mode);
00883       AST_APP_ARG(options);
00884    );
00885 
00886    AST_STANDARD_APP_ARGS(args, data);
00887 
00888    ast_channel_lock(chan);
00889 
00890    if ((datastore = ast_channel_datastore_find(chan, &jack_hook_ds_info, NULL))) {
00891       ast_log(LOG_ERROR, "JACK_HOOK already enabled for '%s'\n", ast_channel_name(chan));
00892       goto return_error;
00893    }
00894 
00895    if (ast_strlen_zero(args.mode) || strcasecmp(args.mode, "manipulate")) {
00896       ast_log(LOG_ERROR, "'%s' is not a supported mode.  Only manipulate is supported.\n",
00897          S_OR(args.mode, "<none>"));
00898       goto return_error;
00899    }
00900 
00901    if (!(jack_data = jack_data_alloc()))
00902       goto return_error;
00903 
00904    if (!ast_strlen_zero(args.options) && handle_options(jack_data, args.options))
00905       goto return_error;
00906 
00907    if (init_jack_data(chan, jack_data))
00908       goto return_error;
00909 
00910    if (!(datastore = ast_datastore_alloc(&jack_hook_ds_info, NULL)))
00911       goto return_error;
00912 
00913    jack_data->has_audiohook = 1;
00914    ast_audiohook_init(&jack_data->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "JACK_HOOK", AST_AUDIOHOOK_MANIPULATE_ALL_RATES);
00915    jack_data->audiohook.manipulate_callback = jack_hook_callback;
00916 
00917    datastore->data = jack_data;
00918 
00919    if (ast_audiohook_attach(chan, &jack_data->audiohook))
00920       goto return_error;
00921 
00922    if (ast_channel_datastore_add(chan, datastore))
00923       goto return_error;
00924 
00925    ast_channel_unlock(chan);
00926 
00927    return 0;
00928 
00929 return_error:
00930    ast_channel_unlock(chan);
00931 
00932    if (jack_data) {
00933       destroy_jack_data(jack_data);
00934    }
00935 
00936    if (datastore) {
00937       datastore->data = NULL;
00938       ast_datastore_free(datastore);
00939    }
00940 
00941    return -1;
00942 }
00943 
00944 static int disable_jack_hook(struct ast_channel *chan)
00945 {
00946    struct ast_datastore *datastore;
00947    struct jack_data *jack_data;
00948 
00949    ast_channel_lock(chan);
00950 
00951    if (!(datastore = ast_channel_datastore_find(chan, &jack_hook_ds_info, NULL))) {
00952       ast_channel_unlock(chan);
00953       ast_log(LOG_WARNING, "No JACK_HOOK found to disable\n");
00954       return -1;
00955    }
00956 
00957    ast_channel_datastore_remove(chan, datastore);
00958 
00959    jack_data = datastore->data;
00960    ast_audiohook_detach(&jack_data->audiohook);
00961 
00962    /* Keep the channel locked while we destroy the datastore, so that we can
00963     * ensure that all of the jack stuff is stopped just in case another frame
00964     * tries to come through the audiohook callback. */
00965    ast_datastore_free(datastore);
00966 
00967    ast_channel_unlock(chan);
00968 
00969    return 0;
00970 }
00971 
00972 static int jack_hook_write(struct ast_channel *chan, const char *cmd, char *data,
00973    const char *value)
00974 {
00975    int res;
00976 
00977    if (!chan) {
00978       ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
00979       return -1;
00980    }
00981 
00982    if (!strcasecmp(value, "on"))
00983       res = enable_jack_hook(chan, data);
00984    else if (!strcasecmp(value, "off"))
00985       res = disable_jack_hook(chan);
00986    else {
00987       ast_log(LOG_ERROR, "'%s' is not a valid value for JACK_HOOK()\n", value);
00988       res = -1;
00989    }
00990 
00991    return res;
00992 }
00993 
00994 static struct ast_custom_function jack_hook_function = {
00995    .name = "JACK_HOOK",
00996    .synopsis = "Enable a jack hook on a channel",
00997    .syntax = "JACK_HOOK(<mode>,[options])",
00998    .desc =
00999    "   The JACK_HOOK allows turning on or off jack connectivity to this channel.\n"
01000    "When the JACK_HOOK is turned on, jack ports will get created that allow\n"
01001    "access to the audio stream for this channel.  The mode specifies which mode\n"
01002    "this hook should run in.  A mode must be specified when turning the JACK_HOOK.\n"
01003    "on.  However, all arguments are optional when turning it off.\n"
01004    "\n"
01005    "   Valid modes are:\n"
01006 #if 0
01007    /* XXX TODO */
01008    "    spy -        Create a read-only audio hook.  Only an output jack port will\n"
01009    "                 get created.\n"
01010    "    whisper -    Create a write-only audio hook.  Only an input jack port will\n"
01011    "                 get created.\n"
01012 #endif
01013    "    manipulate - Create a read/write audio hook.  Both an input and an output\n"
01014    "                 jack port will get created.  Audio from the channel will be\n"
01015    "                 sent out the output port and will be replaced by the audio\n"
01016    "                 coming in on the input port as it gets passed on.\n"
01017    "\n"
01018    "   Valid options are:\n"
01019    COMMON_OPTIONS
01020    "\n"
01021    " Examples:\n"
01022    "   To turn on the JACK_HOOK,\n"
01023    "     Set(JACK_HOOK(manipulate,i(pure_data_0:input0)o(pure_data_0:output0))=on)\n"
01024    "   To turn off the JACK_HOOK,\n"
01025    "     Set(JACK_HOOK()=off)\n"
01026    "",
01027    .write = jack_hook_write,
01028 };
01029 
01030 static int unload_module(void)
01031 {
01032    int res;
01033 
01034    res = ast_unregister_application(jack_app);
01035    res |= ast_custom_function_unregister(&jack_hook_function);
01036 
01037    return res;
01038 }
01039 
01040 static int load_module(void)
01041 {
01042    if (ast_register_application_xml(jack_app, jack_exec)) {
01043       return AST_MODULE_LOAD_DECLINE;
01044    }
01045 
01046    if (ast_custom_function_register(&jack_hook_function)) {
01047       ast_unregister_application(jack_app);
01048       return AST_MODULE_LOAD_DECLINE;
01049    }
01050 
01051    return AST_MODULE_LOAD_SUCCESS;
01052 }
01053 
01054 AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "JACK Interface");
01055 

Generated on Thu Apr 16 06:27:09 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6