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

Generated on Thu Apr 16 06:27:18 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6