Mon Jun 27 16:50:49 2011

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

Generated on Mon Jun 27 16:50:49 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7