Wed Apr 6 11:29:38 2011

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

Generated on Wed Apr 6 11:29:38 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7