Sat Apr 26 2014 22:01:32

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: 371592 $")
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__)
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 ? ast_channel_tech_pvt(c) : 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, struct ast_format_cap *cap, const struct ast_channel *requestor,
00332                               const char *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, const 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    .requester = oss_request,
00350    .send_digit_begin = oss_digit_begin,
00351    .send_digit_end = oss_digit_end,
00352    .send_text = oss_text,
00353    .hangup = oss_hangup,
00354    .answer = oss_answer,
00355    .read = oss_read,
00356    .call = oss_call,
00357    .write = oss_write,
00358    .write_video = console_write_video,
00359    .indicate = oss_indicate,
00360    .fixup = oss_fixup,
00361 };
00362 
00363 /*!
00364  * \brief returns a pointer to the descriptor with the given name
00365  */
00366 static struct chan_oss_pvt *find_desc(const char *dev)
00367 {
00368    struct chan_oss_pvt *o = NULL;
00369 
00370    if (!dev)
00371       ast_log(LOG_WARNING, "null dev\n");
00372 
00373    for (o = oss_default.next; o && o->name && dev && strcmp(o->name, dev) != 0; o = o->next);
00374 
00375    if (!o)
00376       ast_log(LOG_WARNING, "could not find <%s>\n", dev ? dev : "--no-device--");
00377 
00378    return o;
00379 }
00380 
00381 /* !
00382  * \brief split a string in extension-context, returns pointers to malloc'ed
00383  *        strings.
00384  *
00385  * If we do not have 'overridecontext' then the last @ is considered as
00386  * a context separator, and the context is overridden.
00387  * This is usually not very necessary as you can play with the dialplan,
00388  * and it is nice not to need it because you have '@' in SIP addresses.
00389  *
00390  * \return the buffer address.
00391  */
00392 static char *ast_ext_ctx(const char *src, char **ext, char **ctx)
00393 {
00394    struct chan_oss_pvt *o = find_desc(oss_active);
00395 
00396    if (ext == NULL || ctx == NULL)
00397       return NULL;         /* error */
00398 
00399    *ext = *ctx = NULL;
00400 
00401    if (src && *src != '\0')
00402       *ext = ast_strdup(src);
00403 
00404    if (*ext == NULL)
00405       return NULL;
00406 
00407    if (!o->overridecontext) {
00408       /* parse from the right */
00409       *ctx = strrchr(*ext, '@');
00410       if (*ctx)
00411          *(*ctx)++ = '\0';
00412    }
00413 
00414    return *ext;
00415 }
00416 
00417 /*!
00418  * \brief Returns the number of blocks used in the audio output channel
00419  */
00420 static int used_blocks(struct chan_oss_pvt *o)
00421 {
00422    struct audio_buf_info info;
00423 
00424    if (ioctl(o->sounddev, SNDCTL_DSP_GETOSPACE, &info)) {
00425       if (!(o->warned & WARN_used_blocks)) {
00426          ast_log(LOG_WARNING, "Error reading output space\n");
00427          o->warned |= WARN_used_blocks;
00428       }
00429       return 1;
00430    }
00431 
00432    if (o->total_blocks == 0) {
00433       if (0)               /* debugging */
00434          ast_log(LOG_WARNING, "fragtotal %d size %d avail %d\n", info.fragstotal, info.fragsize, info.fragments);
00435       o->total_blocks = info.fragments;
00436    }
00437 
00438    return o->total_blocks - info.fragments;
00439 }
00440 
00441 /*! Write an exactly FRAME_SIZE sized frame */
00442 static int soundcard_writeframe(struct chan_oss_pvt *o, short *data)
00443 {
00444    int res;
00445 
00446    if (o->sounddev < 0)
00447       setformat(o, O_RDWR);
00448    if (o->sounddev < 0)
00449       return 0;            /* not fatal */
00450    /*
00451     * Nothing complex to manage the audio device queue.
00452     * If the buffer is full just drop the extra, otherwise write.
00453     * XXX in some cases it might be useful to write anyways after
00454     * a number of failures, to restart the output chain.
00455     */
00456    res = used_blocks(o);
00457    if (res > o->queuesize) {  /* no room to write a block */
00458       if (o->w_errors++ == 0 && (oss_debug & 0x4))
00459          ast_log(LOG_WARNING, "write: used %d blocks (%d)\n", res, o->w_errors);
00460       return 0;
00461    }
00462    o->w_errors = 0;
00463    return write(o->sounddev, (void *)data, FRAME_SIZE * 2);
00464 }
00465 
00466 /*!
00467  * reset and close the device if opened,
00468  * then open and initialize it in the desired mode,
00469  * trigger reads and writes so we can start using it.
00470  */
00471 static int setformat(struct chan_oss_pvt *o, int mode)
00472 {
00473    int fmt, desired, res, fd;
00474 
00475    if (o->sounddev >= 0) {
00476       ioctl(o->sounddev, SNDCTL_DSP_RESET, 0);
00477       close(o->sounddev);
00478       o->duplex = M_UNSET;
00479       o->sounddev = -1;
00480    }
00481    if (mode == O_CLOSE)    /* we are done */
00482       return 0;
00483    if (ast_tvdiff_ms(ast_tvnow(), o->lastopen) < 1000)
00484       return -1;           /* don't open too often */
00485    o->lastopen = ast_tvnow();
00486    fd = o->sounddev = open(o->device, mode | O_NONBLOCK);
00487    if (fd < 0) {
00488       ast_log(LOG_WARNING, "Unable to re-open DSP device %s: %s\n", o->device, strerror(errno));
00489       return -1;
00490    }
00491    if (o->owner)
00492       ast_channel_set_fd(o->owner, 0, fd);
00493 
00494 #if __BYTE_ORDER == __LITTLE_ENDIAN
00495    fmt = AFMT_S16_LE;
00496 #else
00497    fmt = AFMT_S16_BE;
00498 #endif
00499    res = ioctl(fd, SNDCTL_DSP_SETFMT, &fmt);
00500    if (res < 0) {
00501       ast_log(LOG_WARNING, "Unable to set format to 16-bit signed\n");
00502       return -1;
00503    }
00504    switch (mode) {
00505    case O_RDWR:
00506       res = ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0);
00507       /* Check to see if duplex set (FreeBSD Bug) */
00508       res = ioctl(fd, SNDCTL_DSP_GETCAPS, &fmt);
00509       if (res == 0 && (fmt & DSP_CAP_DUPLEX)) {
00510          ast_verb(2, "Console is full duplex\n");
00511          o->duplex = M_FULL;
00512       };
00513       break;
00514 
00515    case O_WRONLY:
00516       o->duplex = M_WRITE;
00517       break;
00518 
00519    case O_RDONLY:
00520       o->duplex = M_READ;
00521       break;
00522    }
00523 
00524    fmt = 0;
00525    res = ioctl(fd, SNDCTL_DSP_STEREO, &fmt);
00526    if (res < 0) {
00527       ast_log(LOG_WARNING, "Failed to set audio device to mono\n");
00528       return -1;
00529    }
00530    fmt = desired = DEFAULT_SAMPLE_RATE;   /* 8000 Hz desired */
00531    res = ioctl(fd, SNDCTL_DSP_SPEED, &fmt);
00532 
00533    if (res < 0) {
00534       ast_log(LOG_WARNING, "Failed to set sample rate to %d\n", desired);
00535       return -1;
00536    }
00537    if (fmt != desired) {
00538       if (!(o->warned & WARN_speed)) {
00539          ast_log(LOG_WARNING,
00540              "Requested %d Hz, got %d Hz -- sound may be choppy\n",
00541              desired, fmt);
00542          o->warned |= WARN_speed;
00543       }
00544    }
00545    /*
00546     * on Freebsd, SETFRAGMENT does not work very well on some cards.
00547     * Default to use 256 bytes, let the user override
00548     */
00549    if (o->frags) {
00550       fmt = o->frags;
00551       res = ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &fmt);
00552       if (res < 0) {
00553          if (!(o->warned & WARN_frag)) {
00554             ast_log(LOG_WARNING,
00555                "Unable to set fragment size -- sound may be choppy\n");
00556             o->warned |= WARN_frag;
00557          }
00558       }
00559    }
00560    /* on some cards, we need SNDCTL_DSP_SETTRIGGER to start outputting */
00561    res = PCM_ENABLE_INPUT | PCM_ENABLE_OUTPUT;
00562    res = ioctl(fd, SNDCTL_DSP_SETTRIGGER, &res);
00563    /* it may fail if we are in half duplex, never mind */
00564    return 0;
00565 }
00566 
00567 /*
00568  * some of the standard methods supported by channels.
00569  */
00570 static int oss_digit_begin(struct ast_channel *c, char digit)
00571 {
00572    return 0;
00573 }
00574 
00575 static int oss_digit_end(struct ast_channel *c, char digit, unsigned int duration)
00576 {
00577    /* no better use for received digits than print them */
00578    ast_verbose(" << Console Received digit %c of duration %u ms >> \n", 
00579       digit, duration);
00580    return 0;
00581 }
00582 
00583 static int oss_text(struct ast_channel *c, const char *text)
00584 {
00585    /* print received messages */
00586    ast_verbose(" << Console Received text %s >> \n", text);
00587    return 0;
00588 }
00589 
00590 /*!
00591  * \brief handler for incoming calls. Either autoanswer, or start ringing
00592  */
00593 static int oss_call(struct ast_channel *c, const char *dest, int timeout)
00594 {
00595    struct chan_oss_pvt *o = ast_channel_tech_pvt(c);
00596    struct ast_frame f = { AST_FRAME_CONTROL, };
00597    AST_DECLARE_APP_ARGS(args,
00598       AST_APP_ARG(name);
00599       AST_APP_ARG(flags);
00600    );
00601    char *parse = ast_strdupa(dest);
00602 
00603    AST_NONSTANDARD_APP_ARGS(args, parse, '/');
00604 
00605    ast_verbose(" << Call to device '%s' dnid '%s' rdnis '%s' on console from '%s' <%s> >>\n",
00606       dest,
00607       S_OR(ast_channel_dialed(c)->number.str, ""),
00608       S_COR(ast_channel_redirecting(c)->from.number.valid, ast_channel_redirecting(c)->from.number.str, ""),
00609       S_COR(ast_channel_caller(c)->id.name.valid, ast_channel_caller(c)->id.name.str, ""),
00610       S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, ""));
00611    if (!ast_strlen_zero(args.flags) && strcasecmp(args.flags, "answer") == 0) {
00612       f.subclass.integer = AST_CONTROL_ANSWER;
00613       ast_queue_frame(c, &f);
00614    } else if (!ast_strlen_zero(args.flags) && strcasecmp(args.flags, "noanswer") == 0) {
00615       f.subclass.integer = AST_CONTROL_RINGING;
00616       ast_queue_frame(c, &f);
00617       ast_indicate(c, AST_CONTROL_RINGING);
00618    } else if (o->autoanswer) {
00619       ast_verbose(" << Auto-answered >> \n");
00620       f.subclass.integer = AST_CONTROL_ANSWER;
00621       ast_queue_frame(c, &f);
00622       o->hookstate = 1;
00623    } else {
00624       ast_verbose("<< Type 'answer' to answer, or use 'autoanswer' for future calls >> \n");
00625       f.subclass.integer = AST_CONTROL_RINGING;
00626       ast_queue_frame(c, &f);
00627       ast_indicate(c, AST_CONTROL_RINGING);
00628    }
00629    return 0;
00630 }
00631 
00632 /*!
00633  * \brief remote side answered the phone
00634  */
00635 static int oss_answer(struct ast_channel *c)
00636 {
00637    struct chan_oss_pvt *o = ast_channel_tech_pvt(c);
00638    ast_verbose(" << Console call has been answered >> \n");
00639    ast_setstate(c, AST_STATE_UP);
00640    o->hookstate = 1;
00641    return 0;
00642 }
00643 
00644 static int oss_hangup(struct ast_channel *c)
00645 {
00646    struct chan_oss_pvt *o = ast_channel_tech_pvt(c);
00647 
00648    ast_channel_tech_pvt_set(c, NULL);
00649    o->owner = NULL;
00650    ast_verbose(" << Hangup on console >> \n");
00651    console_video_uninit(o->env);
00652    ast_module_unref(ast_module_info->self);
00653    if (o->hookstate) {
00654       if (o->autoanswer || o->autohangup) {
00655          /* Assume auto-hangup too */
00656          o->hookstate = 0;
00657          setformat(o, O_CLOSE);
00658       }
00659    }
00660    return 0;
00661 }
00662 
00663 /*! \brief used for data coming from the network */
00664 static int oss_write(struct ast_channel *c, struct ast_frame *f)
00665 {
00666    int src;
00667    struct chan_oss_pvt *o = ast_channel_tech_pvt(c);
00668 
00669    /*
00670     * we could receive a block which is not a multiple of our
00671     * FRAME_SIZE, so buffer it locally and write to the device
00672     * in FRAME_SIZE chunks.
00673     * Keep the residue stored for future use.
00674     */
00675    src = 0;             /* read position into f->data */
00676    while (src < f->datalen) {
00677       /* Compute spare room in the buffer */
00678       int l = sizeof(o->oss_write_buf) - o->oss_write_dst;
00679 
00680       if (f->datalen - src >= l) {  /* enough to fill a frame */
00681          memcpy(o->oss_write_buf + o->oss_write_dst, f->data.ptr + src, l);
00682          soundcard_writeframe(o, (short *) o->oss_write_buf);
00683          src += l;
00684          o->oss_write_dst = 0;
00685       } else {          /* copy residue */
00686          l = f->datalen - src;
00687          memcpy(o->oss_write_buf + o->oss_write_dst, f->data.ptr + src, l);
00688          src += l;         /* but really, we are done */
00689          o->oss_write_dst += l;
00690       }
00691    }
00692    return 0;
00693 }
00694 
00695 static struct ast_frame *oss_read(struct ast_channel *c)
00696 {
00697    int res;
00698    struct chan_oss_pvt *o = ast_channel_tech_pvt(c);
00699    struct ast_frame *f = &o->read_f;
00700 
00701    /* XXX can be simplified returning &ast_null_frame */
00702    /* prepare a NULL frame in case we don't have enough data to return */
00703    memset(f, '\0', sizeof(struct ast_frame));
00704    f->frametype = AST_FRAME_NULL;
00705    f->src = oss_tech.type;
00706 
00707    res = read(o->sounddev, o->oss_read_buf + o->readpos, sizeof(o->oss_read_buf) - o->readpos);
00708    if (res < 0)            /* audio data not ready, return a NULL frame */
00709       return f;
00710 
00711    o->readpos += res;
00712    if (o->readpos < sizeof(o->oss_read_buf)) /* not enough samples */
00713       return f;
00714 
00715    if (o->mute)
00716       return f;
00717 
00718    o->readpos = AST_FRIENDLY_OFFSET;   /* reset read pointer for next frame */
00719    if (ast_channel_state(c) != AST_STATE_UP) /* drop data if frame is not up */
00720       return f;
00721    /* ok we can build and deliver the frame to the caller */
00722    f->frametype = AST_FRAME_VOICE;
00723    ast_format_set(&f->subclass.format, AST_FORMAT_SLINEAR, 0);
00724    f->samples = FRAME_SIZE;
00725    f->datalen = FRAME_SIZE * 2;
00726    f->data.ptr = o->oss_read_buf + AST_FRIENDLY_OFFSET;
00727    if (o->boost != BOOST_SCALE) {   /* scale and clip values */
00728       int i, x;
00729       int16_t *p = (int16_t *) f->data.ptr;
00730       for (i = 0; i < f->samples; i++) {
00731          x = (p[i] * o->boost) / BOOST_SCALE;
00732          if (x > 32767)
00733             x = 32767;
00734          else if (x < -32768)
00735             x = -32768;
00736          p[i] = x;
00737       }
00738    }
00739 
00740    f->offset = AST_FRIENDLY_OFFSET;
00741    return f;
00742 }
00743 
00744 static int oss_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
00745 {
00746    struct chan_oss_pvt *o = ast_channel_tech_pvt(newchan);
00747    o->owner = newchan;
00748    return 0;
00749 }
00750 
00751 static int oss_indicate(struct ast_channel *c, int cond, const void *data, size_t datalen)
00752 {
00753    struct chan_oss_pvt *o = ast_channel_tech_pvt(c);
00754    int res = 0;
00755 
00756    switch (cond) {
00757    case AST_CONTROL_INCOMPLETE:
00758    case AST_CONTROL_BUSY:
00759    case AST_CONTROL_CONGESTION:
00760    case AST_CONTROL_RINGING:
00761    case AST_CONTROL_PVT_CAUSE_CODE:
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, ast_channel_name(c));
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    ast_channel_tech_set(c, &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 
00801    ast_format_set(ast_channel_readformat(c), AST_FORMAT_SLINEAR, 0);
00802    ast_format_set(ast_channel_writeformat(c), AST_FORMAT_SLINEAR, 0);
00803    ast_format_cap_add(ast_channel_nativeformats(c), ast_channel_readformat(c));
00804 
00805    /* if the console makes the call, add video to the offer */
00806    /* if (state == AST_STATE_RINGING) TODO XXX CONSOLE VIDEO IS DISABLED UNTIL IT GETS A MAINTAINER
00807       c->nativeformats |= console_video_formats; */
00808 
00809    ast_channel_tech_pvt_set(c, o);
00810 
00811    if (!ast_strlen_zero(o->language))
00812       ast_channel_language_set(c, o->language);
00813    /* Don't use ast_set_callerid() here because it will
00814     * generate a needless NewCallerID event */
00815    if (!ast_strlen_zero(o->cid_num)) {
00816       ast_channel_caller(c)->ani.number.valid = 1;
00817       ast_channel_caller(c)->ani.number.str = ast_strdup(o->cid_num);
00818    }
00819    if (!ast_strlen_zero(ext)) {
00820       ast_channel_dialed(c)->number.str = ast_strdup(ext);
00821    }
00822 
00823    o->owner = c;
00824    ast_module_ref(ast_module_info->self);
00825    ast_jb_configure(c, &global_jbconf);
00826    if (state != AST_STATE_DOWN) {
00827       if (ast_pbx_start(c)) {
00828          ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(c));
00829          ast_hangup(c);
00830          o->owner = c = NULL;
00831       }
00832    }
00833    console_video_start(get_video_desc(c), c); /* XXX cleanup */
00834 
00835    return c;
00836 }
00837 
00838 static struct ast_channel *oss_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause)
00839 {
00840    struct ast_channel *c;
00841    struct chan_oss_pvt *o;
00842    AST_DECLARE_APP_ARGS(args,
00843       AST_APP_ARG(name);
00844       AST_APP_ARG(flags);
00845    );
00846    char *parse = ast_strdupa(data);
00847    char buf[256];
00848    struct ast_format tmpfmt;
00849 
00850    AST_NONSTANDARD_APP_ARGS(args, parse, '/');
00851    o = find_desc(args.name);
00852 
00853    ast_log(LOG_WARNING, "oss_request ty <%s> data 0x%p <%s>\n", type, data, data);
00854    if (o == NULL) {
00855       ast_log(LOG_NOTICE, "Device %s not found\n", args.name);
00856       /* XXX we could default to 'dsp' perhaps ? */
00857       return NULL;
00858    }
00859    if (!(ast_format_cap_iscompatible(cap, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0)))) {
00860       ast_log(LOG_NOTICE, "Format %s unsupported\n", ast_getformatname_multiple(buf, sizeof(buf), cap));
00861       return NULL;
00862    }
00863    if (o->owner) {
00864       ast_log(LOG_NOTICE, "Already have a call (chan %p) on the OSS channel\n", o->owner);
00865       *cause = AST_CAUSE_BUSY;
00866       return NULL;
00867    }
00868    c = oss_new(o, NULL, NULL, AST_STATE_DOWN, requestor ? ast_channel_linkedid(requestor) : NULL);
00869    if (c == NULL) {
00870       ast_log(LOG_WARNING, "Unable to create new OSS channel\n");
00871       return NULL;
00872    }
00873    return c;
00874 }
00875 
00876 static void store_config_core(struct chan_oss_pvt *o, const char *var, const char *value);
00877 
00878 /*! Generic console command handler. Basically a wrapper for a subset
00879  *  of config file options which are also available from the CLI
00880  */
00881 static char *console_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00882 {
00883    struct chan_oss_pvt *o = find_desc(oss_active);
00884    const char *var, *value;
00885    switch (cmd) {
00886    case CLI_INIT:
00887       e->command = CONSOLE_VIDEO_CMDS;
00888       e->usage = 
00889          "Usage: " CONSOLE_VIDEO_CMDS "...\n"
00890          "       Generic handler for console commands.\n";
00891       return NULL;
00892 
00893    case CLI_GENERATE:
00894       return NULL;
00895    }
00896 
00897    if (a->argc < e->args)
00898       return CLI_SHOWUSAGE;
00899    if (o == NULL) {
00900       ast_log(LOG_WARNING, "Cannot find device %s (should not happen!)\n",
00901          oss_active);
00902       return CLI_FAILURE;
00903    }
00904    var = a->argv[e->args-1];
00905    value = a->argc > e->args ? a->argv[e->args] : NULL;
00906    if (value)      /* handle setting */
00907       store_config_core(o, var, value);
00908    if (!console_video_cli(o->env, var, a->fd))  /* print video-related values */
00909       return CLI_SUCCESS;
00910    /* handle other values */
00911    if (!strcasecmp(var, "device")) {
00912       ast_cli(a->fd, "device is [%s]\n", o->device);
00913    }
00914    return CLI_SUCCESS;
00915 }
00916 
00917 static char *console_autoanswer(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00918 {
00919    struct chan_oss_pvt *o = find_desc(oss_active);
00920 
00921    switch (cmd) {
00922    case CLI_INIT:
00923       e->command = "console {set|show} autoanswer [on|off]";
00924       e->usage =
00925          "Usage: console {set|show} autoanswer [on|off]\n"
00926          "       Enables or disables autoanswer feature.  If used without\n"
00927          "       argument, displays the current on/off status of autoanswer.\n"
00928          "       The default value of autoanswer is in 'oss.conf'.\n";
00929       return NULL;
00930 
00931    case CLI_GENERATE:
00932       return NULL;
00933    }
00934 
00935    if (a->argc == e->args - 1) {
00936       ast_cli(a->fd, "Auto answer is %s.\n", o->autoanswer ? "on" : "off");
00937       return CLI_SUCCESS;
00938    }
00939    if (a->argc != e->args)
00940       return CLI_SHOWUSAGE;
00941    if (o == NULL) {
00942       ast_log(LOG_WARNING, "Cannot find device %s (should not happen!)\n",
00943           oss_active);
00944       return CLI_FAILURE;
00945    }
00946    if (!strcasecmp(a->argv[e->args-1], "on"))
00947       o->autoanswer = 1;
00948    else if (!strcasecmp(a->argv[e->args - 1], "off"))
00949       o->autoanswer = 0;
00950    else
00951       return CLI_SHOWUSAGE;
00952    return CLI_SUCCESS;
00953 }
00954 
00955 /*! \brief helper function for the answer key/cli command */
00956 static char *console_do_answer(int fd)
00957 {
00958    struct ast_frame f = { AST_FRAME_CONTROL, { AST_CONTROL_ANSWER } };
00959    struct chan_oss_pvt *o = find_desc(oss_active);
00960    if (!o->owner) {
00961       if (fd > -1)
00962          ast_cli(fd, "No one is calling us\n");
00963       return CLI_FAILURE;
00964    }
00965    o->hookstate = 1;
00966    ast_queue_frame(o->owner, &f);
00967    return CLI_SUCCESS;
00968 }
00969 
00970 /*!
00971  * \brief answer command from the console
00972  */
00973 static char *console_answer(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00974 {
00975    switch (cmd) {
00976    case CLI_INIT:
00977       e->command = "console answer";
00978       e->usage =
00979          "Usage: console answer\n"
00980          "       Answers an incoming call on the console (OSS) channel.\n";
00981       return NULL;
00982 
00983    case CLI_GENERATE:
00984       return NULL;   /* no completion */
00985    }
00986    if (a->argc != e->args)
00987       return CLI_SHOWUSAGE;
00988    return console_do_answer(a->fd);
00989 }
00990 
00991 /*!
00992  * \brief Console send text CLI command
00993  *
00994  * \note concatenate all arguments into a single string. argv is NULL-terminated
00995  * so we can use it right away
00996  */
00997 static char *console_sendtext(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00998 {
00999    struct chan_oss_pvt *o = find_desc(oss_active);
01000    char buf[TEXT_SIZE];
01001 
01002    if (cmd == CLI_INIT) {
01003       e->command = "console send text";
01004       e->usage =
01005          "Usage: console send text <message>\n"
01006          "       Sends a text message for display on the remote terminal.\n";
01007       return NULL;
01008    } else if (cmd == CLI_GENERATE)
01009       return NULL;
01010 
01011    if (a->argc < e->args + 1)
01012       return CLI_SHOWUSAGE;
01013    if (!o->owner) {
01014       ast_cli(a->fd, "Not in a call\n");
01015       return CLI_FAILURE;
01016    }
01017    ast_join(buf, sizeof(buf) - 1, a->argv + e->args);
01018    if (!ast_strlen_zero(buf)) {
01019       struct ast_frame f = { 0, };
01020       int i = strlen(buf);
01021       buf[i] = '\n';
01022       f.frametype = AST_FRAME_TEXT;
01023       f.subclass.integer = 0;
01024       f.data.ptr = buf;
01025       f.datalen = i + 1;
01026       ast_queue_frame(o->owner, &f);
01027    }
01028    return CLI_SUCCESS;
01029 }
01030 
01031 static char *console_hangup(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01032 {
01033    struct chan_oss_pvt *o = find_desc(oss_active);
01034 
01035    if (cmd == CLI_INIT) {
01036       e->command = "console hangup";
01037       e->usage =
01038          "Usage: console hangup\n"
01039          "       Hangs up any call currently placed on the console.\n";
01040       return NULL;
01041    } else if (cmd == CLI_GENERATE)
01042       return NULL;
01043 
01044    if (a->argc != e->args)
01045       return CLI_SHOWUSAGE;
01046    if (!o->owner && !o->hookstate) { /* XXX maybe only one ? */
01047       ast_cli(a->fd, "No call to hang up\n");
01048       return CLI_FAILURE;
01049    }
01050    o->hookstate = 0;
01051    if (o->owner)
01052       ast_queue_hangup_with_cause(o->owner, AST_CAUSE_NORMAL_CLEARING);
01053    setformat(o, O_CLOSE);
01054    return CLI_SUCCESS;
01055 }
01056 
01057 static char *console_flash(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01058 {
01059    struct ast_frame f = { AST_FRAME_CONTROL, { AST_CONTROL_FLASH } };
01060    struct chan_oss_pvt *o = find_desc(oss_active);
01061 
01062    if (cmd == CLI_INIT) {
01063       e->command = "console flash";
01064       e->usage =
01065          "Usage: console flash\n"
01066          "       Flashes the call currently placed on the console.\n";
01067       return NULL;
01068    } else if (cmd == CLI_GENERATE)
01069       return NULL;
01070 
01071    if (a->argc != e->args)
01072       return CLI_SHOWUSAGE;
01073    if (!o->owner) {        /* XXX maybe !o->hookstate too ? */
01074       ast_cli(a->fd, "No call to flash\n");
01075       return CLI_FAILURE;
01076    }
01077    o->hookstate = 0;
01078    if (o->owner)
01079       ast_queue_frame(o->owner, &f);
01080    return CLI_SUCCESS;
01081 }
01082 
01083 static char *console_dial(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01084 {
01085    char *s = NULL;
01086    char *mye = NULL, *myc = NULL;
01087    struct chan_oss_pvt *o = find_desc(oss_active);
01088 
01089    if (cmd == CLI_INIT) {
01090       e->command = "console dial";
01091       e->usage =
01092          "Usage: console dial [extension[@context]]\n"
01093          "       Dials a given extension (and context if specified)\n";
01094       return NULL;
01095    } else if (cmd == CLI_GENERATE)
01096       return NULL;
01097 
01098    if (a->argc > e->args + 1)
01099       return CLI_SHOWUSAGE;
01100    if (o->owner) {   /* already in a call */
01101       int i;
01102       struct ast_frame f = { AST_FRAME_DTMF, { 0 } };
01103       const char *digits;
01104 
01105       if (a->argc == e->args) {  /* argument is mandatory here */
01106          ast_cli(a->fd, "Already in a call. You can only dial digits until you hangup.\n");
01107          return CLI_FAILURE;
01108       }
01109       digits = a->argv[e->args];
01110       /* send the string one char at a time */
01111       for (i = 0; i < strlen(digits); i++) {
01112          f.subclass.integer = digits[i];
01113          ast_queue_frame(o->owner, &f);
01114       }
01115       return CLI_SUCCESS;
01116    }
01117    /* if we have an argument split it into extension and context */
01118    if (a->argc == e->args + 1)
01119       s = ast_ext_ctx(a->argv[e->args], &mye, &myc);
01120    /* supply default values if needed */
01121    if (mye == NULL)
01122       mye = o->ext;
01123    if (myc == NULL)
01124       myc = o->ctx;
01125    if (ast_exists_extension(NULL, myc, mye, 1, NULL)) {
01126       o->hookstate = 1;
01127       oss_new(o, mye, myc, AST_STATE_RINGING, NULL);
01128    } else
01129       ast_cli(a->fd, "No such extension '%s' in context '%s'\n", mye, myc);
01130    if (s)
01131       ast_free(s);
01132    return CLI_SUCCESS;
01133 }
01134 
01135 static char *console_mute(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01136 {
01137    struct chan_oss_pvt *o = find_desc(oss_active);
01138    const char *s;
01139    int toggle = 0;
01140    
01141    if (cmd == CLI_INIT) {
01142       e->command = "console {mute|unmute} [toggle]";
01143       e->usage =
01144          "Usage: console {mute|unmute} [toggle]\n"
01145          "       Mute/unmute the microphone.\n";
01146       return NULL;
01147    } else if (cmd == CLI_GENERATE)
01148       return NULL;
01149 
01150    if (a->argc > e->args)
01151       return CLI_SHOWUSAGE;
01152    if (a->argc == e->args) {
01153       if (strcasecmp(a->argv[e->args-1], "toggle"))
01154          return CLI_SHOWUSAGE;
01155       toggle = 1;
01156    }
01157    s = a->argv[e->args-2];
01158    if (!strcasecmp(s, "mute"))
01159       o->mute = toggle ? !o->mute : 1;
01160    else if (!strcasecmp(s, "unmute"))
01161       o->mute = toggle ? !o->mute : 0;
01162    else
01163       return CLI_SHOWUSAGE;
01164    ast_cli(a->fd, "Console mic is %s\n", o->mute ? "off" : "on");
01165    return CLI_SUCCESS;
01166 }
01167 
01168 static char *console_transfer(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01169 {
01170    struct chan_oss_pvt *o = find_desc(oss_active);
01171    struct ast_channel *b = NULL;
01172    char *tmp, *ext, *ctx;
01173 
01174    switch (cmd) {
01175    case CLI_INIT:
01176       e->command = "console transfer";
01177       e->usage =
01178          "Usage: console transfer <extension>[@context]\n"
01179          "       Transfers the currently connected call to the given extension (and\n"
01180          "       context if specified)\n";
01181       return NULL;
01182    case CLI_GENERATE:
01183       return NULL;
01184    }
01185 
01186    if (a->argc != 3)
01187       return CLI_SHOWUSAGE;
01188    if (o == NULL)
01189       return CLI_FAILURE;
01190    if (o->owner == NULL || (b = ast_bridged_channel(o->owner)) == NULL) {
01191       ast_cli(a->fd, "There is no call to transfer\n");
01192       return CLI_SUCCESS;
01193    }
01194 
01195    tmp = ast_ext_ctx(a->argv[2], &ext, &ctx);
01196    if (ctx == NULL)        /* supply default context if needed */
01197       ctx = ast_strdupa(ast_channel_context(o->owner));
01198    if (!ast_exists_extension(b, ctx, ext, 1,
01199       S_COR(ast_channel_caller(b)->id.number.valid, ast_channel_caller(b)->id.number.str, NULL))) {
01200       ast_cli(a->fd, "No such extension exists\n");
01201    } else {
01202       ast_cli(a->fd, "Whee, transferring %s to %s@%s.\n", ast_channel_name(b), ext, ctx);
01203       if (ast_async_goto(b, ctx, ext, 1))
01204          ast_cli(a->fd, "Failed to transfer :(\n");
01205    }
01206    if (tmp)
01207       ast_free(tmp);
01208    return CLI_SUCCESS;
01209 }
01210 
01211 static char *console_active(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01212 {
01213    switch (cmd) {
01214    case CLI_INIT:
01215       e->command = "console {set|show} active [<device>]";
01216       e->usage =
01217          "Usage: console active [device]\n"
01218          "       If used without a parameter, displays which device is the current\n"
01219          "       console.  If a device is specified, the console sound device is changed to\n"
01220          "       the device specified.\n";
01221       return NULL;
01222    case CLI_GENERATE:
01223       return NULL;
01224    }
01225 
01226    if (a->argc == 3)
01227       ast_cli(a->fd, "active console is [%s]\n", oss_active);
01228    else if (a->argc != 4)
01229       return CLI_SHOWUSAGE;
01230    else {
01231       struct chan_oss_pvt *o;
01232       if (strcmp(a->argv[3], "show") == 0) {
01233          for (o = oss_default.next; o; o = o->next)
01234             ast_cli(a->fd, "device [%s] exists\n", o->name);
01235          return CLI_SUCCESS;
01236       }
01237       o = find_desc(a->argv[3]);
01238       if (o == NULL)
01239          ast_cli(a->fd, "No device [%s] exists\n", a->argv[3]);
01240       else
01241          oss_active = o->name;
01242    }
01243    return CLI_SUCCESS;
01244 }
01245 
01246 /*!
01247  * \brief store the boost factor
01248  */
01249 static void store_boost(struct chan_oss_pvt *o, const char *s)
01250 {
01251    double boost = 0;
01252    if (sscanf(s, "%30lf", &boost) != 1) {
01253       ast_log(LOG_WARNING, "invalid boost <%s>\n", s);
01254       return;
01255    }
01256    if (boost < -BOOST_MAX) {
01257       ast_log(LOG_WARNING, "boost %s too small, using %d\n", s, -BOOST_MAX);
01258       boost = -BOOST_MAX;
01259    } else if (boost > BOOST_MAX) {
01260       ast_log(LOG_WARNING, "boost %s too large, using %d\n", s, BOOST_MAX);
01261       boost = BOOST_MAX;
01262    }
01263    boost = exp(log(10) * boost / 20) * BOOST_SCALE;
01264    o->boost = boost;
01265    ast_log(LOG_WARNING, "setting boost %s to %d\n", s, o->boost);
01266 }
01267 
01268 static char *console_boost(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01269 {
01270    struct chan_oss_pvt *o = find_desc(oss_active);
01271 
01272    switch (cmd) {
01273    case CLI_INIT:
01274       e->command = "console boost";
01275       e->usage =
01276          "Usage: console boost [boost in dB]\n"
01277          "       Sets or display mic boost in dB\n";
01278       return NULL;
01279    case CLI_GENERATE:
01280       return NULL;
01281    }
01282 
01283    if (a->argc == 2)
01284       ast_cli(a->fd, "boost currently %5.1f\n", 20 * log10(((double) o->boost / (double) BOOST_SCALE)));
01285    else if (a->argc == 3)
01286       store_boost(o, a->argv[2]);
01287    return CLI_SUCCESS;
01288 }
01289 
01290 static struct ast_cli_entry cli_oss[] = {
01291    AST_CLI_DEFINE(console_answer, "Answer an incoming console call"),
01292    AST_CLI_DEFINE(console_hangup, "Hangup a call on the console"),
01293    AST_CLI_DEFINE(console_flash, "Flash a call on the console"),
01294    AST_CLI_DEFINE(console_dial, "Dial an extension on the console"),
01295    AST_CLI_DEFINE(console_mute, "Disable/Enable mic input"),
01296    AST_CLI_DEFINE(console_transfer, "Transfer a call to a different extension"), 
01297    AST_CLI_DEFINE(console_cmd, "Generic console command"),
01298    AST_CLI_DEFINE(console_sendtext, "Send text to the remote device"),
01299    AST_CLI_DEFINE(console_autoanswer, "Sets/displays autoanswer"),
01300    AST_CLI_DEFINE(console_boost, "Sets/displays mic boost in dB"),
01301    AST_CLI_DEFINE(console_active, "Sets/displays active console"),
01302 };
01303 
01304 /*!
01305  * store the mixer argument from the config file, filtering possibly
01306  * invalid or dangerous values (the string is used as argument for
01307  * system("mixer %s")
01308  */
01309 static void store_mixer(struct chan_oss_pvt *o, const char *s)
01310 {
01311    int i;
01312 
01313    for (i = 0; i < strlen(s); i++) {
01314       if (!isalnum(s[i]) && strchr(" \t-/", s[i]) == NULL) {
01315          ast_log(LOG_WARNING, "Suspect char %c in mixer cmd, ignoring:\n\t%s\n", s[i], s);
01316          return;
01317       }
01318    }
01319    if (o->mixer_cmd)
01320       ast_free(o->mixer_cmd);
01321    o->mixer_cmd = ast_strdup(s);
01322    ast_log(LOG_WARNING, "setting mixer %s\n", s);
01323 }
01324 
01325 /*!
01326  * store the callerid components
01327  */
01328 static void store_callerid(struct chan_oss_pvt *o, const char *s)
01329 {
01330    ast_callerid_split(s, o->cid_name, sizeof(o->cid_name), o->cid_num, sizeof(o->cid_num));
01331 }
01332 
01333 static void store_config_core(struct chan_oss_pvt *o, const char *var, const char *value)
01334 {
01335    CV_START(var, value);
01336 
01337    /* handle jb conf */
01338    if (!ast_jb_read_conf(&global_jbconf, var, value))
01339       return;
01340 
01341    if (!console_video_config(&o->env, var, value))
01342       return;  /* matched there */
01343    CV_BOOL("autoanswer", o->autoanswer);
01344    CV_BOOL("autohangup", o->autohangup);
01345    CV_BOOL("overridecontext", o->overridecontext);
01346    CV_STR("device", o->device);
01347    CV_UINT("frags", o->frags);
01348    CV_UINT("debug", oss_debug);
01349    CV_UINT("queuesize", o->queuesize);
01350    CV_STR("context", o->ctx);
01351    CV_STR("language", o->language);
01352    CV_STR("mohinterpret", o->mohinterpret);
01353    CV_STR("extension", o->ext);
01354    CV_F("mixer", store_mixer(o, value));
01355    CV_F("callerid", store_callerid(o, value))  ;
01356    CV_F("boost", store_boost(o, value));
01357 
01358    CV_END;
01359 }
01360 
01361 /*!
01362  * grab fields from the config file, init the descriptor and open the device.
01363  */
01364 static struct chan_oss_pvt *store_config(struct ast_config *cfg, char *ctg)
01365 {
01366    struct ast_variable *v;
01367    struct chan_oss_pvt *o;
01368 
01369    if (ctg == NULL) {
01370       o = &oss_default;
01371       ctg = "general";
01372    } else {
01373       if (!(o = ast_calloc(1, sizeof(*o))))
01374          return NULL;
01375       *o = oss_default;
01376       /* "general" is also the default thing */
01377       if (strcmp(ctg, "general") == 0) {
01378          o->name = ast_strdup("dsp");
01379          oss_active = o->name;
01380          goto openit;
01381       }
01382       o->name = ast_strdup(ctg);
01383    }
01384 
01385    strcpy(o->mohinterpret, "default");
01386 
01387    o->lastopen = ast_tvnow(); /* don't leave it 0 or tvdiff may wrap */
01388    /* fill other fields from configuration */
01389    for (v = ast_variable_browse(cfg, ctg); v; v = v->next) {
01390       store_config_core(o, v->name, v->value);
01391    }
01392    if (ast_strlen_zero(o->device))
01393       ast_copy_string(o->device, DEV_DSP, sizeof(o->device));
01394    if (o->mixer_cmd) {
01395       char *cmd;
01396 
01397       if (ast_asprintf(&cmd, "mixer %s", o->mixer_cmd) >= 0) {
01398          ast_log(LOG_WARNING, "running [%s]\n", cmd);
01399          if (system(cmd) < 0) {
01400             ast_log(LOG_WARNING, "system() failed: %s\n", strerror(errno));
01401          }
01402          ast_free(cmd);
01403       }
01404    }
01405 
01406    /* if the config file requested to start the GUI, do it */
01407    if (get_gui_startup(o->env))
01408       console_video_start(o->env, NULL);
01409 
01410    if (o == &oss_default)     /* we are done with the default */
01411       return NULL;
01412 
01413 openit:
01414 #ifdef TRYOPEN
01415    if (setformat(o, O_RDWR) < 0) {  /* open device */
01416       ast_verb(1, "Device %s not detected\n", ctg);
01417       ast_verb(1, "Turn off OSS support by adding " "'noload=chan_oss.so' in /etc/asterisk/modules.conf\n");
01418       goto error;
01419    }
01420    if (o->duplex != M_FULL)
01421       ast_log(LOG_WARNING, "XXX I don't work right with non " "full-duplex sound cards XXX\n");
01422 #endif /* TRYOPEN */
01423 
01424    /* link into list of devices */
01425    if (o != &oss_default) {
01426       o->next = oss_default.next;
01427       oss_default.next = o;
01428    }
01429    return o;
01430 
01431 #ifdef TRYOPEN
01432 error:
01433    if (o != &oss_default)
01434       ast_free(o);
01435    return NULL;
01436 #endif
01437 }
01438 
01439 static int load_module(void)
01440 {
01441    struct ast_config *cfg = NULL;
01442    char *ctg = NULL;
01443    struct ast_flags config_flags = { 0 };
01444    struct ast_format tmpfmt;
01445 
01446    /* Copy the default jb config over global_jbconf */
01447    memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
01448 
01449    /* load config file */
01450    if (!(cfg = ast_config_load(config, config_flags))) {
01451       ast_log(LOG_NOTICE, "Unable to load config %s\n", config);
01452       return AST_MODULE_LOAD_DECLINE;
01453    } else if (cfg == CONFIG_STATUS_FILEINVALID) {
01454       ast_log(LOG_ERROR, "Config file %s is in an invalid format.  Aborting.\n", config);
01455       return AST_MODULE_LOAD_DECLINE;
01456    }
01457 
01458    do {
01459       store_config(cfg, ctg);
01460    } while ( (ctg = ast_category_browse(cfg, ctg)) != NULL);
01461 
01462    ast_config_destroy(cfg);
01463 
01464    if (find_desc(oss_active) == NULL) {
01465       ast_log(LOG_NOTICE, "Device %s not found\n", oss_active);
01466       /* XXX we could default to 'dsp' perhaps ? */
01467       /* XXX should cleanup allocated memory etc. */
01468       return AST_MODULE_LOAD_FAILURE;
01469    }
01470 
01471    if (!(oss_tech.capabilities = ast_format_cap_alloc())) {
01472       return AST_MODULE_LOAD_FAILURE;
01473    }
01474    ast_format_cap_add(oss_tech.capabilities, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0));
01475 
01476    /* TODO XXX CONSOLE VIDEO IS DISABLE UNTIL IT HAS A MAINTAINER
01477     * add console_video_formats to oss_tech.capabilities once this occurs. */
01478 
01479    if (ast_channel_register(&oss_tech)) {
01480       ast_log(LOG_ERROR, "Unable to register channel type 'OSS'\n");
01481       return AST_MODULE_LOAD_DECLINE;
01482    }
01483 
01484    ast_cli_register_multiple(cli_oss, ARRAY_LEN(cli_oss));
01485 
01486    return AST_MODULE_LOAD_SUCCESS;
01487 }
01488 
01489 
01490 static int unload_module(void)
01491 {
01492    struct chan_oss_pvt *o, *next;
01493 
01494    ast_channel_unregister(&oss_tech);
01495    ast_cli_unregister_multiple(cli_oss, ARRAY_LEN(cli_oss));
01496 
01497    o = oss_default.next;
01498    while (o) {
01499       close(o->sounddev);
01500       if (o->owner)
01501          ast_softhangup(o->owner, AST_SOFTHANGUP_APPUNLOAD);
01502       if (o->owner)
01503          return -1;
01504       next = o->next;
01505       ast_free(o->name);
01506       ast_free(o);
01507       o = next;
01508    }
01509    oss_tech.capabilities = ast_format_cap_destroy(oss_tech.capabilities);
01510    return 0;
01511 }
01512 
01513 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "OSS Console Channel Driver");