Wed Apr 6 11:29:42 2011

Asterisk developer's documentation


chan_oss.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2007, Digium, Inc.
00005  *
00006  * Mark Spencer <markster@digium.com>
00007  *
00008  * FreeBSD changes and multiple device support by Luigi Rizzo, 2005.05.25
00009  * note-this code best seen with ts=8 (8-spaces tabs) in the editor
00010  *
00011  * See http://www.asterisk.org for more information about
00012  * the Asterisk project. Please do not directly contact
00013  * any of the maintainers of this project for assistance;
00014  * the project provides a web site, mailing lists and IRC
00015  * channels for your use.
00016  *
00017  * This program is free software, distributed under the terms of
00018  * the GNU General Public License Version 2. See the LICENSE file
00019  * at the top of the source tree.
00020  */
00021 
00022 // #define HAVE_VIDEO_CONSOLE // uncomment to enable video
00023 /*! \file
00024  *
00025  * \brief Channel driver for OSS sound cards
00026  *
00027  * \author Mark Spencer <markster@digium.com>
00028  * \author Luigi Rizzo
00029  *
00030  * \par See also
00031  * \arg \ref Config_oss
00032  *
00033  * \ingroup channel_drivers
00034  */
00035 
00036 /*** MODULEINFO
00037    <depend>oss</depend>
00038  ***/
00039 
00040 #include "asterisk.h"
00041 
00042 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 276393 $")
00043 
00044 #include <ctype.h>      /* isalnum() used here */
00045 #include <math.h>
00046 #include <sys/ioctl.h>     
00047 
00048 #ifdef __linux
00049 #include <linux/soundcard.h>
00050 #elif defined(__FreeBSD__) || defined(__CYGWIN__)
00051 #include <sys/soundcard.h>
00052 #else
00053 #include <soundcard.h>
00054 #endif
00055 
00056 #include "asterisk/channel.h"
00057 #include "asterisk/file.h"
00058 #include "asterisk/callerid.h"
00059 #include "asterisk/module.h"
00060 #include "asterisk/pbx.h"
00061 #include "asterisk/cli.h"
00062 #include "asterisk/causes.h"
00063 #include "asterisk/musiconhold.h"
00064 #include "asterisk/app.h"
00065 
00066 #include "console_video.h"
00067 
00068 /*! Global jitterbuffer configuration - by default, jb is disabled */
00069 static struct ast_jb_conf default_jbconf =
00070 {
00071    .flags = 0,
00072    .max_size = -1,
00073    .resync_threshold = -1,
00074    .impl = "",
00075    .target_extra = -1,
00076 };
00077 static struct ast_jb_conf global_jbconf;
00078 
00079 /*
00080  * Basic mode of operation:
00081  *
00082  * we have one keyboard (which receives commands from the keyboard)
00083  * and multiple headset's connected to audio cards.
00084  * Cards/Headsets are named as the sections of oss.conf.
00085  * The section called [general] contains the default parameters.
00086  *
00087  * At any time, the keyboard is attached to one card, and you
00088  * can switch among them using the command 'console foo'
00089  * where 'foo' is the name of the card you want.
00090  *
00091  * oss.conf parameters are
00092 START_CONFIG
00093 
00094 [general]
00095     ; General config options, with default values shown.
00096     ; You should use one section per device, with [general] being used
00097     ; for the first device and also as a template for other devices.
00098     ;
00099     ; All but 'debug' can go also in the device-specific sections.
00100     ;
00101     ; debug = 0x0    ; misc debug flags, default is 0
00102 
00103     ; Set the device to use for I/O
00104     ; device = /dev/dsp
00105 
00106     ; Optional mixer command to run upon startup (e.g. to set
00107     ; volume levels, mutes, etc.
00108     ; mixer =
00109 
00110     ; Software mic volume booster (or attenuator), useful for sound
00111     ; cards or microphones with poor sensitivity. The volume level
00112     ; is in dB, ranging from -20.0 to +20.0
00113     ; boost = n         ; mic volume boost in dB
00114 
00115     ; Set the callerid for outgoing calls
00116     ; callerid = John Doe <555-1234>
00117 
00118     ; autoanswer = no      ; no autoanswer on call
00119     ; autohangup = yes     ; hangup when other party closes
00120     ; extension = s     ; default extension to call
00121     ; context = default    ; default context for outgoing calls
00122     ; language = ""     ; default language
00123 
00124     ; Default Music on Hold class to use when this channel is placed on hold in
00125     ; the case that the music class is not set on the channel with
00126     ; Set(CHANNEL(musicclass)=whatever) in the dialplan and the peer channel
00127     ; putting this one on hold did not suggest a class to use.
00128     ;
00129     ; mohinterpret=default
00130 
00131     ; If you set overridecontext to 'yes', then the whole dial string
00132     ; will be interpreted as an extension, which is extremely useful
00133     ; to dial SIP, IAX and other extensions which use the '@' character.
00134     ; The default is 'no' just for backward compatibility, but the
00135     ; suggestion is to change it.
00136     ; overridecontext = no ; if 'no', the last @ will start the context
00137             ; if 'yes' the whole string is an extension.
00138 
00139     ; low level device parameters in case you have problems with the
00140     ; device driver on your operating system. You should not touch these
00141     ; unless you know what you are doing.
00142     ; queuesize = 10    ; frames in device driver
00143     ; frags = 8         ; argument to SETFRAGMENT
00144 
00145     ;------------------------------ JITTER BUFFER CONFIGURATION --------------------------
00146     ; jbenable = yes              ; Enables the use of a jitterbuffer on the receiving side of an
00147                                   ; OSS channel. Defaults to "no". An enabled jitterbuffer will
00148                                   ; be used only if the sending side can create and the receiving
00149                                   ; side can not accept jitter. The OSS channel can't accept jitter,
00150                                   ; thus an enabled jitterbuffer on the receive OSS side will always
00151                                   ; be used if the sending side can create jitter.
00152 
00153     ; jbmaxsize = 200             ; Max length of the jitterbuffer in milliseconds.
00154 
00155     ; jbresyncthreshold = 1000    ; Jump in the frame timestamps over which the jitterbuffer is
00156                                   ; resynchronized. Useful to improve the quality of the voice, with
00157                                   ; big jumps in/broken timestamps, usualy sent from exotic devices
00158                                   ; and programs. Defaults to 1000.
00159 
00160     ; jbimpl = fixed              ; Jitterbuffer implementation, used on the receiving side of an OSS
00161                                   ; channel. Two implementations are currenlty available - "fixed"
00162                                   ; (with size always equals to jbmax-size) and "adaptive" (with
00163                                   ; variable size, actually the new jb of IAX2). Defaults to fixed.
00164 
00165     ; jblog = no                  ; Enables jitterbuffer frame logging. Defaults to "no".
00166     ;-----------------------------------------------------------------------------------
00167 
00168 [card1]
00169     ; device = /dev/dsp1   ; alternate device
00170 
00171 END_CONFIG
00172 
00173 .. and so on for the other cards.
00174 
00175  */
00176 
00177 /*
00178  * The following parameters are used in the driver:
00179  *
00180  *  FRAME_SIZE the size of an audio frame, in samples.
00181  *    160 is used almost universally, so you should not change it.
00182  *
00183  *  FRAGS   the argument for the SETFRAGMENT ioctl.
00184  *    Overridden by the 'frags' parameter in oss.conf
00185  *
00186  *    Bits 0-7 are the base-2 log of the device's block size,
00187  *    bits 16-31 are the number of blocks in the driver's queue.
00188  *    There are a lot of differences in the way this parameter
00189  *    is supported by different drivers, so you may need to
00190  *    experiment a bit with the value.
00191  *    A good default for linux is 30 blocks of 64 bytes, which
00192  *    results in 6 frames of 320 bytes (160 samples).
00193  *    FreeBSD works decently with blocks of 256 or 512 bytes,
00194  *    leaving the number unspecified.
00195  *    Note that this only refers to the device buffer size,
00196  *    this module will then try to keep the lenght of audio
00197  *    buffered within small constraints.
00198  *
00199  *  QUEUE_SIZE The max number of blocks actually allowed in the device
00200  *    driver's buffer, irrespective of the available number.
00201  *    Overridden by the 'queuesize' parameter in oss.conf
00202  *
00203  *    Should be >=2, and at most as large as the hw queue above
00204  *    (otherwise it will never be full).
00205  */
00206 
00207 #define FRAME_SIZE   160
00208 #define  QUEUE_SIZE  10
00209 
00210 #if defined(__FreeBSD__)
00211 #define  FRAGS 0x8
00212 #else
00213 #define  FRAGS ( ( (6 * 5) << 16 ) | 0x6 )
00214 #endif
00215 
00216 /*
00217  * XXX text message sizes are probably 256 chars, but i am
00218  * not sure if there is a suitable definition anywhere.
00219  */
00220 #define TEXT_SIZE 256
00221 
00222 #if 0
00223 #define  TRYOPEN  1           /* try to open on startup */
00224 #endif
00225 #define  O_CLOSE  0x444       /* special 'close' mode for device */
00226 /* Which device to use */
00227 #if defined( __OpenBSD__ ) || defined( __NetBSD__ )
00228 #define DEV_DSP "/dev/audio"
00229 #else
00230 #define DEV_DSP "/dev/dsp"
00231 #endif
00232 
00233 static char *config = "oss.conf";   /* default config file */
00234 
00235 static int oss_debug;
00236 
00237 /*!
00238  * \brief descriptor for one of our channels.
00239  *
00240  * There is one used for 'default' values (from the [general] entry in
00241  * the configuration file), and then one instance for each device
00242  * (the default is cloned from [general], others are only created
00243  * if the relevant section exists).
00244  */
00245 struct chan_oss_pvt {
00246    struct chan_oss_pvt *next;
00247 
00248    char *name;
00249    int total_blocks;       /*!< total blocks in the output device */
00250    int sounddev;
00251    enum { M_UNSET, M_FULL, M_READ, M_WRITE } duplex;
00252    int autoanswer;             /*!< Boolean: whether to answer the immediately upon calling */
00253    int autohangup;             /*!< Boolean: whether to hangup the call when the remote end hangs up */
00254    int hookstate;              /*!< Boolean: 1 if offhook; 0 if onhook */
00255    char *mixer_cmd;        /*!< initial command to issue to the mixer */
00256    unsigned int queuesize;    /*!< max fragments in queue */
00257    unsigned int frags;        /*!< parameter for SETFRAGMENT */
00258 
00259    int warned;             /*!< various flags used for warnings */
00260 #define WARN_used_blocks   1
00261 #define WARN_speed      2
00262 #define WARN_frag    4
00263    int w_errors;           /*!< overfull in the write path */
00264    struct timeval lastopen;
00265 
00266    int overridecontext;
00267    int mute;
00268 
00269    /*! boost support. BOOST_SCALE * 10 ^(BOOST_MAX/20) must
00270     *  be representable in 16 bits to avoid overflows.
00271     */
00272 #define  BOOST_SCALE (1<<9)
00273 #define  BOOST_MAX   40       /*!< slightly less than 7 bits */
00274    int boost;              /*!< input boost, scaled by BOOST_SCALE */
00275    char device[64];        /*!< device to open */
00276 
00277    pthread_t sthread;
00278 
00279    struct ast_channel *owner;
00280 
00281    struct video_desc *env;       /*!< parameters for video support */
00282 
00283    char ext[AST_MAX_EXTENSION];
00284    char ctx[AST_MAX_CONTEXT];
00285    char language[MAX_LANGUAGE];
00286    char cid_name[256];         /*!< Initial CallerID name */
00287    char cid_num[256];          /*!< Initial CallerID number  */
00288    char mohinterpret[MAX_MUSICCLASS];
00289 
00290    /*! buffers used in oss_write */
00291    char oss_write_buf[FRAME_SIZE * 2];
00292    int oss_write_dst;
00293    /*! buffers used in oss_read - AST_FRIENDLY_OFFSET space for headers
00294     *  plus enough room for a full frame
00295     */
00296    char oss_read_buf[FRAME_SIZE * 2 + AST_FRIENDLY_OFFSET];
00297    int readpos;            /*!< read position above */
00298    struct ast_frame read_f;   /*!< returned by oss_read */
00299 };
00300 
00301 /*! forward declaration */
00302 static struct chan_oss_pvt *find_desc(const char *dev);
00303 
00304 static char *oss_active;    /*!< the active device */
00305 
00306 /*! \brief return the pointer to the video descriptor */
00307 struct video_desc *get_video_desc(struct ast_channel *c)
00308 {
00309    struct chan_oss_pvt *o = c ? c->tech_pvt : find_desc(oss_active);
00310    return o ? o->env : NULL;
00311 }
00312 static struct chan_oss_pvt oss_default = {
00313    .sounddev = -1,
00314    .duplex = M_UNSET,         /* XXX check this */
00315    .autoanswer = 1,
00316    .autohangup = 1,
00317    .queuesize = QUEUE_SIZE,
00318    .frags = FRAGS,
00319    .ext = "s",
00320    .ctx = "default",
00321    .readpos = AST_FRIENDLY_OFFSET,  /* start here on reads */
00322    .lastopen = { 0, 0 },
00323    .boost = BOOST_SCALE,
00324 };
00325 
00326 
00327 static int setformat(struct chan_oss_pvt *o, int mode);
00328 
00329 static struct ast_channel *oss_request(const char *type, format_t format, const struct ast_channel *requestor,
00330                               void *data, int *cause);
00331 static int oss_digit_begin(struct ast_channel *c, char digit);
00332 static int oss_digit_end(struct ast_channel *c, char digit, unsigned int duration);
00333 static int oss_text(struct ast_channel *c, const char *text);
00334 static int oss_hangup(struct ast_channel *c);
00335 static int oss_answer(struct ast_channel *c);
00336 static struct ast_frame *oss_read(struct ast_channel *chan);
00337 static int oss_call(struct ast_channel *c, char *dest, int timeout);
00338 static int oss_write(struct ast_channel *chan, struct ast_frame *f);
00339 static int oss_indicate(struct ast_channel *chan, int cond, const void *data, size_t datalen);
00340 static int oss_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
00341 static char tdesc[] = "OSS Console Channel Driver";
00342 
00343 /* cannot do const because need to update some fields at runtime */
00344 static struct ast_channel_tech oss_tech = {
00345    .type = "Console",
00346    .description = tdesc,
00347    .capabilities = AST_FORMAT_SLINEAR, /* overwritten later */
00348    .requester = oss_request,
00349    .send_digit_begin = oss_digit_begin,
00350    .send_digit_end = oss_digit_end,
00351    .send_text = oss_text,
00352    .hangup = oss_hangup,
00353    .answer = oss_answer,
00354    .read = oss_read,
00355    .call = oss_call,
00356    .write = oss_write,
00357    .write_video = console_write_video,
00358    .indicate = oss_indicate,
00359    .fixup = oss_fixup,
00360 };
00361 
00362 /*!
00363  * \brief returns a pointer to the descriptor with the given name
00364  */
00365 static struct chan_oss_pvt *find_desc(const char *dev)
00366 {
00367    struct chan_oss_pvt *o = NULL;
00368 
00369    if (!dev)
00370       ast_log(LOG_WARNING, "null dev\n");
00371 
00372    for (o = oss_default.next; o && o->name && dev && strcmp(o->name, dev) != 0; o = o->next);
00373 
00374    if (!o)
00375       ast_log(LOG_WARNING, "could not find <%s>\n", dev ? dev : "--no-device--");
00376 
00377    return o;
00378 }
00379 
00380 /* !
00381  * \brief split a string in extension-context, returns pointers to malloc'ed
00382  *        strings.
00383  *
00384  * If we do not have 'overridecontext' then the last @ is considered as
00385  * a context separator, and the context is overridden.
00386  * This is usually not very necessary as you can play with the dialplan,
00387  * and it is nice not to need it because you have '@' in SIP addresses.
00388  *
00389  * \return the buffer address.
00390  */
00391 static char *ast_ext_ctx(const char *src, char **ext, char **ctx)
00392 {
00393    struct chan_oss_pvt *o = find_desc(oss_active);
00394 
00395    if (ext == NULL || ctx == NULL)
00396       return NULL;         /* error */
00397 
00398    *ext = *ctx = NULL;
00399 
00400    if (src && *src != '\0')
00401       *ext = ast_strdup(src);
00402 
00403    if (*ext == NULL)
00404       return NULL;
00405 
00406    if (!o->overridecontext) {
00407       /* parse from the right */
00408       *ctx = strrchr(*ext, '@');
00409       if (*ctx)
00410          *(*ctx)++ = '\0';
00411    }
00412 
00413    return *ext;
00414 }
00415 
00416 /*!
00417  * \brief Returns the number of blocks used in the audio output channel
00418  */
00419 static int used_blocks(struct chan_oss_pvt *o)
00420 {
00421    struct audio_buf_info info;
00422 
00423    if (ioctl(o->sounddev, SNDCTL_DSP_GETOSPACE, &info)) {
00424       if (!(o->warned & WARN_used_blocks)) {
00425          ast_log(LOG_WARNING, "Error reading output space\n");
00426          o->warned |= WARN_used_blocks;
00427       }
00428       return 1;
00429    }
00430 
00431    if (o->total_blocks == 0) {
00432       if (0)               /* debugging */
00433          ast_log(LOG_WARNING, "fragtotal %d size %d avail %d\n", info.fragstotal, info.fragsize, info.fragments);
00434       o->total_blocks = info.fragments;
00435    }
00436 
00437    return o->total_blocks - info.fragments;
00438 }
00439 
00440 /*! Write an exactly FRAME_SIZE sized frame */
00441 static int soundcard_writeframe(struct chan_oss_pvt *o, short *data)
00442 {
00443    int res;
00444 
00445    if (o->sounddev < 0)
00446       setformat(o, O_RDWR);
00447    if (o->sounddev < 0)
00448       return 0;            /* not fatal */
00449    /*
00450     * Nothing complex to manage the audio device queue.
00451     * If the buffer is full just drop the extra, otherwise write.
00452     * XXX in some cases it might be useful to write anyways after
00453     * a number of failures, to restart the output chain.
00454     */
00455    res = used_blocks(o);
00456    if (res > o->queuesize) {  /* no room to write a block */
00457       if (o->w_errors++ == 0 && (oss_debug & 0x4))
00458          ast_log(LOG_WARNING, "write: used %d blocks (%d)\n", res, o->w_errors);
00459       return 0;
00460    }
00461    o->w_errors = 0;
00462    return write(o->sounddev, (void *)data, FRAME_SIZE * 2);
00463 }
00464 
00465 /*!
00466  * reset and close the device if opened,
00467  * then open and initialize it in the desired mode,
00468  * trigger reads and writes so we can start using it.
00469  */
00470 static int setformat(struct chan_oss_pvt *o, int mode)
00471 {
00472    int fmt, desired, res, fd;
00473 
00474    if (o->sounddev >= 0) {
00475       ioctl(o->sounddev, SNDCTL_DSP_RESET, 0);
00476       close(o->sounddev);
00477       o->duplex = M_UNSET;
00478       o->sounddev = -1;
00479    }
00480    if (mode == O_CLOSE)    /* we are done */
00481       return 0;
00482    if (ast_tvdiff_ms(ast_tvnow(), o->lastopen) < 1000)
00483       return -1;           /* don't open too often */
00484    o->lastopen = ast_tvnow();
00485    fd = o->sounddev = open(o->device, mode | O_NONBLOCK);
00486    if (fd < 0) {
00487       ast_log(LOG_WARNING, "Unable to re-open DSP device %s: %s\n", o->device, strerror(errno));
00488       return -1;
00489    }
00490    if (o->owner)
00491       ast_channel_set_fd(o->owner, 0, fd);
00492 
00493 #if __BYTE_ORDER == __LITTLE_ENDIAN
00494    fmt = AFMT_S16_LE;
00495 #else
00496    fmt = AFMT_S16_BE;
00497 #endif
00498    res = ioctl(fd, SNDCTL_DSP_SETFMT, &fmt);
00499    if (res < 0) {
00500       ast_log(LOG_WARNING, "Unable to set format to 16-bit signed\n");
00501       return -1;
00502    }
00503    switch (mode) {
00504    case O_RDWR:
00505       res = ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0);
00506       /* Check to see if duplex set (FreeBSD Bug) */
00507       res = ioctl(fd, SNDCTL_DSP_GETCAPS, &fmt);
00508       if (res == 0 && (fmt & DSP_CAP_DUPLEX)) {
00509          ast_verb(2, "Console is full duplex\n");
00510          o->duplex = M_FULL;
00511       };
00512       break;
00513 
00514    case O_WRONLY:
00515       o->duplex = M_WRITE;
00516       break;
00517 
00518    case O_RDONLY:
00519       o->duplex = M_READ;
00520       break;
00521    }
00522 
00523    fmt = 0;
00524    res = ioctl(fd, SNDCTL_DSP_STEREO, &fmt);
00525    if (res < 0) {
00526       ast_log(LOG_WARNING, "Failed to set audio device to mono\n");
00527       return -1;
00528    }
00529    fmt = desired = DEFAULT_SAMPLE_RATE;   /* 8000 Hz desired */
00530    res = ioctl(fd, SNDCTL_DSP_SPEED, &fmt);
00531 
00532    if (res < 0) {
00533       ast_log(LOG_WARNING, "Failed to set audio device to mono\n");
00534       return -1;
00535    }
00536    if (fmt != desired) {
00537       if (!(o->warned & WARN_speed)) {
00538          ast_log(LOG_WARNING,
00539              "Requested %d Hz, got %d Hz -- sound may be choppy\n",
00540              desired, fmt);
00541          o->warned |= WARN_speed;
00542       }
00543    }
00544    /*
00545     * on Freebsd, SETFRAGMENT does not work very well on some cards.
00546     * Default to use 256 bytes, let the user override
00547     */
00548    if (o->frags) {
00549       fmt = o->frags;
00550       res = ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &fmt);
00551       if (res < 0) {
00552          if (!(o->warned & WARN_frag)) {
00553             ast_log(LOG_WARNING,
00554                "Unable to set fragment size -- sound may be choppy\n");
00555             o->warned |= WARN_frag;
00556          }
00557       }
00558    }
00559    /* on some cards, we need SNDCTL_DSP_SETTRIGGER to start outputting */
00560    res = PCM_ENABLE_INPUT | PCM_ENABLE_OUTPUT;
00561    res = ioctl(fd, SNDCTL_DSP_SETTRIGGER, &res);
00562    /* it may fail if we are in half duplex, never mind */
00563    return 0;
00564 }
00565 
00566 /*
00567  * some of the standard methods supported by channels.
00568  */
00569 static int oss_digit_begin(struct ast_channel *c, char digit)
00570 {
00571    return 0;
00572 }
00573 
00574 static int oss_digit_end(struct ast_channel *c, char digit, unsigned int duration)
00575 {
00576    /* no better use for received digits than print them */
00577    ast_verbose(" << Console Received digit %c of duration %u ms >> \n", 
00578       digit, duration);
00579    return 0;
00580 }
00581 
00582 static int oss_text(struct ast_channel *c, const char *text)
00583 {
00584    /* print received messages */
00585    ast_verbose(" << Console Received text %s >> \n", text);
00586    return 0;
00587 }
00588 
00589 /*!
00590  * \brief handler for incoming calls. Either autoanswer, or start ringing
00591  */
00592 static int oss_call(struct ast_channel *c, char *dest, int timeout)
00593 {
00594    struct chan_oss_pvt *o = c->tech_pvt;
00595    struct ast_frame f = { AST_FRAME_CONTROL, };
00596    AST_DECLARE_APP_ARGS(args,
00597       AST_APP_ARG(name);
00598       AST_APP_ARG(flags);
00599    );
00600    char *parse = ast_strdupa(dest);
00601 
00602    AST_NONSTANDARD_APP_ARGS(args, parse, '/');
00603 
00604    ast_verbose(" << Call to device '%s' dnid '%s' rdnis '%s' on console from '%s' <%s> >>\n",
00605       dest,
00606       S_OR(c->dialed.number.str, ""),
00607       S_COR(c->redirecting.from.number.valid, c->redirecting.from.number.str, ""),
00608       S_COR(c->caller.id.name.valid, c->caller.id.name.str, ""),
00609       S_COR(c->caller.id.number.valid, c->caller.id.number.str, ""));
00610    if (!ast_strlen_zero(args.flags) && strcasecmp(args.flags, "answer") == 0) {
00611       f.subclass.integer = AST_CONTROL_ANSWER;
00612       ast_queue_frame(c, &f);
00613    } else if (!ast_strlen_zero(args.flags) && strcasecmp(args.flags, "noanswer") == 0) {
00614       f.subclass.integer = AST_CONTROL_RINGING;
00615       ast_queue_frame(c, &f);
00616       ast_indicate(c, AST_CONTROL_RINGING);
00617    } else if (o->autoanswer) {
00618       ast_verbose(" << Auto-answered >> \n");
00619       f.subclass.integer = AST_CONTROL_ANSWER;
00620       ast_queue_frame(c, &f);
00621       o->hookstate = 1;
00622    } else {
00623       ast_verbose("<< Type 'answer' to answer, or use 'autoanswer' for future calls >> \n");
00624       f.subclass.integer = AST_CONTROL_RINGING;
00625       ast_queue_frame(c, &f);
00626       ast_indicate(c, AST_CONTROL_RINGING);
00627    }
00628    return 0;
00629 }
00630 
00631 /*!
00632  * \brief remote side answered the phone
00633  */
00634 static int oss_answer(struct ast_channel *c)
00635 {
00636    struct chan_oss_pvt *o = c->tech_pvt;
00637    ast_verbose(" << Console call has been answered >> \n");
00638    ast_setstate(c, AST_STATE_UP);
00639    o->hookstate = 1;
00640    return 0;
00641 }
00642 
00643 static int oss_hangup(struct ast_channel *c)
00644 {
00645    struct chan_oss_pvt *o = c->tech_pvt;
00646 
00647    c->tech_pvt = NULL;
00648    o->owner = NULL;
00649    ast_verbose(" << Hangup on console >> \n");
00650    console_video_uninit(o->env);
00651    ast_module_unref(ast_module_info->self);
00652    if (o->hookstate) {
00653       if (o->autoanswer || o->autohangup) {
00654          /* Assume auto-hangup too */
00655          o->hookstate = 0;
00656          setformat(o, O_CLOSE);
00657       }
00658    }
00659    return 0;
00660 }
00661 
00662 /*! \brief used for data coming from the network */
00663 static int oss_write(struct ast_channel *c, struct ast_frame *f)
00664 {
00665    int src;
00666    struct chan_oss_pvt *o = c->tech_pvt;
00667 
00668    /*
00669     * we could receive a block which is not a multiple of our
00670     * FRAME_SIZE, so buffer it locally and write to the device
00671     * in FRAME_SIZE chunks.
00672     * Keep the residue stored for future use.
00673     */
00674    src = 0;             /* read position into f->data */
00675    while (src < f->datalen) {
00676       /* Compute spare room in the buffer */
00677       int l = sizeof(o->oss_write_buf) - o->oss_write_dst;
00678 
00679       if (f->datalen - src >= l) {  /* enough to fill a frame */
00680          memcpy(o->oss_write_buf + o->oss_write_dst, f->data.ptr + src, l);
00681          soundcard_writeframe(o, (short *) o->oss_write_buf);
00682          src += l;
00683          o->oss_write_dst = 0;
00684       } else {          /* copy residue */
00685          l = f->datalen - src;
00686          memcpy(o->oss_write_buf + o->oss_write_dst, f->data.ptr + src, l);
00687          src += l;         /* but really, we are done */
00688          o->oss_write_dst += l;
00689       }
00690    }
00691    return 0;
00692 }
00693 
00694 static struct ast_frame *oss_read(struct ast_channel *c)
00695 {
00696    int res;
00697    struct chan_oss_pvt *o = c->tech_pvt;
00698    struct ast_frame *f = &o->read_f;
00699 
00700    /* XXX can be simplified returning &ast_null_frame */
00701    /* prepare a NULL frame in case we don't have enough data to return */
00702    memset(f, '\0', sizeof(struct ast_frame));
00703    f->frametype = AST_FRAME_NULL;
00704    f->src = oss_tech.type;
00705 
00706    res = read(o->sounddev, o->oss_read_buf + o->readpos, sizeof(o->oss_read_buf) - o->readpos);
00707    if (res < 0)            /* audio data not ready, return a NULL frame */
00708       return f;
00709 
00710    o->readpos += res;
00711    if (o->readpos < sizeof(o->oss_read_buf)) /* not enough samples */
00712       return f;
00713 
00714    if (o->mute)
00715       return f;
00716 
00717    o->readpos = AST_FRIENDLY_OFFSET;   /* reset read pointer for next frame */
00718    if (c->_state != AST_STATE_UP)   /* drop data if frame is not up */
00719       return f;
00720    /* ok we can build and deliver the frame to the caller */
00721    f->frametype = AST_FRAME_VOICE;
00722    f->subclass.codec = AST_FORMAT_SLINEAR;
00723    f->samples = FRAME_SIZE;
00724    f->datalen = FRAME_SIZE * 2;
00725    f->data.ptr = o->oss_read_buf + AST_FRIENDLY_OFFSET;
00726    if (o->boost != BOOST_SCALE) {   /* scale and clip values */
00727       int i, x;
00728       int16_t *p = (int16_t *) f->data.ptr;
00729       for (i = 0; i < f->samples; i++) {
00730          x = (p[i] * o->boost) / BOOST_SCALE;
00731          if (x > 32767)
00732             x = 32767;
00733          else if (x < -32768)
00734             x = -32768;
00735          p[i] = x;
00736       }
00737    }
00738 
00739    f->offset = AST_FRIENDLY_OFFSET;
00740    return f;
00741 }
00742 
00743 static int oss_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
00744 {
00745    struct chan_oss_pvt *o = newchan->tech_pvt;
00746    o->owner = newchan;
00747    return 0;
00748 }
00749 
00750 static int oss_indicate(struct ast_channel *c, int cond, const void *data, size_t datalen)
00751 {
00752    struct chan_oss_pvt *o = c->tech_pvt;
00753    int res = 0;
00754 
00755    switch (cond) {
00756    case AST_CONTROL_BUSY:
00757    case AST_CONTROL_CONGESTION:
00758    case AST_CONTROL_RINGING:
00759    case -1:
00760       res = -1;
00761       break;
00762    case AST_CONTROL_PROGRESS:
00763    case AST_CONTROL_PROCEEDING:
00764    case AST_CONTROL_VIDUPDATE:
00765    case AST_CONTROL_SRCUPDATE:
00766       break;
00767    case AST_CONTROL_HOLD:
00768       ast_verbose(" << Console Has Been Placed on Hold >> \n");
00769       ast_moh_start(c, data, o->mohinterpret);
00770       break;
00771    case AST_CONTROL_UNHOLD:
00772       ast_verbose(" << Console Has Been Retrieved from Hold >> \n");
00773       ast_moh_stop(c);
00774       break;
00775    default:
00776       ast_log(LOG_WARNING, "Don't know how to display condition %d on %s\n", cond, c->name);
00777       return -1;
00778    }
00779 
00780    return res;
00781 }
00782 
00783 /*!
00784  * \brief allocate a new channel.
00785  */
00786 static struct ast_channel *oss_new(struct chan_oss_pvt *o, char *ext, char *ctx, int state, const char *linkedid)
00787 {
00788    struct ast_channel *c;
00789 
00790    c = ast_channel_alloc(1, state, o->cid_num, o->cid_name, "", ext, ctx, linkedid, 0, "Console/%s", o->device + 5);
00791    if (c == NULL)
00792       return NULL;
00793    c->tech = &oss_tech;
00794    if (o->sounddev < 0)
00795       setformat(o, O_RDWR);
00796    ast_channel_set_fd(c, 0, o->sounddev); /* -1 if device closed, override later */
00797    c->nativeformats = AST_FORMAT_SLINEAR;
00798    /* if the console makes the call, add video to the offer */
00799    if (state == AST_STATE_RINGING)
00800       c->nativeformats |= console_video_formats;
00801 
00802    c->readformat = AST_FORMAT_SLINEAR;
00803    c->writeformat = AST_FORMAT_SLINEAR;
00804    c->tech_pvt = o;
00805 
00806    if (!ast_strlen_zero(o->language))
00807       ast_string_field_set(c, language, o->language);
00808    /* Don't use ast_set_callerid() here because it will
00809     * generate a needless NewCallerID event */
00810    if (!ast_strlen_zero(o->cid_num)) {
00811       c->caller.ani.number.valid = 1;
00812       c->caller.ani.number.str = ast_strdup(o->cid_num);
00813    }
00814    if (!ast_strlen_zero(ext)) {
00815       c->dialed.number.str = ast_strdup(ext);
00816    }
00817 
00818    o->owner = c;
00819    ast_module_ref(ast_module_info->self);
00820    ast_jb_configure(c, &global_jbconf);
00821    if (state != AST_STATE_DOWN) {
00822       if (ast_pbx_start(c)) {
00823          ast_log(LOG_WARNING, "Unable to start PBX on %s\n", c->name);
00824          ast_hangup(c);
00825          o->owner = c = NULL;
00826       }
00827    }
00828    console_video_start(get_video_desc(c), c); /* XXX cleanup */
00829 
00830    return c;
00831 }
00832 
00833 static struct ast_channel *oss_request(const char *type, format_t format, const struct ast_channel *requestor, void *data, int *cause)
00834 {
00835    struct ast_channel *c;
00836    struct chan_oss_pvt *o;
00837    AST_DECLARE_APP_ARGS(args,
00838       AST_APP_ARG(name);
00839       AST_APP_ARG(flags);
00840    );
00841    char *parse = ast_strdupa(data);
00842    char buf[256];
00843 
00844    AST_NONSTANDARD_APP_ARGS(args, parse, '/');
00845    o = find_desc(args.name);
00846 
00847    ast_log(LOG_WARNING, "oss_request ty <%s> data 0x%p <%s>\n", type, data, (char *) data);
00848    if (o == NULL) {
00849       ast_log(LOG_NOTICE, "Device %s not found\n", args.name);
00850       /* XXX we could default to 'dsp' perhaps ? */
00851       return NULL;
00852    }
00853    if ((format & AST_FORMAT_SLINEAR) == 0) {
00854       ast_log(LOG_NOTICE, "Format %s unsupported\n", ast_getformatname_multiple(buf, sizeof(buf), format));
00855       return NULL;
00856    }
00857    if (o->owner) {
00858       ast_log(LOG_NOTICE, "Already have a call (chan %p) on the OSS channel\n", o->owner);
00859       *cause = AST_CAUSE_BUSY;
00860       return NULL;
00861    }
00862    c = oss_new(o, NULL, NULL, AST_STATE_DOWN, requestor ? requestor->linkedid : NULL);
00863    if (c == NULL) {
00864       ast_log(LOG_WARNING, "Unable to create new OSS channel\n");
00865       return NULL;
00866    }
00867    return c;
00868 }
00869 
00870 static void store_config_core(struct chan_oss_pvt *o, const char *var, const char *value);
00871 
00872 /*! Generic console command handler. Basically a wrapper for a subset
00873  *  of config file options which are also available from the CLI
00874  */
00875 static char *console_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00876 {
00877    struct chan_oss_pvt *o = find_desc(oss_active);
00878    const char *var, *value;
00879    switch (cmd) {
00880    case CLI_INIT:
00881       e->command = CONSOLE_VIDEO_CMDS;
00882       e->usage = 
00883          "Usage: " CONSOLE_VIDEO_CMDS "...\n"
00884          "       Generic handler for console commands.\n";
00885       return NULL;
00886 
00887    case CLI_GENERATE:
00888       return NULL;
00889    }
00890 
00891    if (a->argc < e->args)
00892       return CLI_SHOWUSAGE;
00893    if (o == NULL) {
00894       ast_log(LOG_WARNING, "Cannot find device %s (should not happen!)\n",
00895          oss_active);
00896       return CLI_FAILURE;
00897    }
00898    var = a->argv[e->args-1];
00899    value = a->argc > e->args ? a->argv[e->args] : NULL;
00900    if (value)      /* handle setting */
00901       store_config_core(o, var, value);
00902    if (!console_video_cli(o->env, var, a->fd))  /* print video-related values */
00903       return CLI_SUCCESS;
00904    /* handle other values */
00905    if (!strcasecmp(var, "device")) {
00906       ast_cli(a->fd, "device is [%s]\n", o->device);
00907    }
00908    return CLI_SUCCESS;
00909 }
00910 
00911 static char *console_autoanswer(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00912 {
00913    struct chan_oss_pvt *o = find_desc(oss_active);
00914 
00915    switch (cmd) {
00916    case CLI_INIT:
00917       e->command = "console {set|show} autoanswer [on|off]";
00918       e->usage =
00919          "Usage: console {set|show} autoanswer [on|off]\n"
00920          "       Enables or disables autoanswer feature.  If used without\n"
00921          "       argument, displays the current on/off status of autoanswer.\n"
00922          "       The default value of autoanswer is in 'oss.conf'.\n";
00923       return NULL;
00924 
00925    case CLI_GENERATE:
00926       return NULL;
00927    }
00928 
00929    if (a->argc == e->args - 1) {
00930       ast_cli(a->fd, "Auto answer is %s.\n", o->autoanswer ? "on" : "off");
00931       return CLI_SUCCESS;
00932    }
00933    if (a->argc != e->args)
00934       return CLI_SHOWUSAGE;
00935    if (o == NULL) {
00936       ast_log(LOG_WARNING, "Cannot find device %s (should not happen!)\n",
00937           oss_active);
00938       return CLI_FAILURE;
00939    }
00940    if (!strcasecmp(a->argv[e->args-1], "on"))
00941       o->autoanswer = 1;
00942    else if (!strcasecmp(a->argv[e->args - 1], "off"))
00943       o->autoanswer = 0;
00944    else
00945       return CLI_SHOWUSAGE;
00946    return CLI_SUCCESS;
00947 }
00948 
00949 /*! \brief helper function for the answer key/cli command */
00950 static char *console_do_answer(int fd)
00951 {
00952    struct ast_frame f = { AST_FRAME_CONTROL, { AST_CONTROL_ANSWER } };
00953    struct chan_oss_pvt *o = find_desc(oss_active);
00954    if (!o->owner) {
00955       if (fd > -1)
00956          ast_cli(fd, "No one is calling us\n");
00957       return CLI_FAILURE;
00958    }
00959    o->hookstate = 1;
00960    ast_queue_frame(o->owner, &f);
00961    return CLI_SUCCESS;
00962 }
00963 
00964 /*!
00965  * \brief answer command from the console
00966  */
00967 static char *console_answer(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00968 {
00969    switch (cmd) {
00970    case CLI_INIT:
00971       e->command = "console answer";
00972       e->usage =
00973          "Usage: console answer\n"
00974          "       Answers an incoming call on the console (OSS) channel.\n";
00975       return NULL;
00976 
00977    case CLI_GENERATE:
00978       return NULL;   /* no completion */
00979    }
00980    if (a->argc != e->args)
00981       return CLI_SHOWUSAGE;
00982    return console_do_answer(a->fd);
00983 }
00984 
00985 /*!
00986  * \brief Console send text CLI command
00987  *
00988  * \note concatenate all arguments into a single string. argv is NULL-terminated
00989  * so we can use it right away
00990  */
00991 static char *console_sendtext(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00992 {
00993    struct chan_oss_pvt *o = find_desc(oss_active);
00994    char buf[TEXT_SIZE];
00995 
00996    if (cmd == CLI_INIT) {
00997       e->command = "console send text";
00998       e->usage =
00999          "Usage: console send text <message>\n"
01000          "       Sends a text message for display on the remote terminal.\n";
01001       return NULL;
01002    } else if (cmd == CLI_GENERATE)
01003       return NULL;
01004 
01005    if (a->argc < e->args + 1)
01006       return CLI_SHOWUSAGE;
01007    if (!o->owner) {
01008       ast_cli(a->fd, "Not in a call\n");
01009       return CLI_FAILURE;
01010    }
01011    ast_join(buf, sizeof(buf) - 1, a->argv + e->args);
01012    if (!ast_strlen_zero(buf)) {
01013       struct ast_frame f = { 0, };
01014       int i = strlen(buf);
01015       buf[i] = '\n';
01016       f.frametype = AST_FRAME_TEXT;
01017       f.subclass.integer = 0;
01018       f.data.ptr = buf;
01019       f.datalen = i + 1;
01020       ast_queue_frame(o->owner, &f);
01021    }
01022    return CLI_SUCCESS;
01023 }
01024 
01025 static char *console_hangup(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01026 {
01027    struct chan_oss_pvt *o = find_desc(oss_active);
01028 
01029    if (cmd == CLI_INIT) {
01030       e->command = "console hangup";
01031       e->usage =
01032          "Usage: console hangup\n"
01033          "       Hangs up any call currently placed on the console.\n";
01034       return NULL;
01035    } else if (cmd == CLI_GENERATE)
01036       return NULL;
01037 
01038    if (a->argc != e->args)
01039       return CLI_SHOWUSAGE;
01040    if (!o->owner && !o->hookstate) { /* XXX maybe only one ? */
01041       ast_cli(a->fd, "No call to hang up\n");
01042       return CLI_FAILURE;
01043    }
01044    o->hookstate = 0;
01045    if (o->owner)
01046       ast_queue_hangup_with_cause(o->owner, AST_CAUSE_NORMAL_CLEARING);
01047    setformat(o, O_CLOSE);
01048    return CLI_SUCCESS;
01049 }
01050 
01051 static char *console_flash(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01052 {
01053    struct ast_frame f = { AST_FRAME_CONTROL, { AST_CONTROL_FLASH } };
01054    struct chan_oss_pvt *o = find_desc(oss_active);
01055 
01056    if (cmd == CLI_INIT) {
01057       e->command = "console flash";
01058       e->usage =
01059          "Usage: console flash\n"
01060          "       Flashes the call currently placed on the console.\n";
01061       return NULL;
01062    } else if (cmd == CLI_GENERATE)
01063       return NULL;
01064 
01065    if (a->argc != e->args)
01066       return CLI_SHOWUSAGE;
01067    if (!o->owner) {        /* XXX maybe !o->hookstate too ? */
01068       ast_cli(a->fd, "No call to flash\n");
01069       return CLI_FAILURE;
01070    }
01071    o->hookstate = 0;
01072    if (o->owner)
01073       ast_queue_frame(o->owner, &f);
01074    return CLI_SUCCESS;
01075 }
01076 
01077 static char *console_dial(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01078 {
01079    char *s = NULL;
01080    char *mye = NULL, *myc = NULL;
01081    struct chan_oss_pvt *o = find_desc(oss_active);
01082 
01083    if (cmd == CLI_INIT) {
01084       e->command = "console dial";
01085       e->usage =
01086          "Usage: console dial [extension[@context]]\n"
01087          "       Dials a given extension (and context if specified)\n";
01088       return NULL;
01089    } else if (cmd == CLI_GENERATE)
01090       return NULL;
01091 
01092    if (a->argc > e->args + 1)
01093       return CLI_SHOWUSAGE;
01094    if (o->owner) {   /* already in a call */
01095       int i;
01096       struct ast_frame f = { AST_FRAME_DTMF, { 0 } };
01097       const char *s;
01098 
01099       if (a->argc == e->args) {  /* argument is mandatory here */
01100          ast_cli(a->fd, "Already in a call. You can only dial digits until you hangup.\n");
01101          return CLI_FAILURE;
01102       }
01103       s = a->argv[e->args];
01104       /* send the string one char at a time */
01105       for (i = 0; i < strlen(s); i++) {
01106          f.subclass.integer = s[i];
01107          ast_queue_frame(o->owner, &f);
01108       }
01109       return CLI_SUCCESS;
01110    }
01111    /* if we have an argument split it into extension and context */
01112    if (a->argc == e->args + 1)
01113       s = ast_ext_ctx(a->argv[e->args], &mye, &myc);
01114    /* supply default values if needed */
01115    if (mye == NULL)
01116       mye = o->ext;
01117    if (myc == NULL)
01118       myc = o->ctx;
01119    if (ast_exists_extension(NULL, myc, mye, 1, NULL)) {
01120       o->hookstate = 1;
01121       oss_new(o, mye, myc, AST_STATE_RINGING, NULL);
01122    } else
01123       ast_cli(a->fd, "No such extension '%s' in context '%s'\n", mye, myc);
01124    if (s)
01125       ast_free(s);
01126    return CLI_SUCCESS;
01127 }
01128 
01129 static char *console_mute(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01130 {
01131    struct chan_oss_pvt *o = find_desc(oss_active);
01132    const char *s;
01133    int toggle = 0;
01134    
01135    if (cmd == CLI_INIT) {
01136       e->command = "console {mute|unmute} [toggle]";
01137       e->usage =
01138          "Usage: console {mute|unmute} [toggle]\n"
01139          "       Mute/unmute the microphone.\n";
01140       return NULL;
01141    } else if (cmd == CLI_GENERATE)
01142       return NULL;
01143 
01144    if (a->argc > e->args)
01145       return CLI_SHOWUSAGE;
01146    if (a->argc == e->args) {
01147       if (strcasecmp(a->argv[e->args-1], "toggle"))
01148          return CLI_SHOWUSAGE;
01149       toggle = 1;
01150    }
01151    s = a->argv[e->args-2];
01152    if (!strcasecmp(s, "mute"))
01153       o->mute = toggle ? !o->mute : 1;
01154    else if (!strcasecmp(s, "unmute"))
01155       o->mute = toggle ? !o->mute : 0;
01156    else
01157       return CLI_SHOWUSAGE;
01158    ast_cli(a->fd, "Console mic is %s\n", o->mute ? "off" : "on");
01159    return CLI_SUCCESS;
01160 }
01161 
01162 static char *console_transfer(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01163 {
01164    struct chan_oss_pvt *o = find_desc(oss_active);
01165    struct ast_channel *b = NULL;
01166    char *tmp, *ext, *ctx;
01167 
01168    switch (cmd) {
01169    case CLI_INIT:
01170       e->command = "console transfer";
01171       e->usage =
01172          "Usage: console transfer <extension>[@context]\n"
01173          "       Transfers the currently connected call to the given extension (and\n"
01174          "       context if specified)\n";
01175       return NULL;
01176    case CLI_GENERATE:
01177       return NULL;
01178    }
01179 
01180    if (a->argc != 3)
01181       return CLI_SHOWUSAGE;
01182    if (o == NULL)
01183       return CLI_FAILURE;
01184    if (o->owner == NULL || (b = ast_bridged_channel(o->owner)) == NULL) {
01185       ast_cli(a->fd, "There is no call to transfer\n");
01186       return CLI_SUCCESS;
01187    }
01188 
01189    tmp = ast_ext_ctx(a->argv[2], &ext, &ctx);
01190    if (ctx == NULL)        /* supply default context if needed */
01191       ctx = o->owner->context;
01192    if (!ast_exists_extension(b, ctx, ext, 1,
01193       S_COR(b->caller.id.number.valid, b->caller.id.number.str, NULL))) {
01194       ast_cli(a->fd, "No such extension exists\n");
01195    } else {
01196       ast_cli(a->fd, "Whee, transferring %s to %s@%s.\n", b->name, ext, ctx);
01197       if (ast_async_goto(b, ctx, ext, 1))
01198          ast_cli(a->fd, "Failed to transfer :(\n");
01199    }
01200    if (tmp)
01201       ast_free(tmp);
01202    return CLI_SUCCESS;
01203 }
01204 
01205 static char *console_active(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01206 {
01207    switch (cmd) {
01208    case CLI_INIT:
01209       e->command = "console {set|show} active [<device>]";
01210       e->usage =
01211          "Usage: console active [device]\n"
01212          "       If used without a parameter, displays which device is the current\n"
01213          "       console.  If a device is specified, the console sound device is changed to\n"
01214          "       the device specified.\n";
01215       return NULL;
01216    case CLI_GENERATE:
01217       return NULL;
01218    }
01219 
01220    if (a->argc == 3)
01221       ast_cli(a->fd, "active console is [%s]\n", oss_active);
01222    else if (a->argc != 4)
01223       return CLI_SHOWUSAGE;
01224    else {
01225       struct chan_oss_pvt *o;
01226       if (strcmp(a->argv[3], "show") == 0) {
01227          for (o = oss_default.next; o; o = o->next)
01228             ast_cli(a->fd, "device [%s] exists\n", o->name);
01229          return CLI_SUCCESS;
01230       }
01231       o = find_desc(a->argv[3]);
01232       if (o == NULL)
01233          ast_cli(a->fd, "No device [%s] exists\n", a->argv[3]);
01234       else
01235          oss_active = o->name;
01236    }
01237    return CLI_SUCCESS;
01238 }
01239 
01240 /*!
01241  * \brief store the boost factor
01242  */
01243 static void store_boost(struct chan_oss_pvt *o, const char *s)
01244 {
01245    double boost = 0;
01246    if (sscanf(s, "%30lf", &boost) != 1) {
01247       ast_log(LOG_WARNING, "invalid boost <%s>\n", s);
01248       return;
01249    }
01250    if (boost < -BOOST_MAX) {
01251       ast_log(LOG_WARNING, "boost %s too small, using %d\n", s, -BOOST_MAX);
01252       boost = -BOOST_MAX;
01253    } else if (boost > BOOST_MAX) {
01254       ast_log(LOG_WARNING, "boost %s too large, using %d\n", s, BOOST_MAX);
01255       boost = BOOST_MAX;
01256    }
01257    boost = exp(log(10) * boost / 20) * BOOST_SCALE;
01258    o->boost = boost;
01259    ast_log(LOG_WARNING, "setting boost %s to %d\n", s, o->boost);
01260 }
01261 
01262 static char *console_boost(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01263 {
01264    struct chan_oss_pvt *o = find_desc(oss_active);
01265 
01266    switch (cmd) {
01267    case CLI_INIT:
01268       e->command = "console boost";
01269       e->usage =
01270          "Usage: console boost [boost in dB]\n"
01271          "       Sets or display mic boost in dB\n";
01272       return NULL;
01273    case CLI_GENERATE:
01274       return NULL;
01275    }
01276 
01277    if (a->argc == 2)
01278       ast_cli(a->fd, "boost currently %5.1f\n", 20 * log10(((double) o->boost / (double) BOOST_SCALE)));
01279    else if (a->argc == 3)
01280       store_boost(o, a->argv[2]);
01281    return CLI_SUCCESS;
01282 }
01283 
01284 static struct ast_cli_entry cli_oss[] = {
01285    AST_CLI_DEFINE(console_answer, "Answer an incoming console call"),
01286    AST_CLI_DEFINE(console_hangup, "Hangup a call on the console"),
01287    AST_CLI_DEFINE(console_flash, "Flash a call on the console"),
01288    AST_CLI_DEFINE(console_dial, "Dial an extension on the console"),
01289    AST_CLI_DEFINE(console_mute, "Disable/Enable mic input"),
01290    AST_CLI_DEFINE(console_transfer, "Transfer a call to a different extension"), 
01291    AST_CLI_DEFINE(console_cmd, "Generic console command"),
01292    AST_CLI_DEFINE(console_sendtext, "Send text to the remote device"),
01293    AST_CLI_DEFINE(console_autoanswer, "Sets/displays autoanswer"),
01294    AST_CLI_DEFINE(console_boost, "Sets/displays mic boost in dB"),
01295    AST_CLI_DEFINE(console_active, "Sets/displays active console"),
01296 };
01297 
01298 /*!
01299  * store the mixer argument from the config file, filtering possibly
01300  * invalid or dangerous values (the string is used as argument for
01301  * system("mixer %s")
01302  */
01303 static void store_mixer(struct chan_oss_pvt *o, const char *s)
01304 {
01305    int i;
01306 
01307    for (i = 0; i < strlen(s); i++) {
01308       if (!isalnum(s[i]) && strchr(" \t-/", s[i]) == NULL) {
01309          ast_log(LOG_WARNING, "Suspect char %c in mixer cmd, ignoring:\n\t%s\n", s[i], s);
01310          return;
01311       }
01312    }
01313    if (o->mixer_cmd)
01314       ast_free(o->mixer_cmd);
01315    o->mixer_cmd = ast_strdup(s);
01316    ast_log(LOG_WARNING, "setting mixer %s\n", s);
01317 }
01318 
01319 /*!
01320  * store the callerid components
01321  */
01322 static void store_callerid(struct chan_oss_pvt *o, const char *s)
01323 {
01324    ast_callerid_split(s, o->cid_name, sizeof(o->cid_name), o->cid_num, sizeof(o->cid_num));
01325 }
01326 
01327 static void store_config_core(struct chan_oss_pvt *o, const char *var, const char *value)
01328 {
01329    CV_START(var, value);
01330 
01331    /* handle jb conf */
01332    if (!ast_jb_read_conf(&global_jbconf, var, value))
01333       return;
01334 
01335    if (!console_video_config(&o->env, var, value))
01336       return;  /* matched there */
01337    CV_BOOL("autoanswer", o->autoanswer);
01338    CV_BOOL("autohangup", o->autohangup);
01339    CV_BOOL("overridecontext", o->overridecontext);
01340    CV_STR("device", o->device);
01341    CV_UINT("frags", o->frags);
01342    CV_UINT("debug", oss_debug);
01343    CV_UINT("queuesize", o->queuesize);
01344    CV_STR("context", o->ctx);
01345    CV_STR("language", o->language);
01346    CV_STR("mohinterpret", o->mohinterpret);
01347    CV_STR("extension", o->ext);
01348    CV_F("mixer", store_mixer(o, value));
01349    CV_F("callerid", store_callerid(o, value))  ;
01350    CV_F("boost", store_boost(o, value));
01351 
01352    CV_END;
01353 }
01354 
01355 /*!
01356  * grab fields from the config file, init the descriptor and open the device.
01357  */
01358 static struct chan_oss_pvt *store_config(struct ast_config *cfg, char *ctg)
01359 {
01360    struct ast_variable *v;
01361    struct chan_oss_pvt *o;
01362 
01363    if (ctg == NULL) {
01364       o = &oss_default;
01365       ctg = "general";
01366    } else {
01367       if (!(o = ast_calloc(1, sizeof(*o))))
01368          return NULL;
01369       *o = oss_default;
01370       /* "general" is also the default thing */
01371       if (strcmp(ctg, "general") == 0) {
01372          o->name = ast_strdup("dsp");
01373          oss_active = o->name;
01374          goto openit;
01375       }
01376       o->name = ast_strdup(ctg);
01377    }
01378 
01379    strcpy(o->mohinterpret, "default");
01380 
01381    o->lastopen = ast_tvnow(); /* don't leave it 0 or tvdiff may wrap */
01382    /* fill other fields from configuration */
01383    for (v = ast_variable_browse(cfg, ctg); v; v = v->next) {
01384       store_config_core(o, v->name, v->value);
01385    }
01386    if (ast_strlen_zero(o->device))
01387       ast_copy_string(o->device, DEV_DSP, sizeof(o->device));
01388    if (o->mixer_cmd) {
01389       char *cmd;
01390 
01391       if (asprintf(&cmd, "mixer %s", o->mixer_cmd) < 0) {
01392          ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
01393       } else {
01394          ast_log(LOG_WARNING, "running [%s]\n", cmd);
01395          if (system(cmd) < 0) {
01396             ast_log(LOG_WARNING, "system() failed: %s\n", strerror(errno));
01397          }
01398          ast_free(cmd);
01399       }
01400    }
01401 
01402    /* if the config file requested to start the GUI, do it */
01403    if (get_gui_startup(o->env))
01404       console_video_start(o->env, NULL);
01405 
01406    if (o == &oss_default)     /* we are done with the default */
01407       return NULL;
01408 
01409 openit:
01410 #ifdef TRYOPEN
01411    if (setformat(o, O_RDWR) < 0) {  /* open device */
01412       ast_verb(1, "Device %s not detected\n", ctg);
01413       ast_verb(1, "Turn off OSS support by adding " "'noload=chan_oss.so' in /etc/asterisk/modules.conf\n");
01414       goto error;
01415    }
01416    if (o->duplex != M_FULL)
01417       ast_log(LOG_WARNING, "XXX I don't work right with non " "full-duplex sound cards XXX\n");
01418 #endif /* TRYOPEN */
01419 
01420    /* link into list of devices */
01421    if (o != &oss_default) {
01422       o->next = oss_default.next;
01423       oss_default.next = o;
01424    }
01425    return o;
01426 
01427 #ifdef TRYOPEN
01428 error:
01429    if (o != &oss_default)
01430       ast_free(o);
01431    return NULL;
01432 #endif
01433 }
01434 
01435 static int load_module(void)
01436 {
01437    struct ast_config *cfg = NULL;
01438    char *ctg = NULL;
01439    struct ast_flags config_flags = { 0 };
01440 
01441    /* Copy the default jb config over global_jbconf */
01442    memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
01443 
01444    /* load config file */
01445    if (!(cfg = ast_config_load(config, config_flags))) {
01446       ast_log(LOG_NOTICE, "Unable to load config %s\n", config);
01447       return AST_MODULE_LOAD_DECLINE;
01448    } else if (cfg == CONFIG_STATUS_FILEINVALID) {
01449       ast_log(LOG_ERROR, "Config file %s is in an invalid format.  Aborting.\n", config);
01450       return AST_MODULE_LOAD_DECLINE;
01451    }
01452 
01453    do {
01454       store_config(cfg, ctg);
01455    } while ( (ctg = ast_category_browse(cfg, ctg)) != NULL);
01456 
01457    ast_config_destroy(cfg);
01458 
01459    if (find_desc(oss_active) == NULL) {
01460       ast_log(LOG_NOTICE, "Device %s not found\n", oss_active);
01461       /* XXX we could default to 'dsp' perhaps ? */
01462       /* XXX should cleanup allocated memory etc. */
01463       return AST_MODULE_LOAD_FAILURE;
01464    }
01465 
01466    oss_tech.capabilities |= console_video_formats;
01467 
01468    if (ast_channel_register(&oss_tech)) {
01469       ast_log(LOG_ERROR, "Unable to register channel type 'OSS'\n");
01470       return AST_MODULE_LOAD_DECLINE;
01471    }
01472 
01473    ast_cli_register_multiple(cli_oss, ARRAY_LEN(cli_oss));
01474 
01475    return AST_MODULE_LOAD_SUCCESS;
01476 }
01477 
01478 
01479 static int unload_module(void)
01480 {
01481    struct chan_oss_pvt *o, *next;
01482 
01483    ast_channel_unregister(&oss_tech);
01484    ast_cli_unregister_multiple(cli_oss, ARRAY_LEN(cli_oss));
01485 
01486    o = oss_default.next;
01487    while (o) {
01488       close(o->sounddev);
01489       if (o->owner)
01490          ast_softhangup(o->owner, AST_SOFTHANGUP_APPUNLOAD);
01491       if (o->owner)
01492          return -1;
01493       next = o->next;
01494       ast_free(o->name);
01495       ast_free(o);
01496       o = next;
01497    }
01498    return 0;
01499 }
01500 
01501 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "OSS Console Channel Driver");

Generated on Wed Apr 6 11:29:42 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7