Wed Oct 28 15:47:51 2009

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 - 2005, 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 /*! \file
00023  *
00024  * \brief Channel driver for OSS sound cards
00025  *
00026  * \par See also
00027  * \arg \ref Config_oss
00028  *
00029  * \ingroup channel_drivers
00030  */
00031 
00032 #include <stdio.h>
00033 #include <ctype.h>   /* for isalnum */
00034 #include <string.h>
00035 #include <unistd.h>
00036 #include <sys/ioctl.h>
00037 #include <fcntl.h>
00038 #include <sys/time.h>
00039 #include <stdlib.h>
00040 #include <errno.h>
00041 
00042 
00043 #ifdef __linux
00044 #include <linux/soundcard.h>
00045 #elif defined(__FreeBSD__)
00046 #include <sys/soundcard.h>
00047 #else
00048 #include <soundcard.h>
00049 #endif
00050 
00051 #include "asterisk.h"
00052 
00053 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 36998 $")
00054 
00055 #include "asterisk/lock.h"
00056 #include "asterisk/frame.h"
00057 #include "asterisk/logger.h"
00058 #include "asterisk/channel.h"
00059 #include "asterisk/module.h"
00060 #include "asterisk/options.h"
00061 #include "asterisk/pbx.h"
00062 #include "asterisk/config.h"
00063 
00064 #include "asterisk/cli.h"
00065 #include "asterisk/utils.h"
00066 #include "asterisk/causes.h"
00067 #include "asterisk/endian.h"
00068 
00069 /* ringtones we use */
00070 #include "busy.h"
00071 #include "ringtone.h"
00072 #include "ring10.h"
00073 #include "answer.h"
00074 
00075 /*
00076  * Basic mode of operation:
00077  *
00078  * we have one keyboard (which receives commands from the keyboard)
00079  * and multiple headset's connected to audio cards.
00080  * Cards/Headsets are named as the sections of oss.conf.
00081  * The section called [general] contains the default parameters.
00082  *
00083  * At any time, the keyboard is attached to one card, and you
00084  * can switch among them using the command 'console foo'
00085  * where 'foo' is the name of the card you want.
00086  *
00087  * oss.conf parameters are
00088 
00089 [general]
00090 ; general config options, default values are shown
00091 ; all but debug can go also in the device-specific sections.
00092 ; debug=0x0    ; misc debug flags, default is 0
00093 
00094 [card1]
00095 ; autoanswer = no ; no autoanswer on call
00096 ; autohangup = yes   ; hangup when other party closes
00097 ; extension=s     ; default extension to call
00098 ; context=default ; default context
00099 ; language=""     ; default language
00100 ; overridecontext=yes   ; the whole dial string is considered an extension.
00101          ; if no, the last @ will start the context
00102 
00103 ; device=/dev/dsp ; device to open
00104 ; mixer="-f /dev/mixer0 pcm 80 ; mixer command to run on start
00105 ; queuesize=10    ; frames in device driver
00106 ; frags=8      ; argument to SETFRAGMENT
00107 
00108 .. and so on for the other cards.
00109 
00110  */
00111 
00112 /*
00113  * Helper macros to parse config arguments. They will go in a common
00114  * header file if their usage is globally accepted. In the meantime,
00115  * we define them here. Typical usage is as below.
00116  * Remember to open a block right before M_START (as it declares
00117  * some variables) and use the M_* macros WITHOUT A SEMICOLON:
00118  *
00119  * {
00120  *    M_START(v->name, v->value) 
00121  *
00122  *    M_BOOL("dothis", x->flag1)
00123  *    M_STR("name", x->somestring)
00124  *    M_F("bar", some_c_code)
00125  *    M_END(some_final_statement)
00126  *    ... other code in the block
00127  * }
00128  *
00129  * XXX NOTE these macros should NOT be replicated in other parts of asterisk. 
00130  * Likely we will come up with a better way of doing config file parsing.
00131  */
00132 #define M_START(var, val) \
00133         char *__s = var; char *__val = val;
00134 #define M_END(x)   x;
00135 #define M_F(tag, f)        if (!strcasecmp((__s), tag)) { f; } else
00136 #define M_BOOL(tag, dst)   M_F(tag, (dst) = ast_true(__val) )
00137 #define M_UINT(tag, dst)   M_F(tag, (dst) = strtoul(__val, NULL, 0) )
00138 #define M_STR(tag, dst)    M_F(tag, ast_copy_string(dst, __val, sizeof(dst)))
00139 
00140 /*
00141  * The following parameters are used in the driver:
00142  *
00143  *  FRAME_SIZE the size of an audio frame, in samples.
00144  *    160 is used almost universally, so you should not change it.
00145  *
00146  *  FRAGS   the argument for the SETFRAGMENT ioctl.
00147  *    Overridden by the 'frags' parameter in oss.conf
00148  *
00149  *    Bits 0-7 are the base-2 log of the device's block size,
00150  *    bits 16-31 are the number of blocks in the driver's queue.
00151  *    There are a lot of differences in the way this parameter
00152  *    is supported by different drivers, so you may need to
00153  *    experiment a bit with the value.
00154  *    A good default for linux is 30 blocks of 64 bytes, which
00155  *    results in 6 frames of 320 bytes (160 samples).
00156  *    FreeBSD works decently with blocks of 256 or 512 bytes,
00157  *    leaving the number unspecified.
00158  *    Note that this only refers to the device buffer size,
00159  *    this module will then try to keep the lenght of audio
00160  *    buffered within small constraints.
00161  *
00162  *  QUEUE_SIZE The max number of blocks actually allowed in the device
00163  *    driver's buffer, irrespective of the available number.
00164  *    Overridden by the 'queuesize' parameter in oss.conf
00165  *
00166  *    Should be >=2, and at most as large as the hw queue above
00167  *    (otherwise it will never be full).
00168  */
00169 
00170 #define FRAME_SIZE   160
00171 #define  QUEUE_SIZE  10
00172 
00173 #if defined(__FreeBSD__)
00174 #define  FRAGS 0x8
00175 #else
00176 #define  FRAGS ( ( (6 * 5) << 16 ) | 0x6 )
00177 #endif
00178 
00179 /*
00180  * XXX text message sizes are probably 256 chars, but i am
00181  * not sure if there is a suitable definition anywhere.
00182  */
00183 #define TEXT_SIZE 256
00184 
00185 #if 0
00186 #define  TRYOPEN  1  /* try to open on startup */
00187 #endif
00188 #define  O_CLOSE  0x444 /* special 'close' mode for device */
00189 /* Which device to use */
00190 #if defined( __OpenBSD__ ) || defined( __NetBSD__ )
00191 #define DEV_DSP "/dev/audio"
00192 #else
00193 #define DEV_DSP "/dev/dsp"
00194 #endif
00195 
00196 #ifndef MIN
00197 #define MIN(a,b) ((a) < (b) ? (a) : (b))
00198 #endif
00199 #ifndef MAX
00200 #define MAX(a,b) ((a) > (b) ? (a) : (b))
00201 #endif
00202 
00203 
00204 static int usecnt;
00205 AST_MUTEX_DEFINE_STATIC(usecnt_lock);
00206 
00207 static char *config = "oss.conf";   /* default config file */
00208 
00209 static int oss_debug;
00210 
00211 /*
00212  * Each sound is made of 'datalen' samples of sound, repeated as needed to
00213  * generate 'samplen' samples of data, then followed by 'silencelen' samples
00214  * of silence. The loop is repeated if 'repeat' is set.
00215  */
00216 struct sound {
00217    int ind;
00218    char *desc;
00219    short *data;
00220    int datalen;
00221    int samplen;
00222    int silencelen;
00223    int repeat;
00224 };
00225 
00226 static struct sound sounds[] = {
00227    { AST_CONTROL_RINGING, "RINGING", ringtone, sizeof(ringtone)/2, 16000, 32000, 1 },
00228    { AST_CONTROL_BUSY, "BUSY", busy, sizeof(busy)/2, 4000, 4000, 1 },
00229    { AST_CONTROL_CONGESTION, "CONGESTION", busy, sizeof(busy)/2, 2000, 2000, 1 },
00230    { AST_CONTROL_RING, "RING10", ring10, sizeof(ring10)/2, 16000, 32000, 1 },
00231    { AST_CONTROL_ANSWER, "ANSWER", answer, sizeof(answer)/2, 2200, 0, 0 },
00232    { -1, NULL, 0, 0, 0, 0 },  /* end marker */
00233 };
00234 
00235 
00236 /*
00237  * descriptor for one of our channels.
00238  * There is one used for 'default' values (from the [general] entry in
00239  * the configuration file), and then one instance for each device
00240  * (the default is cloned from [general], others are only created
00241  * if the relevant section exists).
00242  */
00243 struct chan_oss_pvt {
00244    struct chan_oss_pvt *next;
00245 
00246    char *type; /* XXX maybe take the one from oss_tech */
00247    char *name;
00248    /*
00249     * cursound indicates which in struct sound we play. -1 means nothing,
00250     * any other value is a valid sound, in which case sampsent indicates
00251     * the next sample to send in [0..samplen + silencelen]
00252     * nosound is set to disable the audio data from the channel
00253     * (so we can play the tones etc.).
00254     */
00255    int sndcmd[2]; /* Sound command pipe */
00256    int cursound;  /* index of sound to send */
00257    int sampsent;  /* # of sound samples sent */
00258    int nosound;   /* set to block audio from the PBX */
00259 
00260    int total_blocks; /* total blocks in the output device */
00261    int sounddev;
00262    enum { M_UNSET, M_FULL, M_READ, M_WRITE } duplex;
00263    int autoanswer;
00264    int autohangup;
00265    int hookstate;
00266    char *mixer_cmd;     /* initial command to issue to the mixer */
00267    unsigned int   queuesize;  /* max fragments in queue */
00268    unsigned int   frags;      /* parameter for SETFRAGMENT */
00269 
00270    int warned;    /* various flags used for warnings */
00271 #define WARN_used_blocks   1
00272 #define WARN_speed      2
00273 #define WARN_frag    4
00274    int w_errors;  /* overfull in the write path */
00275    struct timeval lastopen;
00276 
00277    int overridecontext;
00278    int mute;
00279    char device[64];  /* device to open */
00280 
00281    pthread_t sthread;
00282 
00283    struct ast_channel *owner;
00284    char ext[AST_MAX_EXTENSION];
00285    char ctx[AST_MAX_CONTEXT];
00286    char language[MAX_LANGUAGE];
00287 
00288    /* buffers used in oss_write */
00289    char oss_write_buf[FRAME_SIZE*2];
00290    int oss_write_dst;
00291    /* buffers used in oss_read - AST_FRIENDLY_OFFSET space for headers
00292     * plus enough room for a full frame
00293     */
00294    char oss_read_buf[FRAME_SIZE * 2 + AST_FRIENDLY_OFFSET];
00295    int readpos; /* read position above */
00296    struct ast_frame read_f;   /* returned by oss_read */
00297 };
00298 
00299 static struct chan_oss_pvt oss_default = {
00300    .type = "Console",
00301    .cursound = -1,
00302    .sounddev = -1,
00303    .duplex = M_UNSET, /* XXX check this */
00304    .autoanswer = 1,
00305    .autohangup = 1,
00306    .queuesize = QUEUE_SIZE,
00307    .frags = FRAGS,
00308    .ext = "s",
00309    .ctx = "default",
00310    .readpos = AST_FRIENDLY_OFFSET,  /* start here on reads */
00311    .lastopen = { 0, 0 },
00312 };
00313 
00314 static char *oss_active;    /* the active device */
00315 
00316 static int setformat(struct chan_oss_pvt *o, int mode);
00317 
00318 static struct ast_channel *oss_request(const char *type, int format, void *data
00319 , int *cause);
00320 static int oss_digit(struct ast_channel *c, char digit);
00321 static int oss_text(struct ast_channel *c, const char *text);
00322 static int oss_hangup(struct ast_channel *c);
00323 static int oss_answer(struct ast_channel *c);
00324 static struct ast_frame *oss_read(struct ast_channel *chan);
00325 static int oss_call(struct ast_channel *c, char *dest, int timeout);
00326 static int oss_write(struct ast_channel *chan, struct ast_frame *f);
00327 static int oss_indicate(struct ast_channel *chan, int cond);
00328 static int oss_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
00329 
00330 static const struct ast_channel_tech oss_tech = {
00331    .type =        "Console",
00332    .description = "OSS Console Channel Driver",
00333    .capabilities =   AST_FORMAT_SLINEAR,
00334    .requester =   oss_request,
00335    .send_digit =  oss_digit,
00336    .send_text =   oss_text,
00337    .hangup =      oss_hangup,
00338    .answer =      oss_answer,
00339    .read =        oss_read,
00340    .call =        oss_call,
00341    .write =    oss_write,
00342    .indicate =    oss_indicate,
00343    .fixup =    oss_fixup,
00344 };
00345 
00346 /*
00347  * returns a pointer to the descriptor with the given name
00348  */
00349 static struct chan_oss_pvt *find_desc(char *dev)
00350 {
00351    struct chan_oss_pvt *o;
00352 
00353    for (o = oss_default.next; o && strcmp(o->name, dev) != 0; o = o->next)
00354       ;
00355    if (o == NULL)
00356       ast_log(LOG_WARNING, "could not find <%s>\n", dev);
00357    return o;
00358 }
00359 
00360 /*
00361  * split a string in extension-context, returns pointers to malloc'ed
00362  * strings.
00363  * If we do not have 'overridecontext' then the last @ is considered as
00364  * a context separator, and the context is overridden.
00365  * This is usually not very necessary as you can play with the dialplan,
00366  * and it is nice not to need it because you have '@' in SIP addresses.
00367  * Return value is the buffer address.
00368  */
00369 static char *ast_ext_ctx(const char *src, char **ext, char **ctx)
00370 {
00371    struct chan_oss_pvt *o = find_desc(oss_active);
00372 
00373    if (ext == NULL || ctx == NULL)
00374       return NULL;   /* error */
00375    *ext = *ctx = NULL;
00376    if (src && *src != '\0')
00377       *ext = strdup(src);
00378    if (*ext == NULL)
00379       return NULL;
00380    if (!o->overridecontext) {
00381       /* parse from the right */
00382       *ctx = strrchr(*ext, '@');
00383       if (*ctx)
00384          *(*ctx)++ = '\0';
00385    }
00386    return *ext;
00387 }
00388 
00389 /*
00390  * Returns the number of blocks used in the audio output channel
00391  */
00392 static int used_blocks(struct chan_oss_pvt *o)
00393 {
00394    struct audio_buf_info info;
00395 
00396    if (ioctl(o->sounddev, SNDCTL_DSP_GETOSPACE, &info)) {
00397       if (! (o->warned & WARN_used_blocks)) {
00398          ast_log(LOG_WARNING, "Error reading output space\n");
00399          o->warned |= WARN_used_blocks;
00400       }
00401       return 1;
00402    }
00403    if (o->total_blocks == 0) {
00404       if (0) /* debugging */
00405          ast_log(LOG_WARNING, "fragtotal %d size %d avail %d\n",
00406              info.fragstotal,
00407              info.fragsize,
00408              info.fragments);
00409       o->total_blocks = info.fragments;
00410    }
00411    return o->total_blocks - info.fragments;
00412 }
00413 
00414 /* Write an exactly FRAME_SIZE sized frame */
00415 static int soundcard_writeframe(struct chan_oss_pvt *o, short *data)
00416 {  
00417    int res;
00418 
00419    if (o->sounddev < 0)
00420       setformat(o, O_RDWR);
00421    if (o->sounddev < 0)
00422       return 0;   /* not fatal */
00423    /*
00424     * Nothing complex to manage the audio device queue.
00425     * If the buffer is full just drop the extra, otherwise write.
00426     * XXX in some cases it might be useful to write anyways after
00427     * a number of failures, to restart the output chain.
00428     */
00429    res = used_blocks(o);
00430    if (res > o->queuesize) {  /* no room to write a block */
00431       if (o->w_errors++ == 0 && (oss_debug & 0x4))
00432          ast_log(LOG_WARNING, "write: used %d blocks (%d)\n",
00433              res, o->w_errors);
00434       return 0;
00435    }
00436    o->w_errors = 0;
00437    return write(o->sounddev, ((void *)data), FRAME_SIZE * 2);
00438 }
00439 
00440 /*
00441  * Handler for 'sound writable' events from the sound thread.
00442  * Builds a frame from the high level description of the sounds,
00443  * and passes it to the audio device.
00444  * The actual sound is made of 1 or more sequences of sound samples
00445  * (s->datalen, repeated to make s->samplen samples) followed by
00446  * s->silencelen samples of silence. The position in the sequence is stored
00447  * in o->sampsent, which goes between 0 .. s->samplen+s->silencelen.
00448  * In case we fail to write a frame, don't update o->sampsent.
00449  */
00450 static void send_sound(struct chan_oss_pvt *o)
00451 {
00452    short myframe[FRAME_SIZE];
00453    int ofs, l, start;
00454    int l_sampsent = o->sampsent;
00455    struct sound *s;
00456 
00457    if (o->cursound < 0) /* no sound to send */
00458       return;
00459    s = &sounds[o->cursound];
00460    for (ofs = 0; ofs < FRAME_SIZE; ofs += l) {
00461       l = s->samplen - l_sampsent;  /* # of available samples */
00462       if (l > 0) {
00463          start = l_sampsent % s->datalen; /* source offset */
00464          if (l > FRAME_SIZE - ofs)  /* don't overflow the frame */
00465             l = FRAME_SIZE - ofs;
00466          if (l > s->datalen - start)   /* don't overflow the source */
00467             l = s->datalen - start;
00468          bcopy(s->data + start, myframe + ofs, l*2);
00469          if (0)
00470             ast_log(LOG_WARNING, "send_sound sound %d/%d of %d into %d\n",
00471                 l_sampsent, l, s->samplen, ofs);
00472          l_sampsent += l;
00473       } else { /* end of samples, maybe some silence */
00474          static const short silence[FRAME_SIZE] = {0, };
00475 
00476          l += s->silencelen;
00477          if (l > 0) {
00478             if (l > FRAME_SIZE - ofs)
00479                l = FRAME_SIZE - ofs;
00480             bcopy(silence, myframe + ofs, l*2);
00481             l_sampsent += l;
00482          } else { /* silence is over, restart sound if loop */
00483             if (s->repeat == 0) {   /* last block */
00484                o->cursound = -1;
00485                o->nosound = 0;   /* allow audio data */
00486                if (ofs < FRAME_SIZE)   /* pad with silence */
00487                   bcopy(silence, myframe + ofs, (FRAME_SIZE - ofs)*2);
00488             }
00489             l_sampsent = 0;
00490          }
00491       }
00492    }
00493    l = soundcard_writeframe(o, myframe);
00494    if (l > 0)
00495       o->sampsent = l_sampsent;  /* update status */
00496 }
00497 
00498 static void *sound_thread(void *arg)
00499 {
00500    char ign[4096];
00501    struct chan_oss_pvt *o = (struct chan_oss_pvt *)arg;
00502 
00503    /*
00504     * Just in case, kick the driver by trying to read from it.
00505     * Ignore errors - this read is almost guaranteed to fail.
00506     */
00507    read(o->sounddev, ign, sizeof(ign));
00508    for (;;) {
00509       fd_set rfds, wfds;
00510       int maxfd, res;
00511 
00512       FD_ZERO(&rfds);
00513       FD_ZERO(&wfds);
00514       FD_SET(o->sndcmd[0], &rfds);
00515       maxfd = o->sndcmd[0];   /* pipe from the main process */
00516       if (o->cursound > -1 && o->sounddev < 0)
00517          setformat(o, O_RDWR);   /* need the channel, try to reopen */
00518       else if (o->cursound == -1 && o->owner == NULL)
00519          setformat(o, O_CLOSE);  /* can close */
00520       if (o->sounddev > -1) {
00521          if (!o->owner) { /* no one owns the audio, so we must drain it */
00522             FD_SET(o->sounddev, &rfds);
00523             maxfd = MAX(o->sounddev, maxfd);
00524          }
00525          if (o->cursound > -1) {
00526             FD_SET(o->sounddev, &wfds);
00527             maxfd = MAX(o->sounddev, maxfd);
00528          }
00529       }
00530       /* ast_select emulates linux behaviour in terms of timeout handling */
00531       res = ast_select(maxfd + 1, &rfds, &wfds, NULL, NULL);
00532       if (res < 1) {
00533          ast_log(LOG_WARNING, "select failed: %s\n", strerror(errno));
00534          sleep(1);
00535          continue;
00536       }
00537       if (FD_ISSET(o->sndcmd[0], &rfds)) {
00538          /* read which sound to play from the pipe */
00539          int i, what = -1;
00540 
00541          read(o->sndcmd[0], &what, sizeof(what));
00542          for (i = 0; sounds[i].ind != -1; i++) {
00543             if (sounds[i].ind == what) {
00544                o->cursound = i;
00545                o->sampsent = 0;
00546                o->nosound = 1; /* block audio from pbx */
00547                break;
00548             }
00549          }
00550          if (sounds[i].ind == -1)
00551             ast_log(LOG_WARNING, "invalid sound index: %d\n", what);
00552       }
00553       if (o->sounddev > -1) {
00554          if (FD_ISSET(o->sounddev, &rfds)) /* read and ignore errors */
00555             read(o->sounddev, ign, sizeof(ign));
00556          if (FD_ISSET(o->sounddev, &wfds))
00557             send_sound(o);
00558       }
00559    }
00560    return NULL; /* Never reached */
00561 }
00562 
00563 /*
00564  * reset and close the device if opened,
00565  * then open and initialize it in the desired mode,
00566  * trigger reads and writes so we can start using it.
00567  */
00568 static int setformat(struct chan_oss_pvt *o, int mode)
00569 {
00570    int fmt, desired, res, fd;
00571 
00572    if (o->sounddev >= 0) {
00573       ioctl(o->sounddev, SNDCTL_DSP_RESET, 0);
00574       close(o->sounddev);
00575       o->duplex = M_UNSET;
00576       o->sounddev = -1;
00577    }
00578    if (mode == O_CLOSE) /* we are done */
00579       return 0;
00580    if (ast_tvdiff_ms(ast_tvnow(), o->lastopen) < 1000)
00581       return -1;  /* don't open too often */
00582    o->lastopen = ast_tvnow();
00583    fd = o->sounddev = open(o->device, mode |O_NONBLOCK);
00584    if (fd < 0) {
00585       ast_log(LOG_WARNING, "Unable to re-open DSP device %s: %s\n",
00586           o->device, strerror(errno));
00587       return -1;
00588    }
00589    if (o->owner)
00590       o->owner->fds[0] = fd;
00591 
00592 #if __BYTE_ORDER == __LITTLE_ENDIAN
00593    fmt = AFMT_S16_LE;
00594 #else
00595    fmt = AFMT_S16_BE;
00596 #endif
00597    res = ioctl(fd, SNDCTL_DSP_SETFMT, &fmt);
00598    if (res < 0) {
00599       ast_log(LOG_WARNING, "Unable to set format to 16-bit signed\n");
00600       return -1;
00601    }
00602    switch (mode) {
00603    case O_RDWR:
00604       res = ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0);
00605       /* Check to see if duplex set (FreeBSD Bug)*/
00606       res = ioctl(fd, SNDCTL_DSP_GETCAPS, &fmt);
00607       if (res == 0 && (fmt & DSP_CAP_DUPLEX)) {
00608          if (option_verbose > 1) 
00609             ast_verbose(VERBOSE_PREFIX_2 "Console is full duplex\n");
00610          o->duplex = M_FULL;
00611       };
00612       break;
00613    case O_WRONLY:
00614       o->duplex = M_WRITE;
00615       break;
00616    case O_RDONLY:
00617       o->duplex = M_READ;
00618       break;
00619    }
00620 
00621    fmt = 0;
00622    res = ioctl(fd, SNDCTL_DSP_STEREO, &fmt);
00623    if (res < 0) {
00624       ast_log(LOG_WARNING, "Failed to set audio device to mono\n");
00625       return -1;
00626    }
00627    fmt = desired = 8000; /* 8000 Hz desired */
00628    res = ioctl(fd, SNDCTL_DSP_SPEED, &fmt);
00629 
00630    if (res < 0) {
00631       ast_log(LOG_WARNING, "Failed to set audio device to mono\n");
00632       return -1;
00633    }
00634    if (fmt != desired) {
00635       if (!(o->warned & WARN_speed)) {
00636          ast_log(LOG_WARNING,
00637              "Requested %d Hz, got %d Hz -- sound may be choppy\n",
00638              desired, fmt);
00639          o->warned |= WARN_speed;
00640       }
00641    }
00642    /*
00643     * on Freebsd, SETFRAGMENT does not work very well on some cards.
00644     * Default to use 256 bytes, let the user override
00645     */
00646    if (o->frags) {
00647       fmt = o->frags;
00648       res = ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &fmt);
00649       if (res < 0) {
00650          if (!(o->warned & WARN_frag)) {
00651             ast_log(LOG_WARNING,
00652                "Unable to set fragment size -- sound may be choppy\n");
00653             o->warned |= WARN_frag;
00654          }
00655       }
00656    }
00657    /* on some cards, we need SNDCTL_DSP_SETTRIGGER to start outputting */
00658    res = PCM_ENABLE_INPUT | PCM_ENABLE_OUTPUT;
00659    res = ioctl(fd, SNDCTL_DSP_SETTRIGGER, &res);
00660    /* it may fail if we are in half duplex, never mind */
00661    return 0;
00662 }
00663 
00664 /*
00665  * some of the standard methods supported by channels.
00666  */
00667 static int oss_digit(struct ast_channel *c, char digit)
00668 {
00669    /* no better use for received digits than print them */
00670    ast_verbose( " << Console Received digit %c >> \n", digit);
00671    return 0;
00672 }
00673 
00674 static int oss_text(struct ast_channel *c, const char *text)
00675 {
00676    /* print received messages */
00677    ast_verbose( " << Console Received text %s >> \n", text);
00678    return 0;
00679 }
00680 
00681 /* Play ringtone 'x' on device 'o' */
00682 static void ring(struct chan_oss_pvt *o, int x)
00683 {
00684    write(o->sndcmd[1], &x, sizeof(x));
00685 }
00686 
00687 
00688 /*
00689  * handler for incoming calls. Either autoanswer, or start ringing
00690  */
00691 static int oss_call(struct ast_channel *c, char *dest, int timeout)
00692 {
00693    struct chan_oss_pvt *o = c->tech_pvt;
00694    struct ast_frame f = { 0, };
00695 
00696    ast_verbose(" << Call to '%s' on console from <%s><%s><%s> >>\n",
00697       dest, c->cid.cid_dnid, c->cid.cid_num, c->cid.cid_name);
00698    if (o->autoanswer) {
00699       ast_verbose( " << Auto-answered >> \n" );
00700       f.frametype = AST_FRAME_CONTROL;
00701       f.subclass = AST_CONTROL_ANSWER;
00702       ast_queue_frame(c, &f);
00703    } else {
00704       ast_verbose("<< Type 'answer' to answer, or use 'autoanswer' for future calls >> \n");
00705       f.frametype = AST_FRAME_CONTROL;
00706       f.subclass = AST_CONTROL_RINGING;
00707       ast_queue_frame(c, &f);
00708       ring(o, AST_CONTROL_RING);
00709    }
00710    return 0;
00711 }
00712 
00713 /*
00714  * remote side answered the phone
00715  */
00716 static int oss_answer(struct ast_channel *c)
00717 {
00718    struct chan_oss_pvt *o = c->tech_pvt;
00719 
00720    ast_verbose( " << Console call has been answered >> \n");
00721 #if 0
00722    /* play an answer tone (XXX do we really need it ?) */
00723    ring(o, AST_CONTROL_ANSWER);
00724 #endif
00725    ast_setstate(c, AST_STATE_UP);
00726    o->cursound = -1;
00727    o->nosound=0;
00728    return 0;
00729 }
00730 
00731 static int oss_hangup(struct ast_channel *c)
00732 {
00733    struct chan_oss_pvt *o = c->tech_pvt;
00734 
00735    o->cursound = -1;
00736    o->nosound = 0;
00737    c->tech_pvt = NULL;
00738    o->owner = NULL;
00739    ast_verbose( " << Hangup on console >> \n");
00740    ast_mutex_lock(&usecnt_lock); /* XXX not sure why */
00741    usecnt--;
00742    ast_mutex_unlock(&usecnt_lock);
00743    if (o->hookstate) {
00744       if (o->autoanswer || o->autohangup) {
00745          /* Assume auto-hangup too */
00746          o->hookstate = 0;
00747          setformat(o, O_CLOSE);
00748       } else {
00749          /* Make congestion noise */
00750          ring(o, AST_CONTROL_CONGESTION);
00751       }
00752    }
00753    return 0;
00754 }
00755 
00756 /* used for data coming from the network */
00757 static int oss_write(struct ast_channel *c, struct ast_frame *f)
00758 {
00759    int src;
00760    struct chan_oss_pvt *o = c->tech_pvt;
00761 
00762    /* Immediately return if no sound is enabled */
00763    if (o->nosound)
00764       return 0;
00765    /* Stop any currently playing sound */
00766    o->cursound = -1;
00767    /*
00768     * we could receive a block which is not a multiple of our
00769     * FRAME_SIZE, so buffer it locally and write to the device
00770     * in FRAME_SIZE chunks.
00771     * Keep the residue stored for future use.
00772     */
00773    src = 0; /* read position into f->data */
00774    while ( src < f->datalen ) {
00775       /* Compute spare room in the buffer */
00776       int l = sizeof(o->oss_write_buf) - o->oss_write_dst;
00777 
00778       if (f->datalen - src >= l) {  /* enough to fill a frame */
00779          memcpy(o->oss_write_buf + o->oss_write_dst,
00780             f->data + src, l);
00781          soundcard_writeframe(o, (short *)o->oss_write_buf);
00782          src += l;
00783          o->oss_write_dst = 0;
00784       } else { /* copy residue */
00785          l = f->datalen - src;
00786          memcpy(o->oss_write_buf + o->oss_write_dst,
00787             f->data + src, l);
00788          src += l;   /* but really, we are done */
00789          o->oss_write_dst += l;
00790       }
00791    }
00792    return 0;
00793 }
00794 
00795 static struct ast_frame *oss_read(struct ast_channel *c)
00796 {
00797    int res;
00798    struct chan_oss_pvt *o = c->tech_pvt;
00799    struct ast_frame *f = &o->read_f;
00800 
00801    /* prepare a NULL frame in case we don't have enough data to return */
00802    bzero(f, sizeof(struct ast_frame));
00803    f->frametype = AST_FRAME_NULL;
00804    f->src = o->type;
00805 
00806    res = read(o->sounddev, o->oss_read_buf + o->readpos,
00807    sizeof(o->oss_read_buf) - o->readpos);
00808    if (res < 0)   /* audio data not ready, return a NULL frame */
00809       return f;
00810 
00811    o->readpos += res;
00812    if (o->readpos < sizeof(o->oss_read_buf)) /* not enough samples */
00813       return f;
00814 
00815    if (o->mute)
00816       return f;
00817 
00818    o->readpos = AST_FRIENDLY_OFFSET;   /* reset read pointer for next frame */
00819    if (c->_state != AST_STATE_UP)   /* drop data if frame is not up */
00820       return f;
00821    /* ok we can build and deliver the frame to the caller */
00822    f->frametype = AST_FRAME_VOICE;
00823    f->subclass = AST_FORMAT_SLINEAR;
00824    f->samples = FRAME_SIZE;
00825    f->datalen = FRAME_SIZE * 2;
00826    f->data = o->oss_read_buf + AST_FRIENDLY_OFFSET;
00827    f->offset = AST_FRIENDLY_OFFSET;
00828    return f;
00829 }
00830 
00831 static int oss_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
00832 {
00833    struct chan_oss_pvt *o = newchan->tech_pvt;
00834    o->owner = newchan;
00835    return 0;
00836 }
00837 
00838 static int oss_indicate(struct ast_channel *c, int cond)
00839 {
00840    struct chan_oss_pvt *o = c->tech_pvt;
00841    int res;
00842 
00843    switch(cond) {
00844    case AST_CONTROL_BUSY:
00845    case AST_CONTROL_CONGESTION:
00846    case AST_CONTROL_RINGING:
00847       res = cond;
00848       break;
00849 
00850    case -1:
00851       o->cursound = -1;
00852       o->nosound = 0; /* when cursound is -1 nosound must be 0 */
00853       return 0;
00854 
00855    case AST_CONTROL_VIDUPDATE:
00856       res = -1;
00857       break;
00858    default:
00859       ast_log(LOG_WARNING,
00860           "Don't know how to display condition %d on %s\n",
00861           cond, c->name);
00862       return -1;
00863    }
00864    if (res > -1)
00865       ring(o, res);
00866    return 0;   
00867 }
00868 
00869 /*
00870  * allocate a new channel.
00871  */
00872 static struct ast_channel *oss_new(struct chan_oss_pvt *o,
00873    char *ext, char *ctx, int state)
00874 {
00875    struct ast_channel *c;
00876 
00877    c = ast_channel_alloc(1);
00878    if (c == NULL)
00879       return NULL;
00880    c->tech = &oss_tech;
00881    snprintf(c->name, sizeof(c->name), "OSS/%s", o->device + 5);
00882    c->type = o->type;
00883    c->fds[0] = o->sounddev; /* -1 if device closed, override later */
00884    c->nativeformats = AST_FORMAT_SLINEAR;
00885    c->readformat = AST_FORMAT_SLINEAR;
00886    c->writeformat = AST_FORMAT_SLINEAR;
00887    c->tech_pvt = o;
00888 
00889    if (!ast_strlen_zero(ctx))
00890       ast_copy_string(c->context, ctx, sizeof(c->context));
00891    if (!ast_strlen_zero(ext))
00892       ast_copy_string(c->exten, ext, sizeof(c->exten));
00893    if (!ast_strlen_zero(o->language))
00894       ast_copy_string(c->language, o->language, sizeof(c->language));
00895 
00896    o->owner = c;
00897    ast_setstate(c, state);
00898    ast_mutex_lock(&usecnt_lock);
00899    usecnt++;
00900    ast_mutex_unlock(&usecnt_lock);
00901    ast_update_use_count();
00902    if (state != AST_STATE_DOWN) {
00903       if (ast_pbx_start(c)) {
00904          ast_log(LOG_WARNING, "Unable to start PBX on %s\n", c->name);
00905          ast_hangup(c);
00906          o->owner = c = NULL;
00907          /* XXX what about the channel itself ? */
00908          /* XXX what about usecnt ? */
00909       }
00910    }
00911    return c;
00912 }
00913 
00914 static struct ast_channel *oss_request(const char *type,
00915    int format, void *data, int *cause)
00916 {
00917    struct ast_channel *c;
00918    struct chan_oss_pvt *o = find_desc(data);
00919 
00920    ast_log(LOG_WARNING, "oss_request ty <%s> data 0x%p <%s>\n",
00921       type, data, (char *)data);
00922    if (o == NULL) {
00923       ast_log(LOG_NOTICE, "Device %s not found\n", (char *)data);
00924       /* XXX we could default to 'dsp' perhaps ? */
00925       return NULL;
00926    }
00927    if ((format & AST_FORMAT_SLINEAR) == 0) {
00928       ast_log(LOG_NOTICE, "Format 0x%x unsupported\n", format);
00929       return NULL;
00930    }
00931    if (o->owner) {
00932       ast_log(LOG_NOTICE, "Already have a call (chan %p) on the OSS channel\n", o->owner);
00933       *cause = AST_CAUSE_BUSY;
00934       return NULL;
00935    }
00936    c= oss_new(o, NULL, NULL, AST_STATE_DOWN);
00937    if (c == NULL) {
00938       ast_log(LOG_WARNING, "Unable to create new OSS channel\n");
00939       return NULL;
00940    }
00941    return c;
00942 }
00943 
00944 static int console_autoanswer(int fd, int argc, char *argv[])
00945 {
00946    struct chan_oss_pvt *o = find_desc(oss_active);
00947 
00948    if (argc == 1) {
00949       ast_cli(fd, "Auto answer is %s.\n", o->autoanswer ? "on" : "off");
00950       return RESULT_SUCCESS;
00951    }
00952    if (argc != 2)
00953       return RESULT_SHOWUSAGE;
00954    if (o == NULL) {
00955       ast_log(LOG_WARNING, "Cannot find device %s (should not happen!)\n",
00956           oss_active);
00957       return RESULT_FAILURE;
00958    }
00959    if (!strcasecmp(argv[1], "on"))
00960       o->autoanswer = -1;
00961    else if (!strcasecmp(argv[1], "off"))
00962       o->autoanswer = 0;
00963    else
00964       return RESULT_SHOWUSAGE;
00965    return RESULT_SUCCESS;
00966 }
00967 
00968 static char *autoanswer_complete(char *line, char *word, int pos, int state)
00969 {
00970    int l = strlen(word);
00971 
00972    switch(state) {
00973    case 0:
00974       if (l && !strncasecmp(word, "on", MIN(l, 2)))
00975          return strdup("on");
00976    case 1:
00977       if (l && !strncasecmp(word, "off", MIN(l, 3)))
00978          return strdup("off");
00979    default:
00980       return NULL;
00981    }
00982    return NULL;
00983 }
00984 
00985 static char autoanswer_usage[] =
00986 "Usage: autoanswer [on|off]\n"
00987 "       Enables or disables autoanswer feature.  If used without\n"
00988 "       argument, displays the current on/off status of autoanswer.\n"
00989 "       The default value of autoanswer is in 'oss.conf'.\n";
00990 
00991 /*
00992  * answer command from the console
00993  */
00994 static int console_answer(int fd, int argc, char *argv[])
00995 {
00996    struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
00997    struct chan_oss_pvt *o = find_desc(oss_active);
00998 
00999    if (argc != 1)
01000       return RESULT_SHOWUSAGE;
01001    if (!o->owner) {
01002       ast_cli(fd, "No one is calling us\n");
01003       return RESULT_FAILURE;
01004    }
01005    o->hookstate = 1;
01006    o->cursound = -1;
01007    o->nosound = 0;
01008    ast_queue_frame(o->owner, &f);
01009 #if 0
01010    /* XXX do we really need it ? considering we shut down immediately... */
01011    ring(o, AST_CONTROL_ANSWER);
01012 #endif
01013    return RESULT_SUCCESS;
01014 }
01015 
01016 static char sendtext_usage[] =
01017 "Usage: send text <message>\n"
01018 "       Sends a text message for display on the remote terminal.\n";
01019 
01020 /*
01021  * concatenate all arguments into a single string
01022  */
01023 static int console_sendtext(int fd, int argc, char *argv[])
01024 {
01025    struct chan_oss_pvt *o = find_desc(oss_active);
01026    int tmparg = 2;
01027    char text2send[TEXT_SIZE] = "";
01028    struct ast_frame f = { 0, };
01029 
01030    if (argc < 2)
01031       return RESULT_SHOWUSAGE;
01032    if (!o->owner) {
01033       ast_cli(fd, "Not in a call\n");
01034       return RESULT_FAILURE;
01035    }
01036    while (tmparg < argc) {
01037       strncat(text2send, argv[tmparg++],
01038          sizeof(text2send) - strlen(text2send) - 1);
01039       strncat(text2send, " ",
01040          sizeof(text2send) - strlen(text2send) - 1);
01041    }
01042    if (!ast_strlen_zero(text2send)) {
01043       text2send[strlen(text2send) - 1] = '\n';
01044       f.frametype = AST_FRAME_TEXT;
01045       f.subclass = 0;
01046       f.data = text2send;
01047       f.datalen = strlen(text2send);
01048       ast_queue_frame(o->owner, &f);
01049    }
01050    return RESULT_SUCCESS;
01051 }
01052 
01053 static char answer_usage[] =
01054 "Usage: answer\n"
01055 "       Answers an incoming call on the console (OSS) channel.\n";
01056 
01057 static int console_hangup(int fd, int argc, char *argv[])
01058 {
01059    struct chan_oss_pvt *o = find_desc(oss_active);
01060 
01061    if (argc != 1)
01062       return RESULT_SHOWUSAGE;
01063    o->cursound = -1;
01064    o->nosound = 0;
01065    if (!o->owner && !o->hookstate) { /* XXX maybe only one ? */
01066       ast_cli(fd, "No call to hang up\n");
01067       return RESULT_FAILURE;
01068    }
01069    o->hookstate = 0;
01070    if (o->owner)
01071       ast_queue_hangup(o->owner);
01072    setformat(o, O_CLOSE);
01073    return RESULT_SUCCESS;
01074 }
01075 
01076 static char hangup_usage[] =
01077 "Usage: hangup\n"
01078 "       Hangs up any call currently placed on the console.\n";
01079 
01080 
01081 static int console_flash(int fd, int argc, char *argv[])
01082 {
01083    struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_FLASH };
01084    struct chan_oss_pvt *o = find_desc(oss_active);
01085 
01086    if (argc != 1)
01087       return RESULT_SHOWUSAGE;
01088    o->cursound = -1;
01089    o->nosound = 0; /* when cursound is -1 nosound must be 0 */
01090    if (!o->owner) { /* XXX maybe !o->hookstate too ? */
01091       ast_cli(fd, "No call to flash\n");
01092       return RESULT_FAILURE;
01093    }
01094    o->hookstate = 0;
01095    if (o->owner) /* XXX must be true, right ? */
01096       ast_queue_frame(o->owner, &f);
01097    return RESULT_SUCCESS;
01098 }
01099 
01100 
01101 static char flash_usage[] =
01102 "Usage: flash\n"
01103 "       Flashes the call currently placed on the console.\n";
01104 
01105 
01106 
01107 static int console_dial(int fd, int argc, char *argv[])
01108 {
01109    char *s = NULL, *mye = NULL, *myc = NULL;
01110    struct chan_oss_pvt *o = find_desc(oss_active);
01111 
01112    if (argc != 1 && argc != 2)
01113       return RESULT_SHOWUSAGE;
01114    if (o->owner) {   /* already in a call */
01115       int i;
01116       struct ast_frame f = { AST_FRAME_DTMF, 0 };
01117 
01118       if (argc == 1) {  /* argument is mandatory here */
01119          ast_cli(fd, "Already in a call. You can only dial digits until you hangup.\n");
01120          return RESULT_FAILURE;
01121       }
01122       s = argv[1];
01123       /* send the string one char at a time */
01124       for (i=0; i<strlen(s); i++) {
01125          f.subclass = s[i];
01126          ast_queue_frame(o->owner, &f);
01127       }
01128       return RESULT_SUCCESS;
01129    }
01130    /* if we have an argument split it into extension and context */
01131    if (argc == 2)
01132       s = ast_ext_ctx(argv[1], &mye, &myc);
01133    /* supply default values if needed */
01134    if (mye == NULL)
01135       mye = o->ext;
01136    if (myc == NULL)
01137       myc = o->ctx;
01138    if (ast_exists_extension(NULL, myc, mye, 1, NULL)) {
01139       o->hookstate = 1;
01140       oss_new(o, mye, myc, AST_STATE_RINGING);
01141    } else
01142       ast_cli(fd, "No such extension '%s' in context '%s'\n", mye, myc);
01143    if (s)
01144       free(s);
01145    return RESULT_SUCCESS;
01146 }
01147 
01148 static char dial_usage[] =
01149 "Usage: dial [extension[@context]]\n"
01150 "       Dials a given extension (and context if specified)\n";
01151 
01152 static char mute_usage[] =
01153 "Usage: mute\nMutes the microphone\n";
01154 
01155 static char unmute_usage[] =
01156 "Usage: unmute\nUnmutes the microphone\n";
01157 
01158 static int console_mute(int fd, int argc, char *argv[])
01159 {
01160    struct chan_oss_pvt *o = find_desc(oss_active);
01161 
01162    if (argc != 1)
01163       return RESULT_SHOWUSAGE;
01164    o->mute = 1;
01165    return RESULT_SUCCESS;
01166 }
01167 
01168 static int console_unmute(int fd, int argc, char *argv[])
01169 {
01170    struct chan_oss_pvt *o = find_desc(oss_active);
01171 
01172    if (argc != 1)
01173       return RESULT_SHOWUSAGE;
01174    o->mute = 0;
01175    return RESULT_SUCCESS;
01176 }
01177 
01178 static int console_transfer(int fd, int argc, char *argv[])
01179 {
01180    struct chan_oss_pvt *o = find_desc(oss_active);
01181    struct ast_channel *b = NULL;
01182    char *tmp, *ext, *ctx;
01183 
01184    if (argc != 2)
01185       return RESULT_SHOWUSAGE;
01186    if (o == NULL)
01187       return RESULT_FAILURE;
01188    if (o->owner ==NULL || (b = ast_bridged_channel(o->owner)) == NULL) {
01189       ast_cli(fd, "There is no call to transfer\n");
01190       return RESULT_SUCCESS;
01191    }
01192 
01193    tmp = ast_ext_ctx(argv[1], &ext, &ctx);
01194    if (ctx == NULL)     /* supply default context if needed */
01195       ctx = o->owner->context;
01196    if (!ast_exists_extension(b, ctx, ext, 1, b->cid.cid_num))
01197       ast_cli(fd, "No such extension exists\n");
01198    else {
01199       ast_cli(fd, "Whee, transferring %s to %s@%s.\n",
01200          b->name, ext, ctx);
01201       if (ast_async_goto(b, ctx, ext, 1))
01202          ast_cli(fd, "Failed to transfer :(\n");
01203    }
01204    if (tmp)
01205       free(tmp);
01206    return RESULT_SUCCESS;
01207 }
01208 
01209 static char transfer_usage[] =
01210 "Usage: transfer <extension>[@context]\n"
01211 "       Transfers the currently connected call to the given extension (and\n"
01212 "context if specified)\n";
01213 
01214 static char console_usage[] =
01215 "Usage: console [device]\n"
01216 "       If used without a parameter, displays which device is the current\n"
01217 "console.  If a device is specified, the console sound device is changed to\n"
01218 "the device specified.\n";
01219 
01220 static int console_active(int fd, int argc, char *argv[])
01221 {
01222    if (argc == 1)
01223       ast_cli(fd, "active console is [%s]\n", oss_active);
01224    else if (argc != 2)
01225       return RESULT_SHOWUSAGE;
01226    else {
01227       struct chan_oss_pvt *o;
01228       if (strcmp(argv[1], "show") == 0) {
01229          for (o = oss_default.next; o ; o = o->next)
01230              ast_cli(fd, "device [%s] exists\n", o->name);
01231          return RESULT_SUCCESS;
01232       }
01233       o = find_desc(argv[1]);
01234       if (o == NULL)
01235          ast_cli(fd, "No device [%s] exists\n", argv[1]);
01236       else
01237          oss_active = o->name;
01238    }
01239    return RESULT_SUCCESS;
01240 }
01241 
01242 static struct ast_cli_entry myclis[] = {
01243    { { "answer", NULL }, console_answer, "Answer an incoming console call", answer_usage },
01244    { { "hangup", NULL }, console_hangup, "Hangup a call on the console", hangup_usage },
01245    { { "flash", NULL }, console_flash, "Flash a call on the console", flash_usage },
01246    { { "dial", NULL }, console_dial, "Dial an extension on the console", dial_usage },
01247    { { "mute", NULL }, console_mute, "Disable mic input", mute_usage },
01248    { { "unmute", NULL }, console_unmute, "Enable mic input", unmute_usage },
01249    { { "transfer", NULL }, console_transfer, "Transfer a call to a different extension", transfer_usage },
01250    { { "send", "text", NULL }, console_sendtext, "Send text to the remote device", sendtext_usage },
01251    { { "autoanswer", NULL }, console_autoanswer, "Sets/displays autoanswer", autoanswer_usage, autoanswer_complete },
01252    { { "console", NULL }, console_active, "Sets/displays active console", console_usage },
01253 };
01254 
01255 /*
01256  * store the mixer argument from the config file, filtering possibly
01257  * invalid or dangerous values (the string is used as argument for
01258  * system("mixer %s")
01259  */
01260 static void store_mixer(struct chan_oss_pvt *o, char *s)
01261 {
01262    int i;
01263 
01264    for (i=0; i < strlen(s); i++) {
01265       if (!isalnum(s[i]) && index(" \t-/", s[i]) == NULL) {
01266          ast_log(LOG_WARNING,
01267             "Suspect char %c in mixer cmd, ignoring:\n\t%s\n", s[i], s);
01268          return;
01269       }
01270    }
01271    if (o->mixer_cmd)
01272       free(o->mixer_cmd);
01273    o->mixer_cmd = strdup(s);
01274    ast_log(LOG_WARNING, "setting mixer %s\n", s);
01275 }
01276 
01277 /*
01278  * grab fields from the config file, init the descriptor and open the device.
01279  */
01280 static struct chan_oss_pvt * store_config(struct ast_config *cfg, char *ctg)
01281 {
01282    struct ast_variable *v;
01283    struct chan_oss_pvt *o;
01284 
01285    if (ctg == NULL) {
01286       o = &oss_default;
01287       ctg = "general";
01288    } else {
01289       o = (struct chan_oss_pvt *)malloc(sizeof *o);
01290       if (o == NULL)    /* fail */
01291          return NULL;
01292       *o = oss_default;
01293       /* "general" is also the default thing */
01294       if (strcmp(ctg, "general") == 0) {
01295          o->name = strdup("dsp");
01296          oss_active = o->name;
01297          goto openit;
01298       }
01299       o->name = strdup(ctg);
01300    }
01301 
01302    o->lastopen = ast_tvnow(); /* don't leave it 0 or tvdiff may wrap */
01303    /* fill other fields from configuration */
01304    for (v = ast_variable_browse(cfg, ctg);v; v=v->next) {
01305       M_START(v->name, v->value);
01306 
01307       M_BOOL("autoanswer", o->autoanswer)
01308       M_BOOL("autohangup", o->autohangup)
01309       M_BOOL("overridecontext", o->overridecontext)
01310       M_STR("device", o->device)
01311       M_UINT("frags", o->frags)
01312       M_UINT("debug", oss_debug)
01313       M_UINT("queuesize", o->queuesize)
01314       M_STR("context", o->ctx)
01315       M_STR("language", o->language)
01316       M_STR("extension", o->ext)
01317       M_F("mixer", store_mixer(o, v->value))
01318       M_END(;);
01319    }
01320    if (ast_strlen_zero(o->device))
01321       ast_copy_string(o->device, DEV_DSP, sizeof(o->device));
01322    if (o->mixer_cmd) {
01323       char *cmd;
01324 
01325       asprintf(&cmd, "mixer %s", o->mixer_cmd);
01326       ast_log(LOG_WARNING, "running [%s]\n", cmd);
01327       system(cmd);
01328       free(cmd);
01329    }
01330    if (o == &oss_default)  /* we are done with the default */
01331       return NULL;
01332 
01333 openit:
01334 #if TRYOPEN
01335    if (setformat(o, O_RDWR) < 0) {  /* open device */
01336       if (option_verbose > 0) {
01337          ast_verbose(VERBOSE_PREFIX_2 "Device %s not detected\n", ctg);
01338          ast_verbose(VERBOSE_PREFIX_2 "Turn off OSS support by adding "
01339              "'noload=chan_oss.so' in /etc/asterisk/modules.conf\n");
01340       }
01341       goto error;
01342    }
01343    if (o->duplex != M_FULL)
01344       ast_log(LOG_WARNING, "XXX I don't work right with non "
01345          "full-duplex sound cards XXX\n");
01346 #endif /* TRYOPEN */
01347    if (pipe(o->sndcmd) != 0) {
01348       ast_log(LOG_ERROR, "Unable to create pipe\n");
01349       goto error;
01350    }
01351    ast_pthread_create(&o->sthread, NULL, sound_thread, o);
01352    /* link into list of devices */
01353    if (o != &oss_default) {
01354       o->next = oss_default.next;
01355       oss_default.next = o;
01356    }
01357    return o;
01358 
01359 error:
01360    if (o != &oss_default)
01361       free(o);
01362    return NULL;
01363 }
01364 
01365 int load_module(void)
01366 {
01367    int i;
01368    struct ast_config *cfg;
01369 
01370    /* load config file */
01371    cfg = ast_config_load(config);
01372    if (cfg != NULL) {
01373       char *ctg = NULL; /* first pass is 'general' */
01374 
01375       do {
01376          store_config(cfg, ctg);
01377       } while ( (ctg = ast_category_browse(cfg, ctg)) != NULL);
01378       ast_config_destroy(cfg);
01379    } else {
01380        ast_log(LOG_NOTICE, "Unable to load config oss.conf\n");
01381        return -1;
01382    }
01383    if (find_desc(oss_active) == NULL) {
01384       ast_log(LOG_NOTICE, "Device %s not found\n", oss_active);
01385       /* XXX we could default to 'dsp' perhaps ? */
01386       /* XXX should cleanup allocated memory etc. */
01387       return -1;
01388    }
01389    i = ast_channel_register(&oss_tech);
01390    if (i < 0) {
01391       ast_log(LOG_ERROR, "Unable to register channel class '%s'\n",
01392          oss_default.type);
01393       /* XXX should cleanup allocated memory etc. */
01394       return -1;
01395    }
01396    ast_cli_register_multiple(myclis, sizeof(myclis)/sizeof(struct ast_cli_entry));
01397    return 0;
01398 }
01399 
01400 
01401 int unload_module()
01402 {
01403    struct chan_oss_pvt *o;
01404 
01405    ast_channel_unregister(&oss_tech);
01406    ast_cli_unregister_multiple(myclis,
01407       sizeof(myclis)/sizeof(struct ast_cli_entry));
01408 
01409    for (o = oss_default.next; o ; o = o->next) {
01410       close(o->sounddev);
01411       if (o->sndcmd[0] > 0) {
01412          close(o->sndcmd[0]);
01413          close(o->sndcmd[1]);
01414       }
01415       if (o->owner)
01416          ast_softhangup(o->owner, AST_SOFTHANGUP_APPUNLOAD);
01417       if (o->owner) /* XXX how ??? */
01418          return -1;
01419       /* XXX what about the thread ? */
01420       /* XXX what about the memory allocated ? */
01421    }
01422    return 0;
01423 }
01424 
01425 char *description()
01426 {
01427    return (char *)oss_tech.description;
01428 }
01429 
01430 int usecount()
01431 {
01432    return usecnt;
01433 }
01434 
01435 char *key()
01436 {
01437    return ASTERISK_GPL_KEY;
01438 }

Generated on Wed Oct 28 15:47:51 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6