Tue Mar 2 17:31:44 2010

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

Generated on 2 Mar 2010 for Asterisk - the Open Source PBX by  doxygen 1.6.1