Thu Apr 28 2011 17:13:28

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