Thu Jul 9 13:40:23 2009

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

Generated on Thu Jul 9 13:40:23 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7