Wed Jan 27 20:02:01 2016

Asterisk developer's documentation


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: 411313 $")
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 
00062 #define RESAMPLE_QUALITY 1
00063 
00064 #define RINGBUFFER_SIZE 16384
00065 
00066 /*! \brief Common options between the Jack() app and JACK_HOOK() function */
00067 #define COMMON_OPTIONS \
00068 "    s(<name>) - Connect to the specified jack server name.\n" \
00069 "    i(<name>) - Connect the output port that gets created to the specified\n" \
00070 "                jack input port.\n" \
00071 "    o(<name>) - Connect the input port that gets created to the specified\n" \
00072 "                jack output port.\n" \
00073 "    n         - Do not automatically start the JACK server if it is not already\n" \
00074 "                running.\n" \
00075 "    c(<name>) - By default, Asterisk will use the channel name for the jack client\n" \
00076 "                name.  Use this option to specify a custom client name.\n"
00077 /*** DOCUMENTATION
00078    <application name="JACK" language="en_US">
00079       <synopsis>
00080          Jack Audio Connection Kit
00081       </synopsis>
00082       <syntax>
00083          <parameter name="options" required="false">
00084             <optionlist>
00085                <option name="s">
00086                   <argument name="name" required="true">
00087                      <para>Connect to the specified jack server name</para>
00088                   </argument>
00089                </option>
00090                <option name="i">
00091                   <argument name="name" required="true">
00092                      <para>Connect the output port that gets created to the specified jack input port</para>
00093                   </argument>
00094                </option>
00095                <option name="o">
00096                   <argument name="name" required="true">
00097                      <para>Connect the input port that gets created to the specified jack output port</para>
00098                   </argument>
00099                </option>
00100                <option name="c">
00101                   <argument name="name" required="true">
00102                      <para>By default, Asterisk will use the channel name for the jack client name.</para>
00103                      <para>Use this option to specify a custom client name.</para>
00104                   </argument>
00105                </option>
00106             </optionlist>
00107          </parameter>
00108       </syntax>
00109       <description>
00110          <para>When executing this application, two jack ports will be created;
00111          one input and one output. Other applications can be hooked up to
00112          these ports to access audio coming from, or being send to the channel.</para>
00113       </description>
00114    </application>
00115  ***/
00116 
00117 static const char jack_app[] = "JACK";
00118 
00119 struct jack_data {
00120    AST_DECLARE_STRING_FIELDS(
00121       AST_STRING_FIELD(server_name);
00122       AST_STRING_FIELD(client_name);
00123       AST_STRING_FIELD(connect_input_port);
00124       AST_STRING_FIELD(connect_output_port);
00125    );
00126    jack_client_t *client;
00127    jack_port_t *input_port;
00128    jack_port_t *output_port;
00129    jack_ringbuffer_t *input_rb;
00130    jack_ringbuffer_t *output_rb;
00131    void *output_resampler;
00132    double output_resample_factor;
00133    void *input_resampler;
00134    double input_resample_factor;
00135    unsigned int stop:1;
00136    unsigned int has_audiohook:1;
00137    unsigned int no_start_server:1;
00138    /*! Only used with JACK_HOOK */
00139    struct ast_audiohook audiohook;
00140 };
00141 
00142 static const struct {
00143    jack_status_t status;
00144    const char *str;
00145 } jack_status_table[] = {
00146    { JackFailure,        "Failure" },
00147    { JackInvalidOption,  "Invalid Option" },
00148    { JackNameNotUnique,  "Name Not Unique" },
00149    { JackServerStarted,  "Server Started" },
00150    { JackServerFailed,   "Server Failed" },
00151    { JackServerError,    "Server Error" },
00152    { JackNoSuchClient,   "No Such Client" },
00153    { JackLoadFailure,    "Load Failure" },
00154    { JackInitFailure,    "Init Failure" },
00155    { JackShmFailure,     "Shared Memory Access Failure" },
00156    { JackVersionError,   "Version Mismatch" },
00157 };
00158 
00159 static const char *jack_status_to_str(jack_status_t 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 }
00170 
00171 static void log_jack_status(const char *prefix, jack_status_t status)
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 }
00189 
00190 static int alloc_resampler(struct jack_data *jack_data, int input)
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 }
00233 
00234 /*!
00235  * \brief Handle jack input port
00236  *
00237  * Read nframes number of samples from the input buffer, resample it
00238  * if necessary, and write it into the appropriate ringbuffer.
00239  */
00240 static void handle_input(void *buf, jack_nframes_t nframes,
00241    struct jack_data *jack_data)
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 }
00296 
00297 /*!
00298  * \brief Handle jack output port
00299  *
00300  * Read nframes number of samples from the ringbuffer and write it out to the
00301  * output port buffer.
00302  */
00303 static void handle_output(void *buf, jack_nframes_t nframes,
00304    struct jack_data *jack_data)
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 }
00317 
00318 static int jack_process(jack_nframes_t nframes, void *arg)
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 }
00334 
00335 static void jack_shutdown(void *arg)
00336 {
00337    struct jack_data *jack_data = arg;
00338 
00339    jack_data->stop = 1;
00340 }
00341 
00342 static struct jack_data *destroy_jack_data(struct jack_data *jack_data)
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 }
00388 
00389 static int init_jack_data(struct ast_channel *chan, struct jack_data *jack_data)
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 }
00516 
00517 static int queue_voice_frame(struct jack_data *jack_data, struct ast_frame *f)
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 }
00582 
00583 /*!
00584  * \brief handle jack audio
00585  *
00586  * \param[in]  chan The Asterisk channel to write the frames to if no output frame
00587  *             is provided.
00588  * \param[in]  jack_data This is the jack_data struct that contains the input
00589  *             ringbuffer that audio will be read from.
00590  * \param[out] out_frame If this argument is non-NULL, then assuming there is
00591  *             enough data avilable in the ringbuffer, the audio in this frame
00592  *             will get replaced with audio from the input buffer.  If there is
00593  *             not enough data available to read at this time, then the frame
00594  *             data gets zeroed out.
00595  *
00596  * Read data from the input ringbuffer, which is the properly resampled audio
00597  * that was read from the jack input port.  Write it to the channel in 20 ms frames,
00598  * or fill up an output frame instead if one is provided.
00599  *
00600  * \return Nothing.
00601  */
00602 static void handle_jack_audio(struct ast_channel *chan, struct jack_data *jack_data,
00603    struct ast_frame *out_frame)
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 }
00649 
00650 enum {
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 };
00657 
00658 enum {
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 };
00667 
00668 AST_APP_OPTIONS(jack_exec_options, BEGIN_OPTIONS
00669    AST_APP_OPTION_ARG('s', OPT_SERVER_NAME, OPT_ARG_SERVER_NAME),
00670    AST_APP_OPTION_ARG('i', OPT_INPUT_PORT, OPT_ARG_INPUT_PORT),
00671    AST_APP_OPTION_ARG('o', OPT_OUTPUT_PORT, OPT_ARG_OUTPUT_PORT),
00672    AST_APP_OPTION('n', OPT_NOSTART_SERVER),
00673    AST_APP_OPTION_ARG('c', OPT_CLIENT_NAME, OPT_ARG_CLIENT_NAME),
00674 END_OPTIONS );
00675 
00676 static struct jack_data *jack_data_alloc(void)
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 }
00686 
00687 /*!
00688  * \note This must be done before calling init_jack_data().
00689  */
00690 static int handle_options(struct jack_data *jack_data, const char *__options_str)
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 }
00740 
00741 static int jack_exec(struct ast_channel *chan, const char *data)
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 }
00801 
00802 static void jack_hook_ds_destroy(void *data)
00803 {
00804    struct jack_data *jack_data = data;
00805 
00806    destroy_jack_data(jack_data);
00807 }
00808 
00809 static const struct ast_datastore_info jack_hook_ds_info = {
00810    .type = "JACK_HOOK",
00811    .destroy = jack_hook_ds_destroy,
00812 };
00813 
00814 static int jack_hook_callback(struct ast_audiohook *audiohook, struct ast_channel *chan,
00815    struct ast_frame *frame, enum ast_audiohook_direction direction)
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 }
00853 
00854 static int enable_jack_hook(struct ast_channel *chan, char *data)
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 }
00920 
00921 static int disable_jack_hook(struct ast_channel *chan)
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 }
00948 
00949 static int jack_hook_write(struct ast_channel *chan, const char *cmd, char *data,
00950    const char *value)
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 }
00970 
00971 static struct ast_custom_function jack_hook_function = {
00972    .name = "JACK_HOOK",
00973    .synopsis = "Enable a jack hook on a channel",
00974    .syntax = "JACK_HOOK(<mode>,[options])",
00975    .desc =
00976    "   The JACK_HOOK allows turning on or off jack connectivity to this channel.\n"
00977    "When the JACK_HOOK is turned on, jack ports will get created that allow\n"
00978    "access to the audio stream for this channel.  The mode specifies which mode\n"
00979    "this hook should run in.  A mode must be specified when turning the JACK_HOOK.\n"
00980    "on.  However, all arguments are optional when turning it off.\n"
00981    "\n"
00982    "   Valid modes are:\n"
00983 #if 0
00984    /* XXX TODO */
00985    "    spy -        Create a read-only audio hook.  Only an output jack port will\n"
00986    "                 get created.\n"
00987    "    whisper -    Create a write-only audio hook.  Only an input jack port will\n"
00988    "                 get created.\n"
00989 #endif
00990    "    manipulate - Create a read/write audio hook.  Both an input and an output\n"
00991    "                 jack port will get created.  Audio from the channel will be\n"
00992    "                 sent out the output port and will be replaced by the audio\n"
00993    "                 coming in on the input port as it gets passed on.\n"
00994    "\n"
00995    "   Valid options are:\n"
00996    COMMON_OPTIONS
00997    "\n"
00998    " Examples:\n"
00999    "   To turn on the JACK_HOOK,\n"
01000    "     Set(JACK_HOOK(manipulate,i(pure_data_0:input0)o(pure_data_0:output0))=on)\n"
01001    "   To turn off the JACK_HOOK,\n"
01002    "     Set(JACK_HOOK()=off)\n"
01003    "",
01004    .write = jack_hook_write,
01005 };
01006 
01007 static int unload_module(void)
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 }
01016 
01017 static int load_module(void)
01018 {
01019    if (ast_register_application_xml(jack_app, jack_exec)) {
01020       return AST_MODULE_LOAD_DECLINE;
01021    }
01022 
01023    if (ast_custom_function_register(&jack_hook_function)) {
01024       ast_unregister_application(jack_app);
01025       return AST_MODULE_LOAD_DECLINE;
01026    }
01027 
01028    return AST_MODULE_LOAD_SUCCESS;
01029 }
01030 
01031 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "JACK Interface");

Generated on 27 Jan 2016 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1