Sat Feb 11 06:33: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    <support_level>extended</support_level>
00039  ***/
00040 
00041 #include "asterisk.h"
00042 
00043 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 353685 $")
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 ? c->tech_pvt : find_desc(oss_active);
00312    return o ? o->env : NULL;
00313 }
00314 static struct chan_oss_pvt oss_default = {
00315    .sounddev = -1,
00316    .duplex = M_UNSET,         /* XXX check this */
00317    .autoanswer = 1,
00318    .autohangup = 1,
00319    .queuesize = QUEUE_SIZE,
00320    .frags = FRAGS,
00321    .ext = "s",
00322    .ctx = "default",
00323    .readpos = AST_FRIENDLY_OFFSET,  /* start here on reads */
00324    .lastopen = { 0, 0 },
00325    .boost = BOOST_SCALE,
00326 };
00327 
00328 
00329 static int setformat(struct chan_oss_pvt *o, int mode);
00330 
00331 static struct ast_channel *oss_request(const char *type, 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 audio device to mono\n");
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 = c->tech_pvt;
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(c->dialed.number.str, ""),
00608       S_COR(c->redirecting.from.number.valid, c->redirecting.from.number.str, ""),
00609       S_COR(c->caller.id.name.valid, c->caller.id.name.str, ""),
00610       S_COR(c->caller.id.number.valid, c->caller.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 = c->tech_pvt;
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 = c->tech_pvt;
00647 
00648    c->tech_pvt = 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 = c->tech_pvt;
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 = c->tech_pvt;
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 (c->_state != 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 = newchan->tech_pvt;
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 = c->tech_pvt;
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 -1:
00762       res = -1;
00763       break;
00764    case AST_CONTROL_PROGRESS:
00765    case AST_CONTROL_PROCEEDING:
00766    case AST_CONTROL_VIDUPDATE:
00767    case AST_CONTROL_SRCUPDATE:
00768       break;
00769    case AST_CONTROL_HOLD:
00770       ast_verbose(" << Console Has Been Placed on Hold >> \n");
00771       ast_moh_start(c, data, o->mohinterpret);
00772       break;
00773    case AST_CONTROL_UNHOLD:
00774       ast_verbose(" << Console Has Been Retrieved from Hold >> \n");
00775       ast_moh_stop(c);
00776       break;
00777    default:
00778       ast_log(LOG_WARNING, "Don't know how to display condition %d on %s\n", cond, ast_channel_name(c));
00779       return -1;
00780    }
00781 
00782    return res;
00783 }
00784 
00785 /*!
00786  * \brief allocate a new channel.
00787  */
00788 static struct ast_channel *oss_new(struct chan_oss_pvt *o, char *ext, char *ctx, int state, const char *linkedid)
00789 {
00790    struct ast_channel *c;
00791 
00792    c = ast_channel_alloc(1, state, o->cid_num, o->cid_name, "", ext, ctx, linkedid, 0, "Console/%s", o->device + 5);
00793    if (c == NULL)
00794       return NULL;
00795    c->tech = &oss_tech;
00796    if (o->sounddev < 0)
00797       setformat(o, O_RDWR);
00798    ast_channel_set_fd(c, 0, o->sounddev); /* -1 if device closed, override later */
00799 
00800    ast_format_set(&c->readformat, AST_FORMAT_SLINEAR, 0);
00801    ast_format_set(&c->writeformat, AST_FORMAT_SLINEAR, 0);
00802    ast_format_cap_add(c->nativeformats, &c->readformat);
00803 
00804    /* if the console makes the call, add video to the offer */
00805    /* if (state == AST_STATE_RINGING) TODO XXX CONSOLE VIDEO IS DISABLED UNTIL IT GETS A MAINTAINER
00806       c->nativeformats |= console_video_formats; */
00807 
00808    c->tech_pvt = o;
00809 
00810    if (!ast_strlen_zero(o->language))
00811       ast_channel_language_set(c, o->language);
00812    /* Don't use ast_set_callerid() here because it will
00813     * generate a needless NewCallerID event */
00814    if (!ast_strlen_zero(o->cid_num)) {
00815       c->caller.ani.number.valid = 1;
00816       c->caller.ani.number.str = ast_strdup(o->cid_num);
00817    }
00818    if (!ast_strlen_zero(ext)) {
00819       c->dialed.number.str = ast_strdup(ext);
00820    }
00821 
00822    o->owner = c;
00823    ast_module_ref(ast_module_info->self);
00824    ast_jb_configure(c, &global_jbconf);
00825    if (state != AST_STATE_DOWN) {
00826       if (ast_pbx_start(c)) {
00827          ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(c));
00828          ast_hangup(c);
00829          o->owner = c = NULL;
00830       }
00831    }
00832    console_video_start(get_video_desc(c), c); /* XXX cleanup */
00833 
00834    return c;
00835 }
00836 
00837 static struct ast_channel *oss_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause)
00838 {
00839    struct ast_channel *c;
00840    struct chan_oss_pvt *o;
00841    AST_DECLARE_APP_ARGS(args,
00842       AST_APP_ARG(name);
00843       AST_APP_ARG(flags);
00844    );
00845    char *parse = ast_strdupa(data);
00846    char buf[256];
00847    struct ast_format tmpfmt;
00848 
00849    AST_NONSTANDARD_APP_ARGS(args, parse, '/');
00850    o = find_desc(args.name);
00851 
00852    ast_log(LOG_WARNING, "oss_request ty <%s> data 0x%p <%s>\n", type, data, data);
00853    if (o == NULL) {
00854       ast_log(LOG_NOTICE, "Device %s not found\n", args.name);
00855       /* XXX we could default to 'dsp' perhaps ? */
00856       return NULL;
00857    }
00858    if (!(ast_format_cap_iscompatible(cap, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0)))) {
00859       ast_log(LOG_NOTICE, "Format %s unsupported\n", ast_getformatname_multiple(buf, sizeof(buf), cap));
00860       return NULL;
00861    }
00862    if (o->owner) {
00863       ast_log(LOG_NOTICE, "Already have a call (chan %p) on the OSS channel\n", o->owner);
00864       *cause = AST_CAUSE_BUSY;
00865       return NULL;
00866    }
00867    c = oss_new(o, NULL, NULL, AST_STATE_DOWN, requestor ? ast_channel_linkedid(requestor) : NULL);
00868    if (c == NULL) {
00869       ast_log(LOG_WARNING, "Unable to create new OSS channel\n");
00870       return NULL;
00871    }
00872    return c;
00873 }
00874 
00875 static void store_config_core(struct chan_oss_pvt *o, const char *var, const char *value);
00876 
00877 /*! Generic console command handler. Basically a wrapper for a subset
00878  *  of config file options which are also available from the CLI
00879  */
00880 static char *console_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00881 {
00882    struct chan_oss_pvt *o = find_desc(oss_active);
00883    const char *var, *value;
00884    switch (cmd) {
00885    case CLI_INIT:
00886       e->command = CONSOLE_VIDEO_CMDS;
00887       e->usage = 
00888          "Usage: " CONSOLE_VIDEO_CMDS "...\n"
00889          "       Generic handler for console commands.\n";
00890       return NULL;
00891 
00892    case CLI_GENERATE:
00893       return NULL;
00894    }
00895 
00896    if (a->argc < e->args)
00897       return CLI_SHOWUSAGE;
00898    if (o == NULL) {
00899       ast_log(LOG_WARNING, "Cannot find device %s (should not happen!)\n",
00900          oss_active);
00901       return CLI_FAILURE;
00902    }
00903    var = a->argv[e->args-1];
00904    value = a->argc > e->args ? a->argv[e->args] : NULL;
00905    if (value)      /* handle setting */
00906       store_config_core(o, var, value);
00907    if (!console_video_cli(o->env, var, a->fd))  /* print video-related values */
00908       return CLI_SUCCESS;
00909    /* handle other values */
00910    if (!strcasecmp(var, "device")) {
00911       ast_cli(a->fd, "device is [%s]\n", o->device);
00912    }
00913    return CLI_SUCCESS;
00914 }
00915 
00916 static char *console_autoanswer(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00917 {
00918    struct chan_oss_pvt *o = find_desc(oss_active);
00919 
00920    switch (cmd) {
00921    case CLI_INIT:
00922       e->command = "console {set|show} autoanswer [on|off]";
00923       e->usage =
00924          "Usage: console {set|show} autoanswer [on|off]\n"
00925          "       Enables or disables autoanswer feature.  If used without\n"
00926          "       argument, displays the current on/off status of autoanswer.\n"
00927          "       The default value of autoanswer is in 'oss.conf'.\n";
00928       return NULL;
00929 
00930    case CLI_GENERATE:
00931       return NULL;
00932    }
00933 
00934    if (a->argc == e->args - 1) {
00935       ast_cli(a->fd, "Auto answer is %s.\n", o->autoanswer ? "on" : "off");
00936       return CLI_SUCCESS;
00937    }
00938    if (a->argc != e->args)
00939       return CLI_SHOWUSAGE;
00940    if (o == NULL) {
00941       ast_log(LOG_WARNING, "Cannot find device %s (should not happen!)\n",
00942           oss_active);
00943       return CLI_FAILURE;
00944    }
00945    if (!strcasecmp(a->argv[e->args-1], "on"))
00946       o->autoanswer = 1;
00947    else if (!strcasecmp(a->argv[e->args - 1], "off"))
00948       o->autoanswer = 0;
00949    else
00950       return CLI_SHOWUSAGE;
00951    return CLI_SUCCESS;
00952 }
00953 
00954 /*! \brief helper function for the answer key/cli command */
00955 static char *console_do_answer(int fd)
00956 {
00957    struct ast_frame f = { AST_FRAME_CONTROL, { AST_CONTROL_ANSWER } };
00958    struct chan_oss_pvt *o = find_desc(oss_active);
00959    if (!o->owner) {
00960       if (fd > -1)
00961          ast_cli(fd, "No one is calling us\n");
00962       return CLI_FAILURE;
00963    }
00964    o->hookstate = 1;
00965    ast_queue_frame(o->owner, &f);
00966    return CLI_SUCCESS;
00967 }
00968 
00969 /*!
00970  * \brief answer command from the console
00971  */
00972 static char *console_answer(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00973 {
00974    switch (cmd) {
00975    case CLI_INIT:
00976       e->command = "console answer";
00977       e->usage =
00978          "Usage: console answer\n"
00979          "       Answers an incoming call on the console (OSS) channel.\n";
00980       return NULL;
00981 
00982    case CLI_GENERATE:
00983       return NULL;   /* no completion */
00984    }
00985    if (a->argc != e->args)
00986       return CLI_SHOWUSAGE;
00987    return console_do_answer(a->fd);
00988 }
00989 
00990 /*!
00991  * \brief Console send text CLI command
00992  *
00993  * \note concatenate all arguments into a single string. argv is NULL-terminated
00994  * so we can use it right away
00995  */
00996 static char *console_sendtext(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00997 {
00998    struct chan_oss_pvt *o = find_desc(oss_active);
00999    char buf[TEXT_SIZE];
01000 
01001    if (cmd == CLI_INIT) {
01002       e->command = "console send text";
01003       e->usage =
01004          "Usage: console send text <message>\n"
01005          "       Sends a text message for display on the remote terminal.\n";
01006       return NULL;
01007    } else if (cmd == CLI_GENERATE)
01008       return NULL;
01009 
01010    if (a->argc < e->args + 1)
01011       return CLI_SHOWUSAGE;
01012    if (!o->owner) {
01013       ast_cli(a->fd, "Not in a call\n");
01014       return CLI_FAILURE;
01015    }
01016    ast_join(buf, sizeof(buf) - 1, a->argv + e->args);
01017    if (!ast_strlen_zero(buf)) {
01018       struct ast_frame f = { 0, };
01019       int i = strlen(buf);
01020       buf[i] = '\n';
01021       f.frametype = AST_FRAME_TEXT;
01022       f.subclass.integer = 0;
01023       f.data.ptr = buf;
01024       f.datalen = i + 1;
01025       ast_queue_frame(o->owner, &f);
01026    }
01027    return CLI_SUCCESS;
01028 }
01029 
01030 static char *console_hangup(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01031 {
01032    struct chan_oss_pvt *o = find_desc(oss_active);
01033 
01034    if (cmd == CLI_INIT) {
01035       e->command = "console hangup";
01036       e->usage =
01037          "Usage: console hangup\n"
01038          "       Hangs up any call currently placed on the console.\n";
01039       return NULL;
01040    } else if (cmd == CLI_GENERATE)
01041       return NULL;
01042 
01043    if (a->argc != e->args)
01044       return CLI_SHOWUSAGE;
01045    if (!o->owner && !o->hookstate) { /* XXX maybe only one ? */
01046       ast_cli(a->fd, "No call to hang up\n");
01047       return CLI_FAILURE;
01048    }
01049    o->hookstate = 0;
01050    if (o->owner)
01051       ast_queue_hangup_with_cause(o->owner, AST_CAUSE_NORMAL_CLEARING);
01052    setformat(o, O_CLOSE);
01053    return CLI_SUCCESS;
01054 }
01055 
01056 static char *console_flash(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01057 {
01058    struct ast_frame f = { AST_FRAME_CONTROL, { AST_CONTROL_FLASH } };
01059    struct chan_oss_pvt *o = find_desc(oss_active);
01060 
01061    if (cmd == CLI_INIT) {
01062       e->command = "console flash";
01063       e->usage =
01064          "Usage: console flash\n"
01065          "       Flashes the call currently placed on the console.\n";
01066       return NULL;
01067    } else if (cmd == CLI_GENERATE)
01068       return NULL;
01069 
01070    if (a->argc != e->args)
01071       return CLI_SHOWUSAGE;
01072    if (!o->owner) {        /* XXX maybe !o->hookstate too ? */
01073       ast_cli(a->fd, "No call to flash\n");
01074       return CLI_FAILURE;
01075    }
01076    o->hookstate = 0;
01077    if (o->owner)
01078       ast_queue_frame(o->owner, &f);
01079    return CLI_SUCCESS;
01080 }
01081 
01082 static char *console_dial(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01083 {
01084    char *s = NULL;
01085    char *mye = NULL, *myc = NULL;
01086    struct chan_oss_pvt *o = find_desc(oss_active);
01087 
01088    if (cmd == CLI_INIT) {
01089       e->command = "console dial";
01090       e->usage =
01091          "Usage: console dial [extension[@context]]\n"
01092          "       Dials a given extension (and context if specified)\n";
01093       return NULL;
01094    } else if (cmd == CLI_GENERATE)
01095       return NULL;
01096 
01097    if (a->argc > e->args + 1)
01098       return CLI_SHOWUSAGE;
01099    if (o->owner) {   /* already in a call */
01100       int i;
01101       struct ast_frame f = { AST_FRAME_DTMF, { 0 } };
01102       const char *s;
01103 
01104       if (a->argc == e->args) {  /* argument is mandatory here */
01105          ast_cli(a->fd, "Already in a call. You can only dial digits until you hangup.\n");
01106          return CLI_FAILURE;
01107       }
01108       s = a->argv[e->args];
01109       /* send the string one char at a time */
01110       for (i = 0; i < strlen(s); i++) {
01111          f.subclass.integer = s[i];
01112          ast_queue_frame(o->owner, &f);
01113       }
01114       return CLI_SUCCESS;
01115    }
01116    /* if we have an argument split it into extension and context */
01117    if (a->argc == e->args + 1)
01118       s = ast_ext_ctx(a->argv[e->args], &mye, &myc);
01119    /* supply default values if needed */
01120    if (mye == NULL)
01121       mye = o->ext;
01122    if (myc == NULL)
01123       myc = o->ctx;
01124    if (ast_exists_extension(NULL, myc, mye, 1, NULL)) {
01125       o->hookstate = 1;
01126       oss_new(o, mye, myc, AST_STATE_RINGING, NULL);
01127    } else
01128       ast_cli(a->fd, "No such extension '%s' in context '%s'\n", mye, myc);
01129    if (s)
01130       ast_free(s);
01131    return CLI_SUCCESS;
01132 }
01133 
01134 static char *console_mute(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01135 {
01136    struct chan_oss_pvt *o = find_desc(oss_active);
01137    const char *s;
01138    int toggle = 0;
01139    
01140    if (cmd == CLI_INIT) {
01141       e->command = "console {mute|unmute} [toggle]";
01142       e->usage =
01143          "Usage: console {mute|unmute} [toggle]\n"
01144          "       Mute/unmute the microphone.\n";
01145       return NULL;
01146    } else if (cmd == CLI_GENERATE)
01147       return NULL;
01148 
01149    if (a->argc > e->args)
01150       return CLI_SHOWUSAGE;
01151    if (a->argc == e->args) {
01152       if (strcasecmp(a->argv[e->args-1], "toggle"))
01153          return CLI_SHOWUSAGE;
01154       toggle = 1;
01155    }
01156    s = a->argv[e->args-2];
01157    if (!strcasecmp(s, "mute"))
01158       o->mute = toggle ? !o->mute : 1;
01159    else if (!strcasecmp(s, "unmute"))
01160       o->mute = toggle ? !o->mute : 0;
01161    else
01162       return CLI_SHOWUSAGE;
01163    ast_cli(a->fd, "Console mic is %s\n", o->mute ? "off" : "on");
01164    return CLI_SUCCESS;
01165 }
01166 
01167 static char *console_transfer(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01168 {
01169    struct chan_oss_pvt *o = find_desc(oss_active);
01170    struct ast_channel *b = NULL;
01171    char *tmp, *ext, *ctx;
01172 
01173    switch (cmd) {
01174    case CLI_INIT:
01175       e->command = "console transfer";
01176       e->usage =
01177          "Usage: console transfer <extension>[@context]\n"
01178          "       Transfers the currently connected call to the given extension (and\n"
01179          "       context if specified)\n";
01180       return NULL;
01181    case CLI_GENERATE:
01182       return NULL;
01183    }
01184 
01185    if (a->argc != 3)
01186       return CLI_SHOWUSAGE;
01187    if (o == NULL)
01188       return CLI_FAILURE;
01189    if (o->owner == NULL || (b = ast_bridged_channel(o->owner)) == NULL) {
01190       ast_cli(a->fd, "There is no call to transfer\n");
01191       return CLI_SUCCESS;
01192    }
01193 
01194    tmp = ast_ext_ctx(a->argv[2], &ext, &ctx);
01195    if (ctx == NULL)        /* supply default context if needed */
01196       ctx = o->owner->context;
01197    if (!ast_exists_extension(b, ctx, ext, 1,
01198       S_COR(b->caller.id.number.valid, b->caller.id.number.str, NULL))) {
01199       ast_cli(a->fd, "No such extension exists\n");
01200    } else {
01201       ast_cli(a->fd, "Whee, transferring %s to %s@%s.\n", ast_channel_name(b), ext, ctx);
01202       if (ast_async_goto(b, ctx, ext, 1))
01203          ast_cli(a->fd, "Failed to transfer :(\n");
01204    }
01205    if (tmp)
01206       ast_free(tmp);
01207    return CLI_SUCCESS;
01208 }
01209 
01210 static char *console_active(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01211 {
01212    switch (cmd) {
01213    case CLI_INIT:
01214       e->command = "console {set|show} active [<device>]";
01215       e->usage =
01216          "Usage: console active [device]\n"
01217          "       If used without a parameter, displays which device is the current\n"
01218          "       console.  If a device is specified, the console sound device is changed to\n"
01219          "       the device specified.\n";
01220       return NULL;
01221    case CLI_GENERATE:
01222       return NULL;
01223    }
01224 
01225    if (a->argc == 3)
01226       ast_cli(a->fd, "active console is [%s]\n", oss_active);
01227    else if (a->argc != 4)
01228       return CLI_SHOWUSAGE;
01229    else {
01230       struct chan_oss_pvt *o;
01231       if (strcmp(a->argv[3], "show") == 0) {
01232          for (o = oss_default.next; o; o = o->next)
01233             ast_cli(a->fd, "device [%s] exists\n", o->name);
01234          return CLI_SUCCESS;
01235       }
01236       o = find_desc(a->argv[3]);
01237       if (o == NULL)
01238          ast_cli(a->fd, "No device [%s] exists\n", a->argv[3]);
01239       else
01240          oss_active = o->name;
01241    }
01242    return CLI_SUCCESS;
01243 }
01244 
01245 /*!
01246  * \brief store the boost factor
01247  */
01248 static void store_boost(struct chan_oss_pvt *o, const char *s)
01249 {
01250    double boost = 0;
01251    if (sscanf(s, "%30lf", &boost) != 1) {
01252       ast_log(LOG_WARNING, "invalid boost <%s>\n", s);
01253       return;
01254    }
01255    if (boost < -BOOST_MAX) {
01256       ast_log(LOG_WARNING, "boost %s too small, using %d\n", s, -BOOST_MAX);
01257       boost = -BOOST_MAX;
01258    } else if (boost > BOOST_MAX) {
01259       ast_log(LOG_WARNING, "boost %s too large, using %d\n", s, BOOST_MAX);
01260       boost = BOOST_MAX;
01261    }
01262    boost = exp(log(10) * boost / 20) * BOOST_SCALE;
01263    o->boost = boost;
01264    ast_log(LOG_WARNING, "setting boost %s to %d\n", s, o->boost);
01265 }
01266 
01267 static char *console_boost(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01268 {
01269    struct chan_oss_pvt *o = find_desc(oss_active);
01270 
01271    switch (cmd) {
01272    case CLI_INIT:
01273       e->command = "console boost";
01274       e->usage =
01275          "Usage: console boost [boost in dB]\n"
01276          "       Sets or display mic boost in dB\n";
01277       return NULL;
01278    case CLI_GENERATE:
01279       return NULL;
01280    }
01281 
01282    if (a->argc == 2)
01283       ast_cli(a->fd, "boost currently %5.1f\n", 20 * log10(((double) o->boost / (double) BOOST_SCALE)));
01284    else if (a->argc == 3)
01285       store_boost(o, a->argv[2]);
01286    return CLI_SUCCESS;
01287 }
01288 
01289 static struct ast_cli_entry cli_oss[] = {
01290    AST_CLI_DEFINE(console_answer, "Answer an incoming console call"),
01291    AST_CLI_DEFINE(console_hangup, "Hangup a call on the console"),
01292    AST_CLI_DEFINE(console_flash, "Flash a call on the console"),
01293    AST_CLI_DEFINE(console_dial, "Dial an extension on the console"),
01294    AST_CLI_DEFINE(console_mute, "Disable/Enable mic input"),
01295    AST_CLI_DEFINE(console_transfer, "Transfer a call to a different extension"), 
01296    AST_CLI_DEFINE(console_cmd, "Generic console command"),
01297    AST_CLI_DEFINE(console_sendtext, "Send text to the remote device"),
01298    AST_CLI_DEFINE(console_autoanswer, "Sets/displays autoanswer"),
01299    AST_CLI_DEFINE(console_boost, "Sets/displays mic boost in dB"),
01300    AST_CLI_DEFINE(console_active, "Sets/displays active console"),
01301 };
01302 
01303 /*!
01304  * store the mixer argument from the config file, filtering possibly
01305  * invalid or dangerous values (the string is used as argument for
01306  * system("mixer %s")
01307  */
01308 static void store_mixer(struct chan_oss_pvt *o, const char *s)
01309 {
01310    int i;
01311 
01312    for (i = 0; i < strlen(s); i++) {
01313       if (!isalnum(s[i]) && strchr(" \t-/", s[i]) == NULL) {
01314          ast_log(LOG_WARNING, "Suspect char %c in mixer cmd, ignoring:\n\t%s\n", s[i], s);
01315          return;
01316       }
01317    }
01318    if (o->mixer_cmd)
01319       ast_free(o->mixer_cmd);
01320    o->mixer_cmd = ast_strdup(s);
01321    ast_log(LOG_WARNING, "setting mixer %s\n", s);
01322 }
01323 
01324 /*!
01325  * store the callerid components
01326  */
01327 static void store_callerid(struct chan_oss_pvt *o, const char *s)
01328 {
01329    ast_callerid_split(s, o->cid_name, sizeof(o->cid_name), o->cid_num, sizeof(o->cid_num));
01330 }
01331 
01332 static void store_config_core(struct chan_oss_pvt *o, const char *var, const char *value)
01333 {
01334    CV_START(var, value);
01335 
01336    /* handle jb conf */
01337    if (!ast_jb_read_conf(&global_jbconf, var, value))
01338       return;
01339 
01340    if (!console_video_config(&o->env, var, value))
01341       return;  /* matched there */
01342    CV_BOOL("autoanswer", o->autoanswer);
01343    CV_BOOL("autohangup", o->autohangup);
01344    CV_BOOL("overridecontext", o->overridecontext);
01345    CV_STR("device", o->device);
01346    CV_UINT("frags", o->frags);
01347    CV_UINT("debug", oss_debug);
01348    CV_UINT("queuesize", o->queuesize);
01349    CV_STR("context", o->ctx);
01350    CV_STR("language", o->language);
01351    CV_STR("mohinterpret", o->mohinterpret);
01352    CV_STR("extension", o->ext);
01353    CV_F("mixer", store_mixer(o, value));
01354    CV_F("callerid", store_callerid(o, value))  ;
01355    CV_F("boost", store_boost(o, value));
01356 
01357    CV_END;
01358 }
01359 
01360 /*!
01361  * grab fields from the config file, init the descriptor and open the device.
01362  */
01363 static struct chan_oss_pvt *store_config(struct ast_config *cfg, char *ctg)
01364 {
01365    struct ast_variable *v;
01366    struct chan_oss_pvt *o;
01367 
01368    if (ctg == NULL) {
01369       o = &oss_default;
01370       ctg = "general";
01371    } else {
01372       if (!(o = ast_calloc(1, sizeof(*o))))
01373          return NULL;
01374       *o = oss_default;
01375       /* "general" is also the default thing */
01376       if (strcmp(ctg, "general") == 0) {
01377          o->name = ast_strdup("dsp");
01378          oss_active = o->name;
01379          goto openit;
01380       }
01381       o->name = ast_strdup(ctg);
01382    }
01383 
01384    strcpy(o->mohinterpret, "default");
01385 
01386    o->lastopen = ast_tvnow(); /* don't leave it 0 or tvdiff may wrap */
01387    /* fill other fields from configuration */
01388    for (v = ast_variable_browse(cfg, ctg); v; v = v->next) {
01389       store_config_core(o, v->name, v->value);
01390    }
01391    if (ast_strlen_zero(o->device))
01392       ast_copy_string(o->device, DEV_DSP, sizeof(o->device));
01393    if (o->mixer_cmd) {
01394       char *cmd;
01395 
01396       if (asprintf(&cmd, "mixer %s", o->mixer_cmd) < 0) {
01397          ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
01398       } else {
01399          ast_log(LOG_WARNING, "running [%s]\n", cmd);
01400          if (system(cmd) < 0) {
01401             ast_log(LOG_WARNING, "system() failed: %s\n", strerror(errno));
01402          }
01403          ast_free(cmd);
01404       }
01405    }
01406 
01407    /* if the config file requested to start the GUI, do it */
01408    if (get_gui_startup(o->env))
01409       console_video_start(o->env, NULL);
01410 
01411    if (o == &oss_default)     /* we are done with the default */
01412       return NULL;
01413 
01414 openit:
01415 #ifdef TRYOPEN
01416    if (setformat(o, O_RDWR) < 0) {  /* open device */
01417       ast_verb(1, "Device %s not detected\n", ctg);
01418       ast_verb(1, "Turn off OSS support by adding " "'noload=chan_oss.so' in /etc/asterisk/modules.conf\n");
01419       goto error;
01420    }
01421    if (o->duplex != M_FULL)
01422       ast_log(LOG_WARNING, "XXX I don't work right with non " "full-duplex sound cards XXX\n");
01423 #endif /* TRYOPEN */
01424 
01425    /* link into list of devices */
01426    if (o != &oss_default) {
01427       o->next = oss_default.next;
01428       oss_default.next = o;
01429    }
01430    return o;
01431 
01432 #ifdef TRYOPEN
01433 error:
01434    if (o != &oss_default)
01435       ast_free(o);
01436    return NULL;
01437 #endif
01438 }
01439 
01440 static int load_module(void)
01441 {
01442    struct ast_config *cfg = NULL;
01443    char *ctg = NULL;
01444    struct ast_flags config_flags = { 0 };
01445    struct ast_format tmpfmt;
01446 
01447    /* Copy the default jb config over global_jbconf */
01448    memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
01449 
01450    /* load config file */
01451    if (!(cfg = ast_config_load(config, config_flags))) {
01452       ast_log(LOG_NOTICE, "Unable to load config %s\n", config);
01453       return AST_MODULE_LOAD_DECLINE;
01454    } else if (cfg == CONFIG_STATUS_FILEINVALID) {
01455       ast_log(LOG_ERROR, "Config file %s is in an invalid format.  Aborting.\n", config);
01456       return AST_MODULE_LOAD_DECLINE;
01457    }
01458 
01459    do {
01460       store_config(cfg, ctg);
01461    } while ( (ctg = ast_category_browse(cfg, ctg)) != NULL);
01462 
01463    ast_config_destroy(cfg);
01464 
01465    if (find_desc(oss_active) == NULL) {
01466       ast_log(LOG_NOTICE, "Device %s not found\n", oss_active);
01467       /* XXX we could default to 'dsp' perhaps ? */
01468       /* XXX should cleanup allocated memory etc. */
01469       return AST_MODULE_LOAD_FAILURE;
01470    }
01471 
01472    if (!(oss_tech.capabilities = ast_format_cap_alloc())) {
01473       return AST_MODULE_LOAD_FAILURE;
01474    }
01475    ast_format_cap_add(oss_tech.capabilities, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0));
01476 
01477    /* TODO XXX CONSOLE VIDEO IS DISABLE UNTIL IT HAS A MAINTAINER
01478     * add console_video_formats to oss_tech.capabilities once this occurs. */
01479 
01480    if (ast_channel_register(&oss_tech)) {
01481       ast_log(LOG_ERROR, "Unable to register channel type 'OSS'\n");
01482       return AST_MODULE_LOAD_DECLINE;
01483    }
01484 
01485    ast_cli_register_multiple(cli_oss, ARRAY_LEN(cli_oss));
01486 
01487    return AST_MODULE_LOAD_SUCCESS;
01488 }
01489 
01490 
01491 static int unload_module(void)
01492 {
01493    struct chan_oss_pvt *o, *next;
01494 
01495    ast_channel_unregister(&oss_tech);
01496    ast_cli_unregister_multiple(cli_oss, ARRAY_LEN(cli_oss));
01497 
01498    o = oss_default.next;
01499    while (o) {
01500       close(o->sounddev);
01501       if (o->owner)
01502          ast_softhangup(o->owner, AST_SOFTHANGUP_APPUNLOAD);
01503       if (o->owner)
01504          return -1;
01505       next = o->next;
01506       ast_free(o->name);
01507       ast_free(o);
01508       o = next;
01509    }
01510    oss_tech.capabilities = ast_format_cap_destroy(oss_tech.capabilities);
01511    return 0;
01512 }
01513 
01514 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "OSS Console Channel Driver");

Generated on Sat Feb 11 06:33:10 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6