Thu Oct 11 06:47:10 2012

Asterisk developer's documentation


chan_oss.c

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

Generated on Thu Oct 11 06:47:10 2012 for Asterisk - the Open Source PBX by  doxygen 1.5.6