Fri Aug 17 00:17:14 2018

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

Generated on 17 Aug 2018 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1