Mon Oct 8 12:38:58 2012

Asterisk developer's documentation


chan_console.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 2006 - 2008, Digium, Inc.
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 Cross-platform console channel driver 
00022  *
00023  * \author Russell Bryant <russell@digium.com>
00024  *
00025  * \note Some of the code in this file came from chan_oss and chan_alsa.
00026  *       chan_oss,  Mark Spencer <markster@digium.com>
00027  *       chan_oss,  Luigi Rizzo
00028  *       chan_alsa, Matthew Fredrickson <creslin@digium.com>
00029  * 
00030  * \ingroup channel_drivers
00031  *
00032  * \extref Portaudio http://www.portaudio.com/
00033  *
00034  * To install portaudio v19 from svn, check it out using the following command:
00035  *  - svn co https://www.portaudio.com/repos/portaudio/branches/v19-devel
00036  *
00037  * \note Since this works with any audio system that libportaudio supports,
00038  * including ALSA and OSS, this may someday deprecate chan_alsa and chan_oss.
00039  * However, before that can be done, it needs to *at least* have all of the
00040  * features that these other channel drivers have.  The features implemented
00041  * in at least one of the other console channel drivers that are not yet
00042  * implemented here are:
00043  *
00044  * - Set Auto-answer from the dialplan
00045  * - transfer CLI command
00046  * - boost CLI command and .conf option
00047  * - console_video support
00048  */
00049 
00050 /*** MODULEINFO
00051    <depend>portaudio</depend>
00052    <support_level>extended</support_level>
00053  ***/
00054 
00055 #include "asterisk.h"
00056 
00057 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 335064 $")
00058 
00059 #include <sys/signal.h>  /* SIGURG */
00060 
00061 #include <portaudio.h>
00062 
00063 #include "asterisk/module.h"
00064 #include "asterisk/channel.h"
00065 #include "asterisk/pbx.h"
00066 #include "asterisk/causes.h"
00067 #include "asterisk/cli.h"
00068 #include "asterisk/musiconhold.h"
00069 #include "asterisk/callerid.h"
00070 #include "asterisk/astobj2.h"
00071 
00072 /*! 
00073  * \brief The sample rate to request from PortAudio 
00074  *
00075  * \todo Make this optional.  If this is only going to talk to 8 kHz endpoints,
00076  *       then it makes sense to use 8 kHz natively.
00077  */
00078 #define SAMPLE_RATE      16000
00079 
00080 /*! 
00081  * \brief The number of samples to configure the portaudio stream for
00082  *
00083  * 320 samples (20 ms) is the most common frame size in Asterisk.  So, the code
00084  * in this module reads 320 sample frames from the portaudio stream and queues
00085  * them up on the Asterisk channel.  Frames of any size can be written to a
00086  * portaudio stream, but the portaudio documentation does say that for high
00087  * performance applications, the data should be written to Pa_WriteStream in
00088  * the same size as what is used to initialize the stream.
00089  */
00090 #define NUM_SAMPLES      320
00091 
00092 /*! \brief Mono Input */
00093 #define INPUT_CHANNELS   1
00094 
00095 /*! \brief Mono Output */
00096 #define OUTPUT_CHANNELS  1
00097 
00098 /*! 
00099  * \brief Maximum text message length
00100  * \note This should be changed if there is a common definition somewhere
00101  *       that defines the maximum length of a text message.
00102  */
00103 #define TEXT_SIZE 256
00104 
00105 /*! \brief Dance, Kirby, Dance! @{ */
00106 #define V_BEGIN " --- <(\"<) --- "
00107 #define V_END   " --- (>\")> ---\n"
00108 /*! @} */
00109 
00110 static const char config_file[] = "console.conf";
00111 
00112 /*!
00113  * \brief Console pvt structure
00114  *
00115  * Currently, this is a singleton object.  However, multiple instances will be
00116  * needed when this module is updated for multiple device support.
00117  */
00118 static struct console_pvt {
00119    AST_DECLARE_STRING_FIELDS(
00120       /*! Name of the device */
00121       AST_STRING_FIELD(name);
00122       AST_STRING_FIELD(input_device);
00123       AST_STRING_FIELD(output_device);
00124       /*! Default context for outgoing calls */
00125       AST_STRING_FIELD(context);
00126       /*! Default extension for outgoing calls */
00127       AST_STRING_FIELD(exten);
00128       /*! Default CallerID number */
00129       AST_STRING_FIELD(cid_num);
00130       /*! Default CallerID name */
00131       AST_STRING_FIELD(cid_name);
00132       /*! Default MOH class to listen to, if:
00133        *    - No MOH class set on the channel
00134        *    - Peer channel putting this device on hold did not suggest a class */
00135       AST_STRING_FIELD(mohinterpret);
00136       /*! Default language */
00137       AST_STRING_FIELD(language);
00138       /*! Default parkinglot */
00139       AST_STRING_FIELD(parkinglot);
00140    );
00141    /*! Current channel for this device */
00142    struct ast_channel *owner;
00143    /*! Current PortAudio stream for this device */
00144    PaStream *stream;
00145    /*! A frame for preparing to queue on to the channel */
00146    struct ast_frame fr;
00147    /*! Running = 1, Not running = 0 */
00148    unsigned int streamstate:1;
00149    /*! On-hook = 0, Off-hook = 1 */
00150    unsigned int hookstate:1;
00151    /*! Unmuted = 0, Muted = 1 */
00152    unsigned int muted:1;
00153    /*! Automatically answer incoming calls */
00154    unsigned int autoanswer:1;
00155    /*! Ignore context in the console dial CLI command */
00156    unsigned int overridecontext:1;
00157    /*! Set during a reload so that we know to destroy this if it is no longer
00158     *  in the configuration file. */
00159    unsigned int destroy:1;
00160    /*! ID for the stream monitor thread */
00161    pthread_t thread;
00162 } globals;
00163 
00164 AST_MUTEX_DEFINE_STATIC(globals_lock);
00165 
00166 static struct ao2_container *pvts;
00167 #define NUM_PVT_BUCKETS 7
00168 
00169 static struct console_pvt *active_pvt;
00170 AST_RWLOCK_DEFINE_STATIC(active_lock);
00171 
00172 /*! 
00173  * \brief Global jitterbuffer configuration 
00174  *
00175  * \note Disabled by default.
00176  * \note Values shown here match the defaults shown in console.conf.sample
00177  */
00178 static struct ast_jb_conf default_jbconf = {
00179    .flags = 0,
00180    .max_size = 200,
00181    .resync_threshold = 1000,
00182    .impl = "fixed",
00183    .target_extra = 40,
00184 };
00185 static struct ast_jb_conf global_jbconf;
00186 
00187 /*! Channel Technology Callbacks @{ */
00188 static struct ast_channel *console_request(const char *type, format_t format,
00189    const struct ast_channel *requestor, void *data, int *cause);
00190 static int console_digit_begin(struct ast_channel *c, char digit);
00191 static int console_digit_end(struct ast_channel *c, char digit, unsigned int duration);
00192 static int console_text(struct ast_channel *c, const char *text);
00193 static int console_hangup(struct ast_channel *c);
00194 static int console_answer(struct ast_channel *c);
00195 static struct ast_frame *console_read(struct ast_channel *chan);
00196 static int console_call(struct ast_channel *c, char *dest, int timeout);
00197 static int console_write(struct ast_channel *chan, struct ast_frame *f);
00198 static int console_indicate(struct ast_channel *chan, int cond, 
00199    const void *data, size_t datalen);
00200 static int console_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
00201 /*! @} */
00202 
00203 /*!
00204  * \brief Formats natively supported by this module.
00205  */
00206 #define SUPPORTED_FORMATS ( AST_FORMAT_SLINEAR16 )
00207 
00208 static const struct ast_channel_tech console_tech = {
00209    .type = "Console",
00210    .description = "Console Channel Driver",
00211    .capabilities = SUPPORTED_FORMATS,
00212    .requester = console_request,
00213    .send_digit_begin = console_digit_begin,
00214    .send_digit_end = console_digit_end,
00215    .send_text = console_text,
00216    .hangup = console_hangup,
00217    .answer = console_answer,
00218    .read = console_read,
00219    .call = console_call,
00220    .write = console_write,
00221    .indicate = console_indicate,
00222    .fixup = console_fixup,
00223 };
00224 
00225 /*! \brief lock a console_pvt struct */
00226 #define console_pvt_lock(pvt) ao2_lock(pvt)
00227 
00228 /*! \brief unlock a console_pvt struct */
00229 #define console_pvt_unlock(pvt) ao2_unlock(pvt)
00230 
00231 static inline struct console_pvt *ref_pvt(struct console_pvt *pvt)
00232 {
00233    if (pvt)
00234       ao2_ref(pvt, +1);
00235    return pvt;
00236 }
00237 
00238 static inline struct console_pvt *unref_pvt(struct console_pvt *pvt)
00239 {
00240    ao2_ref(pvt, -1);
00241    return NULL;
00242 }
00243 
00244 static struct console_pvt *find_pvt(const char *name)
00245 {
00246    struct console_pvt tmp_pvt = {
00247       .name = name,
00248    };
00249 
00250    return ao2_find(pvts, &tmp_pvt, OBJ_POINTER);
00251 }
00252 
00253 /*!
00254  * \brief Stream monitor thread 
00255  *
00256  * \arg data A pointer to the console_pvt structure that contains the portaudio
00257  *      stream that needs to be monitored.
00258  *
00259  * This function runs in its own thread to monitor data coming in from a
00260  * portaudio stream.  When enough data is available, it is queued up to
00261  * be read from the Asterisk channel.
00262  */
00263 static void *stream_monitor(void *data)
00264 {
00265    struct console_pvt *pvt = data;
00266    char buf[NUM_SAMPLES * sizeof(int16_t)];
00267    PaError res;
00268    struct ast_frame f = {
00269       .frametype = AST_FRAME_VOICE,
00270       .subclass.codec = AST_FORMAT_SLINEAR16,
00271       .src = "console_stream_monitor",
00272       .data.ptr = buf,
00273       .datalen = sizeof(buf),
00274       .samples = sizeof(buf) / sizeof(int16_t),
00275    };
00276 
00277    for (;;) {
00278       pthread_testcancel();
00279       res = Pa_ReadStream(pvt->stream, buf, sizeof(buf) / sizeof(int16_t));
00280       pthread_testcancel();
00281 
00282       if (!pvt->owner) {
00283          return NULL;
00284       }
00285 
00286       if (res == paNoError)
00287          ast_queue_frame(pvt->owner, &f);
00288    }
00289 
00290    return NULL;
00291 }
00292 
00293 static int open_stream(struct console_pvt *pvt)
00294 {
00295    int res = paInternalError;
00296 
00297    if (!strcasecmp(pvt->input_device, "default") && 
00298       !strcasecmp(pvt->output_device, "default")) {
00299       res = Pa_OpenDefaultStream(&pvt->stream, INPUT_CHANNELS, OUTPUT_CHANNELS, 
00300          paInt16, SAMPLE_RATE, NUM_SAMPLES, NULL, NULL);
00301    } else {
00302       PaStreamParameters input_params = { 
00303          .channelCount = 1,
00304          .sampleFormat = paInt16,
00305          .suggestedLatency = (1.0 / 50.0), /* 20 ms */
00306          .device = paNoDevice,
00307       };
00308       PaStreamParameters output_params = { 
00309          .channelCount = 1, 
00310          .sampleFormat = paInt16,
00311          .suggestedLatency = (1.0 / 50.0), /* 20 ms */
00312          .device = paNoDevice,
00313       };
00314       PaDeviceIndex idx, num_devices, def_input, def_output;
00315 
00316       if (!(num_devices = Pa_GetDeviceCount()))
00317          return res;
00318 
00319       def_input = Pa_GetDefaultInputDevice();
00320       def_output = Pa_GetDefaultOutputDevice();
00321 
00322       for (idx = 0; 
00323          idx < num_devices && (input_params.device == paNoDevice 
00324             || output_params.device == paNoDevice); 
00325          idx++) 
00326       {
00327          const PaDeviceInfo *dev = Pa_GetDeviceInfo(idx);
00328 
00329          if (dev->maxInputChannels) {
00330             if ( (idx == def_input && !strcasecmp(pvt->input_device, "default")) ||
00331                !strcasecmp(pvt->input_device, dev->name) )
00332                input_params.device = idx;
00333          }
00334 
00335          if (dev->maxOutputChannels) {
00336             if ( (idx == def_output && !strcasecmp(pvt->output_device, "default")) ||
00337                !strcasecmp(pvt->output_device, dev->name) )
00338                output_params.device = idx;
00339          }
00340       }
00341 
00342       if (input_params.device == paNoDevice)
00343          ast_log(LOG_ERROR, "No input device found for console device '%s'\n", pvt->name);
00344       if (output_params.device == paNoDevice)
00345          ast_log(LOG_ERROR, "No output device found for console device '%s'\n", pvt->name);
00346 
00347       res = Pa_OpenStream(&pvt->stream, &input_params, &output_params,
00348          SAMPLE_RATE, NUM_SAMPLES, paNoFlag, NULL, NULL);
00349    }
00350 
00351    return res;
00352 }
00353 
00354 static int start_stream(struct console_pvt *pvt)
00355 {
00356    PaError res;
00357    int ret_val = 0;
00358 
00359    console_pvt_lock(pvt);
00360 
00361    /* It is possible for console_hangup to be called before the
00362     * stream is started, if this is the case pvt->owner will be NULL
00363     * and start_stream should be aborted. */
00364    if (pvt->streamstate || !pvt->owner)
00365       goto return_unlock;
00366 
00367    pvt->streamstate = 1;
00368    ast_debug(1, "Starting stream\n");
00369 
00370    res = open_stream(pvt);
00371    if (res != paNoError) {
00372       ast_log(LOG_WARNING, "Failed to open stream - (%d) %s\n",
00373          res, Pa_GetErrorText(res));
00374       ret_val = -1;
00375       goto return_unlock;
00376    }
00377 
00378    res = Pa_StartStream(pvt->stream);
00379    if (res != paNoError) {
00380       ast_log(LOG_WARNING, "Failed to start stream - (%d) %s\n",
00381          res, Pa_GetErrorText(res));
00382       ret_val = -1;
00383       goto return_unlock;
00384    }
00385 
00386    if (ast_pthread_create_background(&pvt->thread, NULL, stream_monitor, pvt)) {
00387       ast_log(LOG_ERROR, "Failed to start stream monitor thread\n");
00388       ret_val = -1;
00389    }
00390 
00391 return_unlock:
00392    console_pvt_unlock(pvt);
00393 
00394    return ret_val;
00395 }
00396 
00397 static int stop_stream(struct console_pvt *pvt)
00398 {
00399    if (!pvt->streamstate || pvt->thread == AST_PTHREADT_NULL)
00400       return 0;
00401 
00402    pthread_cancel(pvt->thread);
00403    pthread_kill(pvt->thread, SIGURG);
00404    pthread_join(pvt->thread, NULL);
00405 
00406    console_pvt_lock(pvt);
00407    Pa_AbortStream(pvt->stream);
00408    Pa_CloseStream(pvt->stream);
00409    pvt->stream = NULL;
00410    pvt->streamstate = 0;
00411    console_pvt_unlock(pvt);
00412 
00413    return 0;
00414 }
00415 
00416 /*!
00417  * \note Called with the pvt struct locked
00418  */
00419 static struct ast_channel *console_new(struct console_pvt *pvt, const char *ext, const char *ctx, int state, const char *linkedid)
00420 {
00421    struct ast_channel *chan;
00422 
00423    if (!(chan = ast_channel_alloc(1, state, pvt->cid_num, pvt->cid_name, NULL, 
00424       ext, ctx, linkedid, 0, "Console/%s", pvt->name))) {
00425       return NULL;
00426    }
00427 
00428    chan->tech = &console_tech;
00429    chan->nativeformats = AST_FORMAT_SLINEAR16;
00430    chan->readformat = AST_FORMAT_SLINEAR16;
00431    chan->writeformat = AST_FORMAT_SLINEAR16;
00432    chan->tech_pvt = ref_pvt(pvt);
00433 
00434    pvt->owner = chan;
00435 
00436    if (!ast_strlen_zero(pvt->language))
00437       ast_string_field_set(chan, language, pvt->language);
00438 
00439    ast_jb_configure(chan, &global_jbconf);
00440 
00441    if (state != AST_STATE_DOWN) {
00442       if (ast_pbx_start(chan)) {
00443          chan->hangupcause = AST_CAUSE_SWITCH_CONGESTION;
00444          ast_hangup(chan);
00445          chan = NULL;
00446       } else
00447          start_stream(pvt);
00448    }
00449 
00450    return chan;
00451 }
00452 
00453 static struct ast_channel *console_request(const char *type, format_t format, const struct ast_channel *requestor, void *data, int *cause)
00454 {
00455    format_t oldformat = format;
00456    struct ast_channel *chan = NULL;
00457    struct console_pvt *pvt;
00458    char buf[512];
00459 
00460    if (!(pvt = find_pvt(data))) {
00461       ast_log(LOG_ERROR, "Console device '%s' not found\n", (char *) data);
00462       return NULL;
00463    }
00464 
00465    format &= SUPPORTED_FORMATS;
00466    if (!format) {
00467       ast_log(LOG_NOTICE, "Channel requested with unsupported format(s): '%s'\n", ast_getformatname_multiple(buf, sizeof(buf), oldformat));
00468       goto return_unref;
00469    }
00470 
00471    if (pvt->owner) {
00472       ast_log(LOG_NOTICE, "Console channel already active!\n");
00473       *cause = AST_CAUSE_BUSY;
00474       goto return_unref;
00475    }
00476 
00477    console_pvt_lock(pvt);
00478    chan = console_new(pvt, NULL, NULL, AST_STATE_DOWN, requestor ? requestor->linkedid : NULL);
00479    console_pvt_unlock(pvt);
00480 
00481    if (!chan)
00482       ast_log(LOG_WARNING, "Unable to create new Console channel!\n");
00483 
00484 return_unref:
00485    unref_pvt(pvt);
00486 
00487    return chan;
00488 }
00489 
00490 static int console_digit_begin(struct ast_channel *c, char digit)
00491 {
00492    ast_verb(1, V_BEGIN "Console Received Beginning of Digit %c" V_END, digit);
00493 
00494    return -1; /* non-zero to request inband audio */
00495 }
00496 
00497 static int console_digit_end(struct ast_channel *c, char digit, unsigned int duration)
00498 {
00499    ast_verb(1, V_BEGIN "Console Received End of Digit %c (duration %u)" V_END, 
00500       digit, duration);
00501 
00502    return -1; /* non-zero to request inband audio */
00503 }
00504 
00505 static int console_text(struct ast_channel *c, const char *text)
00506 {
00507    ast_verb(1, V_BEGIN "Console Received Text '%s'" V_END, text);
00508 
00509    return 0;
00510 }
00511 
00512 static int console_hangup(struct ast_channel *c)
00513 {
00514    struct console_pvt *pvt = c->tech_pvt;
00515 
00516    ast_verb(1, V_BEGIN "Hangup on Console" V_END);
00517 
00518    pvt->hookstate = 0;
00519    pvt->owner = NULL;
00520    stop_stream(pvt);
00521 
00522    c->tech_pvt = unref_pvt(pvt);
00523 
00524    return 0;
00525 }
00526 
00527 static int console_answer(struct ast_channel *c)
00528 {
00529    struct console_pvt *pvt = c->tech_pvt;
00530 
00531    ast_verb(1, V_BEGIN "Call from Console has been Answered" V_END);
00532 
00533    ast_setstate(c, AST_STATE_UP);
00534 
00535    return start_stream(pvt);
00536 }
00537 
00538 /*
00539  * \brief Implementation of the ast_channel_tech read() callback
00540  *
00541  * Calling this function is harmless.  However, if it does get called, it
00542  * is an indication that something weird happened that really shouldn't
00543  * have and is worth looking into.
00544  * 
00545  * Why should this function not get called?  Well, let me explain.  There are
00546  * a couple of ways to pass on audio that has come from this channel.  The way
00547  * that this channel driver uses is that once the audio is available, it is
00548  * wrapped in an ast_frame and queued onto the channel using ast_queue_frame().
00549  *
00550  * The other method would be signalling to the core that there is audio waiting,
00551  * and that it needs to call the channel's read() callback to get it.  The way
00552  * the channel gets signalled is that one or more file descriptors are placed
00553  * in the fds array on the ast_channel which the core will poll() on.  When the
00554  * fd indicates that input is available, the read() callback is called.  This
00555  * is especially useful when there is a dedicated file descriptor where the
00556  * audio is read from.  An example would be the socket for an RTP stream.
00557  */
00558 static struct ast_frame *console_read(struct ast_channel *chan)
00559 {
00560    ast_debug(1, "I should not be called ...\n");
00561 
00562    return &ast_null_frame;
00563 }
00564 
00565 static int console_call(struct ast_channel *c, char *dest, int timeout)
00566 {
00567    struct console_pvt *pvt = c->tech_pvt;
00568    enum ast_control_frame_type ctrl;
00569 
00570    ast_verb(1, V_BEGIN "Call to device '%s' on console from '%s' <%s>" V_END,
00571       dest,
00572       S_COR(c->caller.id.name.valid, c->caller.id.name.str, ""),
00573       S_COR(c->caller.id.number.valid, c->caller.id.number.str, ""));
00574 
00575    console_pvt_lock(pvt);
00576 
00577    if (pvt->autoanswer) {
00578       pvt->hookstate = 1;
00579       console_pvt_unlock(pvt);
00580       ast_verb(1, V_BEGIN "Auto-answered" V_END);
00581       ctrl = AST_CONTROL_ANSWER;
00582    } else {
00583       console_pvt_unlock(pvt);
00584       ast_verb(1, V_BEGIN "Type 'console answer' to answer, or use the 'autoanswer' option "
00585             "for future calls" V_END);
00586       ctrl = AST_CONTROL_RINGING;
00587       ast_indicate(c, AST_CONTROL_RINGING);
00588    }
00589 
00590    ast_queue_control(c, ctrl);
00591 
00592    return start_stream(pvt);
00593 }
00594 
00595 static int console_write(struct ast_channel *chan, struct ast_frame *f)
00596 {
00597    struct console_pvt *pvt = chan->tech_pvt;
00598 
00599    Pa_WriteStream(pvt->stream, f->data.ptr, f->samples);
00600 
00601    return 0;
00602 }
00603 
00604 static int console_indicate(struct ast_channel *chan, int cond, const void *data, size_t datalen)
00605 {
00606    struct console_pvt *pvt = chan->tech_pvt;
00607    int res = 0;
00608 
00609    switch (cond) {
00610    case AST_CONTROL_BUSY:
00611    case AST_CONTROL_CONGESTION:
00612    case AST_CONTROL_RINGING:
00613    case AST_CONTROL_INCOMPLETE:
00614    case -1:
00615       res = -1;  /* Ask for inband indications */
00616       break;
00617    case AST_CONTROL_PROGRESS:
00618    case AST_CONTROL_PROCEEDING:
00619    case AST_CONTROL_VIDUPDATE:
00620    case AST_CONTROL_SRCUPDATE:
00621       break;
00622    case AST_CONTROL_HOLD:
00623       ast_verb(1, V_BEGIN "Console Has Been Placed on Hold" V_END);
00624       ast_moh_start(chan, data, pvt->mohinterpret);
00625       break;
00626    case AST_CONTROL_UNHOLD:
00627       ast_verb(1, V_BEGIN "Console Has Been Retrieved from Hold" V_END);
00628       ast_moh_stop(chan);
00629       break;
00630    default:
00631       ast_log(LOG_WARNING, "Don't know how to display condition %d on %s\n", 
00632          cond, chan->name);
00633       /* The core will play inband indications for us if appropriate */
00634       res = -1;
00635    }
00636 
00637    return res;
00638 }
00639 
00640 static int console_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
00641 {
00642    struct console_pvt *pvt = newchan->tech_pvt;
00643 
00644    pvt->owner = newchan;
00645 
00646    return 0;
00647 }
00648 
00649 /*!
00650  * split a string in extension-context, returns pointers to malloc'ed
00651  * strings.
00652  * If we do not have 'overridecontext' then the last @ is considered as
00653  * a context separator, and the context is overridden.
00654  * This is usually not very necessary as you can play with the dialplan,
00655  * and it is nice not to need it because you have '@' in SIP addresses.
00656  * Return value is the buffer address.
00657  *
00658  * \note came from chan_oss
00659  */
00660 static char *ast_ext_ctx(struct console_pvt *pvt, const char *src, char **ext, char **ctx)
00661 {
00662    if (ext == NULL || ctx == NULL)
00663       return NULL;         /* error */
00664 
00665    *ext = *ctx = NULL;
00666 
00667    if (src && *src != '\0')
00668       *ext = ast_strdup(src);
00669 
00670    if (*ext == NULL)
00671       return NULL;
00672 
00673    if (!pvt->overridecontext) {
00674       /* parse from the right */
00675       *ctx = strrchr(*ext, '@');
00676       if (*ctx)
00677          *(*ctx)++ = '\0';
00678    }
00679 
00680    return *ext;
00681 }
00682 
00683 static struct console_pvt *get_active_pvt(void)
00684 {
00685    struct console_pvt *pvt;
00686 
00687    ast_rwlock_rdlock(&active_lock);
00688    pvt = ref_pvt(active_pvt); 
00689    ast_rwlock_unlock(&active_lock);
00690 
00691    return pvt;
00692 }
00693 
00694 static char *cli_console_autoanswer(struct ast_cli_entry *e, int cmd, 
00695    struct ast_cli_args *a)
00696 {
00697    struct console_pvt *pvt = get_active_pvt();
00698    char *res = CLI_SUCCESS;
00699 
00700    switch (cmd) {
00701    case CLI_INIT:
00702       e->command = "console {set|show} autoanswer [on|off]";
00703       e->usage =
00704          "Usage: console {set|show} autoanswer [on|off]\n"
00705          "       Enables or disables autoanswer feature.  If used without\n"
00706          "       argument, displays the current on/off status of autoanswer.\n"
00707          "       The default value of autoanswer is in 'oss.conf'.\n";
00708       return NULL;
00709 
00710    case CLI_GENERATE:
00711       return NULL;
00712    }
00713 
00714    if (!pvt) {
00715       ast_cli(a->fd, "No console device is set as active.\n");
00716       return CLI_FAILURE;
00717    }
00718 
00719    if (a->argc == e->args - 1) {
00720       ast_cli(a->fd, "Auto answer is %s.\n", pvt->autoanswer ? "on" : "off");
00721       unref_pvt(pvt);
00722       return CLI_SUCCESS;
00723    }
00724 
00725    if (a->argc != e->args) {
00726       unref_pvt(pvt);
00727       return CLI_SHOWUSAGE;
00728    }
00729 
00730    if (!strcasecmp(a->argv[e->args-1], "on"))
00731       pvt->autoanswer = 1;
00732    else if (!strcasecmp(a->argv[e->args - 1], "off"))
00733       pvt->autoanswer = 0;
00734    else
00735       res = CLI_SHOWUSAGE;
00736 
00737    unref_pvt(pvt);
00738 
00739    return res;
00740 }
00741 
00742 static char *cli_console_flash(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00743 {
00744    struct console_pvt *pvt = get_active_pvt();
00745 
00746    if (cmd == CLI_INIT) {
00747       e->command = "console flash";
00748       e->usage =
00749          "Usage: console flash\n"
00750          "       Flashes the call currently placed on the console.\n";
00751       return NULL;
00752    } else if (cmd == CLI_GENERATE)
00753       return NULL;
00754 
00755    if (!pvt) {
00756       ast_cli(a->fd, "No console device is set as active\n");
00757       return CLI_FAILURE;
00758    }
00759 
00760    if (a->argc != e->args)
00761       return CLI_SHOWUSAGE;
00762 
00763    if (!pvt->owner) {
00764       ast_cli(a->fd, "No call to flash\n");
00765       unref_pvt(pvt);
00766       return CLI_FAILURE;
00767    }
00768 
00769    pvt->hookstate = 0;
00770 
00771    ast_queue_control(pvt->owner, AST_CONTROL_FLASH);
00772 
00773    unref_pvt(pvt);
00774 
00775    return CLI_SUCCESS;
00776 }
00777 
00778 static char *cli_console_dial(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00779 {
00780    char *s = NULL;
00781    const char *mye = NULL, *myc = NULL; 
00782    struct console_pvt *pvt = get_active_pvt();
00783 
00784    if (cmd == CLI_INIT) {
00785       e->command = "console dial";
00786       e->usage =
00787          "Usage: console dial [extension[@context]]\n"
00788          "       Dials a given extension (and context if specified)\n";
00789       return NULL;
00790    } else if (cmd == CLI_GENERATE)
00791       return NULL;
00792 
00793    if (!pvt) {
00794       ast_cli(a->fd, "No console device is currently set as active\n");
00795       return CLI_FAILURE;
00796    }
00797    
00798    if (a->argc > e->args + 1)
00799       return CLI_SHOWUSAGE;
00800 
00801    if (pvt->owner) { /* already in a call */
00802       int i;
00803       struct ast_frame f = { AST_FRAME_DTMF };
00804       const char *s;
00805 
00806       if (a->argc == e->args) {  /* argument is mandatory here */
00807          ast_cli(a->fd, "Already in a call. You can only dial digits until you hangup.\n");
00808          unref_pvt(pvt);
00809          return CLI_FAILURE;
00810       }
00811       s = a->argv[e->args];
00812       /* send the string one char at a time */
00813       for (i = 0; i < strlen(s); i++) {
00814          f.subclass.integer = s[i];
00815          ast_queue_frame(pvt->owner, &f);
00816       }
00817       unref_pvt(pvt);
00818       return CLI_SUCCESS;
00819    }
00820 
00821    /* if we have an argument split it into extension and context */
00822    if (a->argc == e->args + 1) {
00823       char *ext = NULL, *con = NULL;
00824       s = ast_ext_ctx(pvt, a->argv[e->args], &ext, &con);
00825       ast_debug(1, "provided '%s', exten '%s' context '%s'\n", 
00826          a->argv[e->args], mye, myc);
00827       mye = ext;
00828       myc = con;
00829    }
00830 
00831    /* supply default values if needed */
00832    if (ast_strlen_zero(mye))
00833       mye = pvt->exten;
00834    if (ast_strlen_zero(myc))
00835       myc = pvt->context;
00836 
00837    if (ast_exists_extension(NULL, myc, mye, 1, NULL)) {
00838       console_pvt_lock(pvt);
00839       pvt->hookstate = 1;
00840       console_new(pvt, mye, myc, AST_STATE_RINGING, NULL);
00841       console_pvt_unlock(pvt);
00842    } else
00843       ast_cli(a->fd, "No such extension '%s' in context '%s'\n", mye, myc);
00844 
00845    free(s);
00846 
00847    unref_pvt(pvt);
00848 
00849    return CLI_SUCCESS;
00850 }
00851 
00852 static char *cli_console_hangup(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00853 {
00854    struct console_pvt *pvt = get_active_pvt();
00855 
00856    if (cmd == CLI_INIT) {
00857       e->command = "console hangup";
00858       e->usage =
00859          "Usage: console hangup\n"
00860          "       Hangs up any call currently placed on the console.\n";
00861       return NULL;
00862    } else if (cmd == CLI_GENERATE)
00863       return NULL;
00864 
00865    if (!pvt) {
00866       ast_cli(a->fd, "No console device is set as active\n");
00867       return CLI_FAILURE;
00868    }
00869    
00870    if (a->argc != e->args)
00871       return CLI_SHOWUSAGE;
00872 
00873    if (!pvt->owner && !pvt->hookstate) {
00874       ast_cli(a->fd, "No call to hang up\n");
00875       unref_pvt(pvt);
00876       return CLI_FAILURE;
00877    }
00878 
00879    pvt->hookstate = 0;
00880    if (pvt->owner)
00881       ast_queue_hangup(pvt->owner);
00882 
00883    unref_pvt(pvt);
00884 
00885    return CLI_SUCCESS;
00886 }
00887 
00888 static char *cli_console_mute(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00889 {
00890    const char *s;
00891    struct console_pvt *pvt = get_active_pvt();
00892    char *res = CLI_SUCCESS;
00893 
00894    if (cmd == CLI_INIT) {
00895       e->command = "console {mute|unmute}";
00896       e->usage =
00897          "Usage: console {mute|unmute}\n"
00898          "       Mute/unmute the microphone.\n";
00899       return NULL;
00900    } else if (cmd == CLI_GENERATE)
00901       return NULL;
00902 
00903    if (!pvt) {
00904       ast_cli(a->fd, "No console device is set as active\n");
00905       return CLI_FAILURE;
00906    }
00907 
00908    if (a->argc != e->args)
00909       return CLI_SHOWUSAGE;
00910 
00911    s = a->argv[e->args-1];
00912    if (!strcasecmp(s, "mute"))
00913       pvt->muted = 1;
00914    else if (!strcasecmp(s, "unmute"))
00915       pvt->muted = 0;
00916    else
00917       res = CLI_SHOWUSAGE;
00918 
00919    ast_verb(1, V_BEGIN "The Console is now %s" V_END, 
00920       pvt->muted ? "Muted" : "Unmuted");
00921 
00922    unref_pvt(pvt);
00923 
00924    return res;
00925 }
00926 
00927 static char *cli_list_available(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00928 {
00929    PaDeviceIndex idx, num, def_input, def_output;
00930 
00931    if (cmd == CLI_INIT) {
00932       e->command = "console list available";
00933       e->usage =
00934          "Usage: console list available\n"
00935          "       List all available devices.\n";
00936       return NULL;
00937    } else if (cmd == CLI_GENERATE)
00938       return NULL;
00939 
00940    if (a->argc != e->args)
00941       return CLI_SHOWUSAGE;
00942 
00943    ast_cli(a->fd, "\n"
00944                "=============================================================\n"
00945                "=== Available Devices =======================================\n"
00946                "=============================================================\n"
00947                "===\n");
00948 
00949    num = Pa_GetDeviceCount();
00950    if (!num) {
00951       ast_cli(a->fd, "(None)\n");
00952       return CLI_SUCCESS;
00953    }
00954 
00955    def_input = Pa_GetDefaultInputDevice();
00956    def_output = Pa_GetDefaultOutputDevice();
00957    for (idx = 0; idx < num; idx++) {
00958       const PaDeviceInfo *dev = Pa_GetDeviceInfo(idx);
00959       if (!dev)
00960          continue;
00961       ast_cli(a->fd, "=== ---------------------------------------------------------\n"
00962                      "=== Device Name: %s\n", dev->name);
00963       if (dev->maxInputChannels)
00964          ast_cli(a->fd, "=== ---> %sInput Device\n", (idx == def_input) ? "Default " : "");
00965       if (dev->maxOutputChannels)
00966          ast_cli(a->fd, "=== ---> %sOutput Device\n", (idx == def_output) ? "Default " : "");
00967       ast_cli(a->fd, "=== ---------------------------------------------------------\n===\n");
00968    }
00969 
00970    ast_cli(a->fd, "=============================================================\n\n");
00971 
00972    return CLI_SUCCESS;
00973 }
00974 
00975 static char *cli_list_devices(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00976 {
00977    struct ao2_iterator i;
00978    struct console_pvt *pvt;
00979 
00980    if (cmd == CLI_INIT) {
00981       e->command = "console list devices";
00982       e->usage =
00983          "Usage: console list devices\n"
00984          "       List all configured devices.\n";
00985       return NULL;
00986    } else if (cmd == CLI_GENERATE)
00987       return NULL;
00988 
00989    if (a->argc != e->args)
00990       return CLI_SHOWUSAGE;
00991 
00992    ast_cli(a->fd, "\n"
00993                "=============================================================\n"
00994                "=== Configured Devices ======================================\n"
00995                "=============================================================\n"
00996                "===\n");
00997 
00998    i = ao2_iterator_init(pvts, 0);
00999    while ((pvt = ao2_iterator_next(&i))) {
01000       console_pvt_lock(pvt);
01001 
01002       ast_cli(a->fd, "=== ---------------------------------------------------------\n"
01003                      "=== Device Name: %s\n"
01004                      "=== ---> Active:           %s\n"
01005                      "=== ---> Input Device:     %s\n"
01006                      "=== ---> Output Device:    %s\n"
01007                      "=== ---> Context:          %s\n"
01008                      "=== ---> Extension:        %s\n"
01009                      "=== ---> CallerID Num:     %s\n"
01010                      "=== ---> CallerID Name:    %s\n"
01011                      "=== ---> MOH Interpret:    %s\n"
01012                      "=== ---> Language:         %s\n"
01013                      "=== ---> Parkinglot:       %s\n"
01014                      "=== ---> Muted:            %s\n"
01015                      "=== ---> Auto-Answer:      %s\n"
01016                      "=== ---> Override Context: %s\n"
01017                      "=== ---------------------------------------------------------\n===\n",
01018          pvt->name, (pvt == active_pvt) ? "Yes" : "No",
01019          pvt->input_device, pvt->output_device, pvt->context,
01020          pvt->exten, pvt->cid_num, pvt->cid_name, pvt->mohinterpret,
01021          pvt->language, pvt->parkinglot, pvt->muted ? "Yes" : "No", pvt->autoanswer ? "Yes" : "No",
01022          pvt->overridecontext ? "Yes" : "No");
01023 
01024       console_pvt_unlock(pvt);
01025       unref_pvt(pvt);
01026    }
01027    ao2_iterator_destroy(&i);
01028 
01029    ast_cli(a->fd, "=============================================================\n\n");
01030 
01031    return CLI_SUCCESS;
01032 }
01033 /*!
01034  * \brief answer command from the console
01035  */
01036 static char *cli_console_answer(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01037 {
01038    struct console_pvt *pvt = get_active_pvt();
01039 
01040    switch (cmd) {
01041    case CLI_INIT:
01042       e->command = "console answer";
01043       e->usage =
01044          "Usage: console answer\n"
01045          "       Answers an incoming call on the console channel.\n";
01046       return NULL;
01047 
01048    case CLI_GENERATE:
01049       return NULL;   /* no completion */
01050    }
01051 
01052    if (!pvt) {
01053       ast_cli(a->fd, "No console device is set as active\n");
01054       return CLI_FAILURE;
01055    }
01056 
01057    if (a->argc != e->args) {
01058       unref_pvt(pvt);
01059       return CLI_SHOWUSAGE;
01060    }
01061 
01062    if (!pvt->owner) {
01063       ast_cli(a->fd, "No one is calling us\n");
01064       unref_pvt(pvt);
01065       return CLI_FAILURE;
01066    }
01067 
01068    pvt->hookstate = 1;
01069 
01070    ast_indicate(pvt->owner, -1);
01071 
01072    ast_queue_control(pvt->owner, AST_CONTROL_ANSWER);
01073 
01074    unref_pvt(pvt);
01075 
01076    return CLI_SUCCESS;
01077 }
01078 
01079 /*!
01080  * \brief Console send text CLI command
01081  *
01082  * \note concatenate all arguments into a single string. argv is NULL-terminated
01083  * so we can use it right away
01084  */
01085 static char *cli_console_sendtext(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01086 {
01087    char buf[TEXT_SIZE];
01088    struct console_pvt *pvt = get_active_pvt();
01089    struct ast_frame f = {
01090       .frametype = AST_FRAME_TEXT,
01091       .data.ptr = buf,
01092       .src = "console_send_text",
01093    };
01094    int len;
01095 
01096    if (cmd == CLI_INIT) {
01097       e->command = "console send text";
01098       e->usage =
01099          "Usage: console send text <message>\n"
01100          "       Sends a text message for display on the remote terminal.\n";
01101       return NULL;
01102    } else if (cmd == CLI_GENERATE)
01103       return NULL;
01104 
01105    if (!pvt) {
01106       ast_cli(a->fd, "No console device is set as active\n");
01107       return CLI_FAILURE;
01108    }
01109 
01110    if (a->argc < e->args + 1) {
01111       unref_pvt(pvt);
01112       return CLI_SHOWUSAGE;
01113    }
01114 
01115    if (!pvt->owner) {
01116       ast_cli(a->fd, "Not in a call\n");
01117       unref_pvt(pvt);
01118       return CLI_FAILURE;
01119    }
01120 
01121    ast_join(buf, sizeof(buf) - 1, a->argv + e->args);
01122    if (ast_strlen_zero(buf)) {
01123       unref_pvt(pvt);
01124       return CLI_SHOWUSAGE;
01125    }
01126 
01127    len = strlen(buf);
01128    buf[len] = '\n';
01129    f.datalen = len + 1;
01130 
01131    ast_queue_frame(pvt->owner, &f);
01132 
01133    unref_pvt(pvt);
01134 
01135    return CLI_SUCCESS;
01136 }
01137 
01138 static void set_active(struct console_pvt *pvt, const char *value)
01139 {
01140    if (pvt == &globals) {
01141       ast_log(LOG_ERROR, "active is only valid as a per-device setting\n");
01142       return;
01143    }
01144 
01145    if (!ast_true(value))
01146       return;
01147 
01148    ast_rwlock_wrlock(&active_lock);
01149    if (active_pvt)
01150       unref_pvt(active_pvt);
01151    active_pvt = ref_pvt(pvt);
01152    ast_rwlock_unlock(&active_lock);
01153 }
01154 
01155 static char *cli_console_active(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01156 {
01157    struct console_pvt *pvt;
01158 
01159    switch (cmd) {
01160    case CLI_INIT:
01161       e->command = "console {set|show} active";
01162       e->usage =
01163          "Usage: console {set|show} active [<device>]\n"
01164          "       Set or show the active console device for the Asterisk CLI.\n";
01165       return NULL;
01166    case CLI_GENERATE:
01167       if (a->pos == e->args) {
01168          struct ao2_iterator i;
01169          int x = 0;
01170          char *res = NULL;
01171          i = ao2_iterator_init(pvts, 0);
01172          while ((pvt = ao2_iterator_next(&i))) {
01173             if (++x > a->n && !strncasecmp(pvt->name, a->word, strlen(a->word)))
01174                res = ast_strdup(pvt->name);
01175             unref_pvt(pvt);
01176             if (res) {
01177                ao2_iterator_destroy(&i);
01178                return res;
01179             }
01180          }
01181          ao2_iterator_destroy(&i);
01182       }
01183       return NULL;
01184    }
01185 
01186    if (a->argc < e->args)
01187       return CLI_SHOWUSAGE;
01188 
01189    if (a->argc == 3) {
01190       pvt = get_active_pvt();
01191 
01192       if (!pvt)
01193          ast_cli(a->fd, "No device is currently set as the active console device.\n");
01194       else {
01195          console_pvt_lock(pvt);
01196          ast_cli(a->fd, "The active console device is '%s'.\n", pvt->name);
01197          console_pvt_unlock(pvt);
01198          pvt = unref_pvt(pvt);
01199       }
01200 
01201       return CLI_SUCCESS;
01202    }
01203 
01204    if (!(pvt = find_pvt(a->argv[e->args - 1]))) {
01205       ast_cli(a->fd, "Could not find a device called '%s'.\n", a->argv[e->args]);
01206       return CLI_FAILURE;
01207    }
01208 
01209    set_active(pvt, "yes");
01210 
01211    console_pvt_lock(pvt);
01212    ast_cli(a->fd, "The active console device has been set to '%s'\n", pvt->name);
01213    console_pvt_unlock(pvt);
01214 
01215    unref_pvt(pvt);
01216 
01217    return CLI_SUCCESS;
01218 }
01219 
01220 static struct ast_cli_entry cli_console[] = {
01221    AST_CLI_DEFINE(cli_console_dial,       "Dial an extension from the console"),
01222    AST_CLI_DEFINE(cli_console_hangup,     "Hangup a call on the console"),
01223    AST_CLI_DEFINE(cli_console_mute,       "Disable/Enable mic input"),
01224    AST_CLI_DEFINE(cli_console_answer,     "Answer an incoming console call"),
01225    AST_CLI_DEFINE(cli_console_sendtext,   "Send text to a connected party"),
01226    AST_CLI_DEFINE(cli_console_flash,      "Send a flash to the connected party"),
01227    AST_CLI_DEFINE(cli_console_autoanswer, "Turn autoanswer on or off"),
01228    AST_CLI_DEFINE(cli_list_available,     "List available devices"),
01229    AST_CLI_DEFINE(cli_list_devices,       "List configured devices"),
01230    AST_CLI_DEFINE(cli_console_active,     "View or Set the active console device"),
01231 };
01232 
01233 /*!
01234  * \brief Set default values for a pvt struct
01235  *
01236  * \note This function expects the pvt lock to be held.
01237  */
01238 static void set_pvt_defaults(struct console_pvt *pvt)
01239 {
01240    if (pvt == &globals) {
01241       ast_string_field_set(pvt, mohinterpret, "default");
01242       ast_string_field_set(pvt, context, "default");
01243       ast_string_field_set(pvt, exten, "s");
01244       ast_string_field_set(pvt, language, "");
01245       ast_string_field_set(pvt, cid_num, "");
01246       ast_string_field_set(pvt, cid_name, "");
01247       ast_string_field_set(pvt, parkinglot, "");
01248    
01249       pvt->overridecontext = 0;
01250       pvt->autoanswer = 0;
01251    } else {
01252       ast_mutex_lock(&globals_lock);
01253 
01254       ast_string_field_set(pvt, mohinterpret, globals.mohinterpret);
01255       ast_string_field_set(pvt, context, globals.context);
01256       ast_string_field_set(pvt, exten, globals.exten);
01257       ast_string_field_set(pvt, language, globals.language);
01258       ast_string_field_set(pvt, cid_num, globals.cid_num);
01259       ast_string_field_set(pvt, cid_name, globals.cid_name);
01260       ast_string_field_set(pvt, parkinglot, globals.parkinglot);
01261 
01262       pvt->overridecontext = globals.overridecontext;
01263       pvt->autoanswer = globals.autoanswer;
01264 
01265       ast_mutex_unlock(&globals_lock);
01266    }
01267 }
01268 
01269 static void store_callerid(struct console_pvt *pvt, const char *value)
01270 {
01271    char cid_name[256];
01272    char cid_num[256];
01273 
01274    ast_callerid_split(value, cid_name, sizeof(cid_name), 
01275       cid_num, sizeof(cid_num));
01276 
01277    ast_string_field_set(pvt, cid_name, cid_name);
01278    ast_string_field_set(pvt, cid_num, cid_num);
01279 }
01280 
01281 /*!
01282  * \brief Store a configuration parameter in a pvt struct
01283  *
01284  * \note This function expects the pvt lock to be held.
01285  */
01286 static void store_config_core(struct console_pvt *pvt, const char *var, const char *value)
01287 {
01288    if (pvt == &globals && !ast_jb_read_conf(&global_jbconf, var, value))
01289       return;
01290 
01291    CV_START(var, value);
01292 
01293    CV_STRFIELD("context", pvt, context);
01294    CV_STRFIELD("extension", pvt, exten);
01295    CV_STRFIELD("mohinterpret", pvt, mohinterpret);
01296    CV_STRFIELD("language", pvt, language);
01297    CV_F("callerid", store_callerid(pvt, value));
01298    CV_BOOL("overridecontext", pvt->overridecontext);
01299    CV_BOOL("autoanswer", pvt->autoanswer);
01300    CV_STRFIELD("parkinglot", pvt, parkinglot);
01301 
01302    if (pvt != &globals) {
01303       CV_F("active", set_active(pvt, value))
01304       CV_STRFIELD("input_device", pvt, input_device);
01305       CV_STRFIELD("output_device", pvt, output_device);
01306    }
01307 
01308    ast_log(LOG_WARNING, "Unknown option '%s'\n", var);
01309 
01310    CV_END;
01311 }
01312 
01313 static void pvt_destructor(void *obj)
01314 {
01315    struct console_pvt *pvt = obj;
01316 
01317    ast_string_field_free_memory(pvt);
01318 }
01319 
01320 static int init_pvt(struct console_pvt *pvt, const char *name)
01321 {
01322    pvt->thread = AST_PTHREADT_NULL;
01323 
01324    if (ast_string_field_init(pvt, 32))
01325       return -1;
01326 
01327    ast_string_field_set(pvt, name, S_OR(name, ""));
01328 
01329    return 0;
01330 }
01331 
01332 static void build_device(struct ast_config *cfg, const char *name)
01333 {
01334    struct ast_variable *v;
01335    struct console_pvt *pvt;
01336    int new = 0;
01337 
01338    if ((pvt = find_pvt(name))) {
01339       console_pvt_lock(pvt);
01340       set_pvt_defaults(pvt);
01341       pvt->destroy = 0;
01342    } else {
01343       if (!(pvt = ao2_alloc(sizeof(*pvt), pvt_destructor)))
01344          return;
01345       init_pvt(pvt, name);
01346       set_pvt_defaults(pvt);
01347       new = 1;
01348    }
01349 
01350    for (v = ast_variable_browse(cfg, name); v; v = v->next)
01351       store_config_core(pvt, v->name, v->value);
01352 
01353    if (new)
01354       ao2_link(pvts, pvt);
01355    else
01356       console_pvt_unlock(pvt);
01357    
01358    unref_pvt(pvt);
01359 }
01360 
01361 static int pvt_mark_destroy_cb(void *obj, void *arg, int flags)
01362 {
01363    struct console_pvt *pvt = obj;
01364    pvt->destroy = 1;
01365    return 0;
01366 }
01367 
01368 static void destroy_pvts(void)
01369 {
01370    struct ao2_iterator i;
01371    struct console_pvt *pvt;
01372 
01373    i = ao2_iterator_init(pvts, 0);
01374    while ((pvt = ao2_iterator_next(&i))) {
01375       if (pvt->destroy) {
01376          ao2_unlink(pvts, pvt);
01377          ast_rwlock_wrlock(&active_lock);
01378          if (active_pvt == pvt)
01379             active_pvt = unref_pvt(pvt);
01380          ast_rwlock_unlock(&active_lock);
01381       }
01382       unref_pvt(pvt);
01383    }
01384    ao2_iterator_destroy(&i);
01385 }
01386 
01387 /*!
01388  * \brief Load the configuration
01389  * \param reload if this was called due to a reload
01390  * \retval 0 success
01391  * \retval -1 failure
01392  */
01393 static int load_config(int reload)
01394 {
01395    struct ast_config *cfg;
01396    struct ast_variable *v;
01397    struct ast_flags config_flags = { 0 };
01398    char *context = NULL;
01399 
01400    /* default values */
01401    memcpy(&global_jbconf, &default_jbconf, sizeof(global_jbconf));
01402    ast_mutex_lock(&globals_lock);
01403    set_pvt_defaults(&globals);
01404    ast_mutex_unlock(&globals_lock);
01405 
01406    if (!(cfg = ast_config_load(config_file, config_flags))) {
01407       ast_log(LOG_NOTICE, "Unable to open configuration file %s!\n", config_file);
01408       return -1;
01409    } else if (cfg == CONFIG_STATUS_FILEINVALID) {
01410       ast_log(LOG_NOTICE, "Config file %s has an invalid format\n", config_file);
01411       return -1;
01412    }
01413    
01414    ao2_callback(pvts, OBJ_NODATA, pvt_mark_destroy_cb, NULL);
01415 
01416    ast_mutex_lock(&globals_lock);
01417    for (v = ast_variable_browse(cfg, "general"); v; v = v->next)
01418       store_config_core(&globals, v->name, v->value);
01419    ast_mutex_unlock(&globals_lock);
01420 
01421    while ((context = ast_category_browse(cfg, context))) {
01422       if (strcasecmp(context, "general"))
01423          build_device(cfg, context);
01424    }
01425 
01426    ast_config_destroy(cfg);
01427 
01428    destroy_pvts();
01429 
01430    return 0;
01431 }
01432 
01433 static int pvt_hash_cb(const void *obj, const int flags)
01434 {
01435    const struct console_pvt *pvt = obj;
01436 
01437    return ast_str_case_hash(pvt->name);
01438 }
01439 
01440 static int pvt_cmp_cb(void *obj, void *arg, int flags)
01441 {
01442    struct console_pvt *pvt = obj, *pvt2 = arg;
01443 
01444    return !strcasecmp(pvt->name, pvt2->name) ? CMP_MATCH | CMP_STOP : 0;
01445 }
01446 
01447 static void stop_streams(void)
01448 {
01449    struct console_pvt *pvt;
01450    struct ao2_iterator i;
01451 
01452    i = ao2_iterator_init(pvts, 0);
01453    while ((pvt = ao2_iterator_next(&i))) {
01454       if (pvt->hookstate)
01455          stop_stream(pvt);
01456       unref_pvt(pvt);
01457    }
01458    ao2_iterator_destroy(&i);
01459 }
01460 
01461 static int unload_module(void)
01462 {
01463    ast_channel_unregister(&console_tech);
01464    ast_cli_unregister_multiple(cli_console, ARRAY_LEN(cli_console));
01465 
01466    stop_streams();
01467 
01468    Pa_Terminate();
01469 
01470    /* Will unref all the pvts so they will get destroyed, too */
01471    ao2_ref(pvts, -1);
01472 
01473    pvt_destructor(&globals);
01474 
01475    return 0;
01476 }
01477 
01478 static int load_module(void)
01479 {
01480    PaError res;
01481 
01482    init_pvt(&globals, NULL);
01483 
01484    if (!(pvts = ao2_container_alloc(NUM_PVT_BUCKETS, pvt_hash_cb, pvt_cmp_cb)))
01485       goto return_error;
01486 
01487    if (load_config(0))
01488       goto return_error;
01489 
01490    res = Pa_Initialize();
01491    if (res != paNoError) {
01492       ast_log(LOG_WARNING, "Failed to initialize audio system - (%d) %s\n",
01493          res, Pa_GetErrorText(res));
01494       goto return_error_pa_init;
01495    }
01496 
01497    if (ast_channel_register(&console_tech)) {
01498       ast_log(LOG_ERROR, "Unable to register channel type 'Console'\n");
01499       goto return_error_chan_reg;
01500    }
01501 
01502    if (ast_cli_register_multiple(cli_console, ARRAY_LEN(cli_console)))
01503       goto return_error_cli_reg;
01504 
01505    return AST_MODULE_LOAD_SUCCESS;
01506 
01507 return_error_cli_reg:
01508    ast_cli_unregister_multiple(cli_console, ARRAY_LEN(cli_console));
01509 return_error_chan_reg:
01510    ast_channel_unregister(&console_tech);
01511 return_error_pa_init:
01512    Pa_Terminate();
01513 return_error:
01514    if (pvts)
01515       ao2_ref(pvts, -1);
01516    pvts = NULL;
01517    pvt_destructor(&globals);
01518 
01519    return AST_MODULE_LOAD_DECLINE;
01520 }
01521 
01522 static int reload(void)
01523 {
01524    return load_config(1);
01525 }
01526 
01527 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Console Channel Driver",
01528       .load = load_module,
01529       .unload = unload_module,
01530       .reload = reload,
01531       .load_pri = AST_MODPRI_CHANNEL_DRIVER,
01532 );

Generated on Mon Oct 8 12:38:58 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7