Asterisk.org: Developer Documentation (28 Oct 2009)

Wed Oct 28 15:47:51 2009

## Asterisk developer's documentation

# chan_oss_old.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  * See http://www.asterisk.org for more information about
    00009  * the Asterisk project. Please do not directly contact
    00010  * any of the maintainers of this project for assistance;
    00011  * the project provides a web site, mailing lists and IRC
    00012  * channels for your use.
    00013  *
    00014  * This program is free software, distributed under the terms of
    00015  * the GNU General Public License Version 2. See the LICENSE file
    00016  * at the top of the source tree.
    00017  */
    00018
    00019 /*
    00020  * Use /dev/dsp as a channel, and the console to command it :).
    00021  *
    00022  * The full-duplex "simulation" is pretty weak.  This is generally a
    00023  * VERY BADLY WRITTEN DRIVER so please don't use it as a model for
    00024  * writing a driver.
    00025  *
    00026  * \ingroup channel_drivers
    00027  */
    00028
    00029 #include <unistd.h>
    00030 #include <fcntl.h>
    00031 #include <errno.h>
    00032 #include <sys/ioctl.h>
    00033 #include <sys/time.h>
    00034 #include <string.h>
    00035 #include <stdlib.h>
    00036 #include <stdio.h>
    00037
    00038 #ifdef __linux
    00039 #include <linux/soundcard.h>
    00040 #elif defined(__FreeBSD__)
    00041 #include <sys/soundcard.h>
    00042 #else
    00043 #include <soundcard.h>
    00044 #endif
    00045
    00046 #include "asterisk.h"
    00047
    00048 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 7221 $")
    00049
    00050 #include "asterisk/lock.h"
    00051 #include "asterisk/frame.h"
    00052 #include "asterisk/logger.h"
    00053 #include "asterisk/channel.h"
    00054 #include "asterisk/module.h"
    00055 #include "asterisk/options.h"
    00056 #include "asterisk/pbx.h"
    00057 #include "asterisk/config.h"
    00058 #include "asterisk/cli.h"
    00059 #include "asterisk/utils.h"
    00060 #include "asterisk/causes.h"
    00061 #include "asterisk/endian.h"
    00062
    00063 #include "busy.h"
    00064 #include "ringtone.h"
    00065 #include "ring10.h"
    00066 #include "answer.h"
    00067
    00068 /* Which device to use */
    00069 #if defined( __OpenBSD__ ) || defined( __NetBSD__ )
    00070 #define DEV_DSP "/dev/audio"
    00071 #else
    00072 #define DEV_DSP "/dev/dsp"
    00073 #endif
    00074
    00075 /* Lets use 160 sample frames, just like GSM.  */
    00076 #define FRAME_SIZE 160
    00077
    00078 /* When you set the frame size, you have to come up with
    00079    the right buffer format as well. */
    00080 /* 5 64-byte frames = one frame */
    00081 #define BUFFER_FMT ((buffersize * 10) << 16) | (0x0006);
    00082
    00083 /* Don't switch between read/write modes faster than every 300 ms */
    00084 #define MIN_SWITCH_TIME 600
    00085
    00086 static struct timeval lasttime;
    00087
    00088 static int usecnt;
    00089 static int silencesuppression = 0;
    00090 static int silencethreshold = 1000;
    00091 static int playbackonly = 0;
    00092
    00093
    00094 AST_MUTEX_DEFINE_STATIC(usecnt_lock);
    00095
    00096 static const char type[] = "Console";
    00097 static const char desc[] = "OSS Console Channel Driver";
    00098 static const char tdesc[] = "OSS Console Channel Driver";
    00099 static const char config[] = "oss.conf";
    00100
    00101 static char context[AST_MAX_CONTEXT] = "default";
    00102 static char language[MAX_LANGUAGE] = "";
    00103 static char exten[AST_MAX_EXTENSION] = "s";
    00104
    00105 static int hookstate=0;
    00106
    00107 static short silence[FRAME_SIZE] = {0, };
    00108
    00109 struct sound {
    00110    int ind;
    00111    short *data;
    00112    int datalen;
    00113    int samplen;
    00114    int silencelen;
    00115    int repeat;
    00116 };
    00117
    00118 static struct sound sounds[] = {
    00119    { AST_CONTROL_RINGING, ringtone, sizeof(ringtone)/2, 16000, 32000, 1 },
    00120    { AST_CONTROL_BUSY, busy, sizeof(busy)/2, 4000, 4000, 1 },
    00121    { AST_CONTROL_CONGESTION, busy, sizeof(busy)/2, 2000, 2000, 1 },
    00122    { AST_CONTROL_RING, ring10, sizeof(ring10)/2, 16000, 32000, 1 },
    00123    { AST_CONTROL_ANSWER, answer, sizeof(answer)/2, 2200, 0, 0 },
    00124 };
    00125
    00126 /* Sound command pipe */
    00127 static int sndcmd[2];
    00128
    00129 static struct chan_oss_pvt {
    00130    /* We only have one OSS structure -- near sighted perhaps, but it
    00131       keeps this driver as simple as possible -- as it should be. */
    00132    struct ast_channel *owner;
    00133    char exten[AST_MAX_EXTENSION];
    00134    char context[AST_MAX_CONTEXT];
    00135 } oss;
    00136
    00137 static struct ast_channel *oss_request(const char *type, int format, void *data, int *cause);
    00138 static int oss_digit(struct ast_channel *c, char digit);
    00139 static int oss_text(struct ast_channel *c, const char *text);
    00140 static int oss_hangup(struct ast_channel *c);
    00141 static int oss_answer(struct ast_channel *c);
    00142 static struct ast_frame *oss_read(struct ast_channel *chan);
    00143 static int oss_call(struct ast_channel *c, char *dest, int timeout);
    00144 static int oss_write(struct ast_channel *chan, struct ast_frame *f);
    00145 static int oss_indicate(struct ast_channel *chan, int cond);
    00146 static int oss_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
    00147
    00148 static const struct ast_channel_tech oss_tech = {
    00149    .type = type,
    00150    .description = tdesc,
    00151    .capabilities = AST_FORMAT_SLINEAR,
    00152    .requester = oss_request,
    00153    .send_digit = oss_digit,
    00154    .send_text = oss_text,
    00155    .hangup = oss_hangup,
    00156    .answer = oss_answer,
    00157    .read = oss_read,
    00158    .call = oss_call,
    00159    .write = oss_write,
    00160    .indicate = oss_indicate,
    00161    .fixup = oss_fixup,
    00162 };
    00163
    00164 static int time_has_passed(void)
    00165 {
    00166    struct timeval tv;
    00167    int ms;
    00168    gettimeofday(&tv, NULL);
    00169    ms = (tv.tv_sec - lasttime.tv_sec) * 1000 +
    00170          (tv.tv_usec - lasttime.tv_usec) / 1000;
    00171    if (ms > MIN_SWITCH_TIME)
    00172       return -1;
    00173    return 0;
    00174 }
    00175
    00176 /* Number of buffers...  Each is FRAMESIZE/8 ms long.  For example
    00177    with 160 sample frames, and a buffer size of 3, we have a 60ms buffer,
    00178    usually plenty. */
    00179
    00180 static pthread_t sthread;
    00181
    00182 #define MAX_BUFFER_SIZE 100
    00183 static int buffersize = 3;
    00184
    00185 static int full_duplex = 0;
    00186
    00187 /* Are we reading or writing (simulated full duplex) */
    00188 static int readmode = 1;
    00189
    00190 /* File descriptor for sound device */
    00191 static int sounddev = -1;
    00192
    00193 static int autoanswer = 1;
    00194
    00195 #if 0
    00196 static int calc_loudness(short *frame)
    00197 {
    00198    int sum = 0;
    00199    int x;
    00200    for (x=0;x<FRAME_SIZE;x++) {
    00201       if (frame[x] < 0)
    00202          sum -= frame[x];
    00203       else
    00204          sum += frame[x];
    00205    }
    00206    sum = sum/FRAME_SIZE;
    00207    return sum;
    00208 }
    00209 #endif
    00210
    00211 static int cursound = -1;
    00212 static int sampsent = 0;
    00213 static int silencelen=0;
    00214 static int offset=0;
    00215 static int nosound=0;
    00216
    00217 static int send_sound(void)
    00218 {
    00219    short myframe[FRAME_SIZE];
    00220    int total = FRAME_SIZE;
    00221    short *frame = NULL;
    00222    int amt=0;
    00223    int res;
    00224    int myoff;
    00225    audio_buf_info abi;
    00226    if (cursound > -1) {
    00227       res = ioctl(sounddev, SNDCTL_DSP_GETOSPACE ,&abi);
    00228       if (res) {
    00229          ast_log(LOG_WARNING, "Unable to read output space\n");
    00230          return -1;
    00231       }
    00232       /* Calculate how many samples we can send, max */
    00233       if (total > (abi.fragments * abi.fragsize / 2))
    00234          total = abi.fragments * abi.fragsize / 2;
    00235       res = total;
    00236       if (sampsent < sounds[cursound].samplen) {
    00237          myoff=0;
    00238          while(total) {
    00239             amt = total;
    00240             if (amt > (sounds[cursound].datalen - offset))
    00241                amt = sounds[cursound].datalen - offset;
    00242             memcpy(myframe + myoff, sounds[cursound].data + offset, amt * 2);
    00243             total -= amt;
    00244             offset += amt;
    00245             sampsent += amt;
    00246             myoff += amt;
    00247             if (offset >= sounds[cursound].datalen)
    00248                offset = 0;
    00249          }
    00250          /* Set it up for silence */
    00251          if (sampsent >= sounds[cursound].samplen)
    00252             silencelen = sounds[cursound].silencelen;
    00253          frame = myframe;
    00254       } else {
    00255          if (silencelen > 0) {
    00256             frame = silence;
    00257             silencelen -= res;
    00258          } else {
    00259             if (sounds[cursound].repeat) {
    00260                /* Start over */
    00261                sampsent = 0;
    00262                offset = 0;
    00263             } else {
    00264                cursound = -1;
    00265                nosound = 0;
    00266             }
    00267          }
    00268       }
    00269       if (frame)
    00270          res = write(sounddev, frame, res * 2);
    00271       if (res > 0)
    00272          return 0;
    00273       return res;
    00274    }
    00275    return 0;
    00276 }
    00277
    00278 static void *sound_thread(void *unused)
    00279 {
    00280    fd_set rfds;
    00281    fd_set wfds;
    00282    int max;
    00283    int res;
    00284    char ign[4096];
    00285    if (read(sounddev, ign, sizeof(sounddev)) < 0)
    00286       ast_log(LOG_WARNING, "Read error on sound device: %s\n", strerror(errno));
    00287    for(;;) {
    00288       FD_ZERO(&rfds);
    00289       FD_ZERO(&wfds);
    00290       max = sndcmd[0];
    00291       FD_SET(sndcmd[0], &rfds);
    00292       if (!oss.owner) {
    00293          FD_SET(sounddev, &rfds);
    00294          if (sounddev > max)
    00295             max = sounddev;
    00296       }
    00297       if (cursound > -1) {
    00298          FD_SET(sounddev, &wfds);
    00299          if (sounddev > max)
    00300             max = sounddev;
    00301       }
    00302       res = ast_select(max + 1, &rfds, &wfds, NULL, NULL);
    00303       if (res < 1) {
    00304          ast_log(LOG_WARNING, "select failed: %s\n", strerror(errno));
    00305          continue;
    00306       }
    00307       if (FD_ISSET(sndcmd[0], &rfds)) {
    00308          read(sndcmd[0], &cursound, sizeof(cursound));
    00309          silencelen = 0;
    00310          offset = 0;
    00311          sampsent = 0;
    00312       }
    00313       if (FD_ISSET(sounddev, &rfds)) {
    00314          /* Ignore read */
    00315          if (read(sounddev, ign, sizeof(ign)) < 0)
    00316             ast_log(LOG_WARNING, "Read error on sound device: %s\n", strerror(errno));
    00317       }
    00318       if (FD_ISSET(sounddev, &wfds))
    00319          if (send_sound())
    00320             ast_log(LOG_WARNING, "Failed to write sound\n");
    00321    }
    00322    /* Never reached */
    00323    return NULL;
    00324 }
    00325
    00326 #if 0
    00327 static int silence_suppress(short *buf)
    00328 {
    00329 #define SILBUF 3
    00330    int loudness;
    00331    static int silentframes = 0;
    00332    static char silbuf[FRAME_SIZE * 2 * SILBUF];
    00333    static int silbufcnt=0;
    00334    if (!silencesuppression)
    00335       return 0;
    00336    loudness = calc_loudness((short *)(buf));
    00337    if (option_debug)
    00338       ast_log(LOG_DEBUG, "loudness is %d\n", loudness);
    00339    if (loudness < silencethreshold) {
    00340       silentframes++;
    00341       silbufcnt++;
    00342       /* Keep track of the last few bits of silence so we can play
    00343          them as lead-in when the time is right */
    00344       if (silbufcnt >= SILBUF) {
    00345          /* Make way for more buffer */
    00346          memmove(silbuf, silbuf + FRAME_SIZE * 2, FRAME_SIZE * 2 * (SILBUF - 1));
    00347          silbufcnt--;
    00348       }
    00349       memcpy(silbuf + FRAME_SIZE * 2 * silbufcnt, buf, FRAME_SIZE * 2);
    00350       if (silentframes > 10) {
    00351          /* We've had plenty of silence, so compress it now */
    00352          return 1;
    00353       }
    00354    } else {
    00355       silentframes=0;
    00356       /* Write any buffered silence we have, it may have something
    00357          important */
    00358       if (silbufcnt) {
    00359          write(sounddev, silbuf, silbufcnt * FRAME_SIZE);
    00360          silbufcnt = 0;
    00361       }
    00362    }
    00363    return 0;
    00364 }
    00365 #endif
    00366
    00367 static int setformat(void)
    00368 {
    00369    int fmt, desired, res, fd = sounddev;
    00370    static int warnedalready = 0;
    00371    static int warnedalready2 = 0;
    00372
    00373 #if __BYTE_ORDER == __LITTLE_ENDIAN
    00374    fmt = AFMT_S16_LE;
    00375 #else
    00376    fmt = AFMT_S16_BE;
    00377 #endif
    00378
    00379    res = ioctl(fd, SNDCTL_DSP_SETFMT, &fmt);
    00380    if (res < 0) {
    00381       ast_log(LOG_WARNING, "Unable to set format to 16-bit signed\n");
    00382       return -1;
    00383    }
    00384    res = ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0);
    00385
    00386    /* Check to see if duplex set (FreeBSD Bug)*/
    00387    res = ioctl(fd, SNDCTL_DSP_GETCAPS, &fmt);
    00388
    00389    if ((fmt & DSP_CAP_DUPLEX) && !res) {
    00390       if (option_verbose > 1)
    00391          ast_verbose(VERBOSE_PREFIX_2 "Console is full duplex\n");
    00392       full_duplex = -1;
    00393    }
    00394    fmt = 0;
    00395    res = ioctl(fd, SNDCTL_DSP_STEREO, &fmt);
    00396    if (res < 0) {
    00397       ast_log(LOG_WARNING, "Failed to set audio device to mono\n");
    00398       return -1;
    00399    }
    00400    /* 8000 Hz desired */
    00401    desired = 8000;
    00402    fmt = desired;
    00403    res = ioctl(fd, SNDCTL_DSP_SPEED, &fmt);
    00404    if (res < 0) {
    00405       ast_log(LOG_WARNING, "Failed to set audio device to mono\n");
    00406       return -1;
    00407    }
    00408    if (fmt != desired) {
    00409       if (!warnedalready++)
    00410          ast_log(LOG_WARNING, "Requested %d Hz, got %d Hz -- sound may be choppy\n", desired, fmt);
    00411    }
    00412 #if 1
    00413    fmt = BUFFER_FMT;
    00414    res = ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &fmt);
    00415    if (res < 0) {
    00416       if (!warnedalready2++)
    00417          ast_log(LOG_WARNING, "Unable to set fragment size -- sound may be choppy\n");
    00418    }
    00419 #endif
    00420    return 0;
    00421 }
    00422
    00423 static int soundcard_setoutput(int force)
    00424 {
    00425    /* Make sure the soundcard is in output mode.  */
    00426    int fd = sounddev;
    00427    if (full_duplex || (!readmode && !force))
    00428       return 0;
    00429    readmode = 0;
    00430    if (force || time_has_passed()) {
    00431       ioctl(sounddev, SNDCTL_DSP_RESET, 0);
    00432       /* Keep the same fd reserved by closing the sound device and copying stdin at the same
    00433          time. */
    00434       /* dup2(0, sound); */
    00435       close(sounddev);
    00436       fd = open(DEV_DSP, O_WRONLY |O_NONBLOCK);
    00437       if (fd < 0) {
    00438          ast_log(LOG_WARNING, "Unable to re-open DSP device: %s\n", strerror(errno));
    00439          return -1;
    00440       }
    00441       /* dup2 will close the original and make fd be sound */
    00442       if (dup2(fd, sounddev) < 0) {
    00443          ast_log(LOG_WARNING, "dup2() failed: %s\n", strerror(errno));
    00444          return -1;
    00445       }
    00446       if (setformat()) {
    00447          return -1;
    00448       }
    00449       return 0;
    00450    }
    00451    return 1;
    00452 }
    00453
    00454 static int soundcard_setinput(int force)
    00455 {
    00456    int fd = sounddev;
    00457    if (full_duplex || (readmode && !force))
    00458       return 0;
    00459    readmode = -1;
    00460    if (force || time_has_passed()) {
    00461       ioctl(sounddev, SNDCTL_DSP_RESET, 0);
    00462       close(sounddev);
    00463       /* dup2(0, sound); */
    00464       fd = open(DEV_DSP, O_RDONLY | O_NONBLOCK);
    00465       if (fd < 0) {
    00466          ast_log(LOG_WARNING, "Unable to re-open DSP device: %s\n", strerror(errno));
    00467          return -1;
    00468       }
    00469       /* dup2 will close the original and make fd be sound */
    00470       if (dup2(fd, sounddev) < 0) {
    00471          ast_log(LOG_WARNING, "dup2() failed: %s\n", strerror(errno));
    00472          return -1;
    00473       }
    00474       if (setformat()) {
    00475          return -1;
    00476       }
    00477       return 0;
    00478    }
    00479    return 1;
    00480 }
    00481
    00482 static int soundcard_init(void)
    00483 {
    00484    /* Assume it's full duplex for starters */
    00485    int fd = open(DEV_DSP,  O_RDWR | O_NONBLOCK);
    00486    if (fd < 0) {
    00487       ast_log(LOG_WARNING, "Unable to open %s: %s\n", DEV_DSP, strerror(errno));
    00488       return fd;
    00489    }
    00490    gettimeofday(&lasttime, NULL);
    00491    sounddev = fd;
    00492    setformat();
    00493    if (!full_duplex)
    00494       soundcard_setinput(1);
    00495    return sounddev;
    00496 }
    00497
    00498 static int oss_digit(struct ast_channel *c, char digit)
    00499 {
    00500    ast_verbose( " << Console Received digit %c >> \n", digit);
    00501    return 0;
    00502 }
    00503
    00504 static int oss_text(struct ast_channel *c, const char *text)
    00505 {
    00506    ast_verbose( " << Console Received text %s >> \n", text);
    00507    return 0;
    00508 }
    00509
    00510 static int oss_call(struct ast_channel *c, char *dest, int timeout)
    00511 {
    00512    int res = 3;
    00513    struct ast_frame f = { 0, };
    00514    ast_verbose( " << Call placed to '%s' on console >> \n", dest);
    00515    if (autoanswer) {
    00516       ast_verbose( " << Auto-answered >> \n" );
    00517       f.frametype = AST_FRAME_CONTROL;
    00518       f.subclass = AST_CONTROL_ANSWER;
    00519       ast_queue_frame(c, &f);
    00520    } else {
    00521       nosound = 1;
    00522       ast_verbose( " << Type 'answer' to answer, or use 'autoanswer' for future calls >> \n");
    00523       f.frametype = AST_FRAME_CONTROL;
    00524       f.subclass = AST_CONTROL_RINGING;
    00525       ast_queue_frame(c, &f);
    00526       write(sndcmd[1], &res, sizeof(res));
    00527    }
    00528    return 0;
    00529 }
    00530
    00531 static void answer_sound(void)
    00532 {
    00533    int res;
    00534    nosound = 1;
    00535    res = 4;
    00536    write(sndcmd[1], &res, sizeof(res));
    00537
    00538 }
    00539
    00540 static int oss_answer(struct ast_channel *c)
    00541 {
    00542    ast_verbose( " << Console call has been answered >> \n");
    00543    answer_sound();
    00544    ast_setstate(c, AST_STATE_UP);
    00545    cursound = -1;
    00546    nosound=0;
    00547    return 0;
    00548 }
    00549
    00550 static int oss_hangup(struct ast_channel *c)
    00551 {
    00552    int res = 0;
    00553    cursound = -1;
    00554    c->tech_pvt = NULL;
    00555    oss.owner = NULL;
    00556    ast_verbose( " << Hangup on console >> \n");
    00557    ast_mutex_lock(&usecnt_lock);
    00558    usecnt--;
    00559    ast_mutex_unlock(&usecnt_lock);
    00560    if (hookstate) {
    00561       if (autoanswer) {
    00562          /* Assume auto-hangup too */
    00563          hookstate = 0;
    00564       } else {
    00565          /* Make congestion noise */
    00566          res = 2;
    00567          write(sndcmd[1], &res, sizeof(res));
    00568          hookstate = 0;
    00569       }
    00570    }
    00571    return 0;
    00572 }
    00573
    00574 static int soundcard_writeframe(short *data)
    00575 {
    00576    /* Write an exactly FRAME_SIZE sized of frame */
    00577    static int bufcnt = 0;
    00578    static short buffer[FRAME_SIZE * MAX_BUFFER_SIZE * 5];
    00579    struct audio_buf_info info;
    00580    int res;
    00581    int fd = sounddev;
    00582    static int warned=0;
    00583    if (ioctl(fd, SNDCTL_DSP_GETOSPACE, &info)) {
    00584       if (!warned)
    00585          ast_log(LOG_WARNING, "Error reading output space\n");
    00586       bufcnt = buffersize;
    00587       warned++;
    00588    }
    00589    if ((info.fragments >= buffersize * 5) && (bufcnt == buffersize)) {
    00590       /* We've run out of stuff, buffer again */
    00591       bufcnt = 0;
    00592    }
    00593    if (bufcnt == buffersize) {
    00594       /* Write sample immediately */
    00595       res = write(fd, ((void *)data), FRAME_SIZE * 2);
    00596    } else {
    00597       /* Copy the data into our buffer */
    00598       res = FRAME_SIZE * 2;
    00599       memcpy(buffer + (bufcnt * FRAME_SIZE), data, FRAME_SIZE * 2);
    00600       bufcnt++;
    00601       if (bufcnt == buffersize) {
    00602          res = write(fd, ((void *)buffer), FRAME_SIZE * 2 * buffersize);
    00603       }
    00604    }
    00605    return res;
    00606 }
    00607
    00608
    00609 static int oss_write(struct ast_channel *chan, struct ast_frame *f)
    00610 {
    00611    int res;
    00612    static char sizbuf[8000];
    00613    static int sizpos = 0;
    00614    int len = sizpos;
    00615    int pos;
    00616    /* Immediately return if no sound is enabled */
    00617    if (nosound)
    00618       return 0;
    00619    /* Stop any currently playing sound */
    00620    cursound = -1;
    00621    if (!full_duplex && !playbackonly) {
    00622       /* If we're half duplex, we have to switch to read mode
    00623          to honor immediate needs if necessary.  But if we are in play
    00624          back only mode, then we don't switch because the console
    00625          is only being used one way -- just to playback something. */
    00626       res = soundcard_setinput(1);
    00627       if (res < 0) {
    00628          ast_log(LOG_WARNING, "Unable to set device to input mode\n");
    00629          return -1;
    00630       }
    00631       return 0;
    00632    }
    00633    res = soundcard_setoutput(0);
    00634    if (res < 0) {
    00635       ast_log(LOG_WARNING, "Unable to set output device\n");
    00636       return -1;
    00637    } else if (res > 0) {
    00638       /* The device is still in read mode, and it's too soon to change it,
    00639          so just pretend we wrote it */
    00640       return 0;
    00641    }
    00642    /* We have to digest the frame in 160-byte portions */
    00643    if (f->datalen > sizeof(sizbuf) - sizpos) {
    00644       ast_log(LOG_WARNING, "Frame too large\n");
    00645       return -1;
    00646    }
    00647    memcpy(sizbuf + sizpos, f->data, f->datalen);
    00648    len += f->datalen;
    00649    pos = 0;
    00650    while(len - pos > FRAME_SIZE * 2) {
    00651       soundcard_writeframe((short *)(sizbuf + pos));
    00652       pos += FRAME_SIZE * 2;
    00653    }
    00654    if (len - pos)
    00655       memmove(sizbuf, sizbuf + pos, len - pos);
    00656    sizpos = len - pos;
    00657    return 0;
    00658 }
    00659
    00660 static struct ast_frame *oss_read(struct ast_channel *chan)
    00661 {
    00662    static struct ast_frame f;
    00663    static char buf[FRAME_SIZE * 2 + AST_FRIENDLY_OFFSET];
    00664    static int readpos = 0;
    00665    int res;
    00666
    00667 #if 0
    00668    ast_log(LOG_DEBUG, "oss_read()\n");
    00669 #endif
    00670
    00671    f.frametype = AST_FRAME_NULL;
    00672    f.subclass = 0;
    00673    f.samples = 0;
    00674    f.datalen = 0;
    00675    f.data = NULL;
    00676    f.offset = 0;
    00677    f.src = type;
    00678    f.mallocd = 0;
    00679    f.delivery.tv_sec = 0;
    00680    f.delivery.tv_usec = 0;
    00681
    00682    res = soundcard_setinput(0);
    00683    if (res < 0) {
    00684       ast_log(LOG_WARNING, "Unable to set input mode\n");
    00685       return NULL;
    00686    }
    00687    if (res > 0) {
    00688       /* Theoretically shouldn't happen, but anyway, return a NULL frame */
    00689       return &f;
    00690    }
    00691    res = read(sounddev, buf + AST_FRIENDLY_OFFSET + readpos, FRAME_SIZE * 2 - readpos);
    00692    if (res < 0) {
    00693       ast_log(LOG_WARNING, "Error reading from sound device (If you're running 'artsd' then kill it): %s\n", strerror(errno));
    00694 #if 0
    00695       CRASH;
    00696 #endif
    00697       return NULL;
    00698    }
    00699    readpos += res;
    00700
    00701    if (readpos >= FRAME_SIZE * 2) {
    00702       /* A real frame */
    00703       readpos = 0;
    00704       if (chan->_state != AST_STATE_UP) {
    00705          /* Don't transmit unless it's up */
    00706          return &f;
    00707       }
    00708       f.frametype = AST_FRAME_VOICE;
    00709       f.subclass = AST_FORMAT_SLINEAR;
    00710       f.samples = FRAME_SIZE;
    00711       f.datalen = FRAME_SIZE * 2;
    00712       f.data = buf + AST_FRIENDLY_OFFSET;
    00713       f.offset = AST_FRIENDLY_OFFSET;
    00714       f.src = type;
    00715       f.mallocd = 0;
    00716       f.delivery.tv_sec = 0;
    00717       f.delivery.tv_usec = 0;
    00718 #if 0
    00719       { static int fd = -1;
    00720         if (fd < 0)
    00721          fd = open("output.raw", O_RDWR | O_TRUNC | O_CREAT);
    00722         write(fd, f.data, f.datalen);
    00723       }
    00724 #endif
    00725    }
    00726    return &f;
    00727 }
    00728
    00729 static int oss_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
    00730 {
    00731    struct chan_oss_pvt *p = newchan->tech_pvt;
    00732    p->owner = newchan;
    00733    return 0;
    00734 }
    00735
    00736 static int oss_indicate(struct ast_channel *chan, int cond)
    00737 {
    00738    int res;
    00739    switch(cond) {
    00740    case AST_CONTROL_BUSY:
    00741       res = 1;
    00742       break;
    00743    case AST_CONTROL_CONGESTION:
    00744       res = 2;
    00745       break;
    00746    case AST_CONTROL_RINGING:
    00747       res = 0;
    00748       break;
    00749    case -1:
    00750       cursound = -1;
    00751       return 0;
    00752    default:
    00753       ast_log(LOG_WARNING, "Don't know how to display condition %d on %s\n", cond, chan->name);
    00754       return -1;
    00755    }
    00756    if (res > -1) {
    00757       write(sndcmd[1], &res, sizeof(res));
    00758    }
    00759    return 0;
    00760 }
    00761
    00762 static struct ast_channel *oss_new(struct chan_oss_pvt *p, int state)
    00763 {
    00764    struct ast_channel *tmp;
    00765    tmp = ast_channel_alloc(1);
    00766    if (tmp) {
    00767       tmp->tech = &oss_tech;
    00768       snprintf(tmp->name, sizeof(tmp->name), "OSS/%s", DEV_DSP + 5);
    00769       tmp->type = type;
    00770       tmp->fds[0] = sounddev;
    00771       tmp->nativeformats = AST_FORMAT_SLINEAR;
    00772       tmp->readformat = AST_FORMAT_SLINEAR;
    00773       tmp->writeformat = AST_FORMAT_SLINEAR;
    00774       tmp->tech_pvt = p;
    00775       if (!ast_strlen_zero(p->context))
    00776          strncpy(tmp->context, p->context, sizeof(tmp->context)-1);
    00777       if (!ast_strlen_zero(p->exten))
    00778          strncpy(tmp->exten, p->exten, sizeof(tmp->exten)-1);
    00779       if (!ast_strlen_zero(language))
    00780          strncpy(tmp->language, language, sizeof(tmp->language)-1);
    00781       p->owner = tmp;
    00782       ast_setstate(tmp, state);
    00783       ast_mutex_lock(&usecnt_lock);
    00784       usecnt++;
    00785       ast_mutex_unlock(&usecnt_lock);
    00786       ast_update_use_count();
    00787       if (state != AST_STATE_DOWN) {
    00788          if (ast_pbx_start(tmp)) {
    00789             ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
    00790             ast_hangup(tmp);
    00791             tmp = NULL;
    00792          }
    00793       }
    00794    }
    00795    return tmp;
    00796 }
    00797
    00798 static struct ast_channel *oss_request(const char *type, int format, void *data, int *cause)
    00799 {
    00800    int oldformat = format;
    00801    struct ast_channel *tmp;
    00802    format &= AST_FORMAT_SLINEAR;
    00803    if (!format) {
    00804       ast_log(LOG_NOTICE, "Asked to get a channel of format '%d'\n", oldformat);
    00805       return NULL;
    00806    }
    00807    if (oss.owner) {
    00808       ast_log(LOG_NOTICE, "Already have a call on the OSS channel\n");
    00809       *cause = AST_CAUSE_BUSY;
    00810       return NULL;
    00811    }
    00812    tmp= oss_new(&oss, AST_STATE_DOWN);
    00813    if (!tmp) {
    00814       ast_log(LOG_WARNING, "Unable to create new OSS channel\n");
    00815    }
    00816    return tmp;
    00817 }
    00818
    00819 static int console_autoanswer(int fd, int argc, char *argv[])
    00820 {
    00821    if ((argc != 1) && (argc != 2))
    00822       return RESULT_SHOWUSAGE;
    00823    if (argc == 1) {
    00824       ast_cli(fd, "Auto answer is %s.\n", autoanswer ? "on" : "off");
    00825       return RESULT_SUCCESS;
    00826    } else {
    00827       if (!strcasecmp(argv[1], "on"))
    00828          autoanswer = -1;
    00829       else if (!strcasecmp(argv[1], "off"))
    00830          autoanswer = 0;
    00831       else
    00832          return RESULT_SHOWUSAGE;
    00833    }
    00834    return RESULT_SUCCESS;
    00835 }
    00836
    00837 static char *autoanswer_complete(char *line, char *word, int pos, int state)
    00838 {
    00839 #ifndef MIN
    00840 #define MIN(a,b) ((a) < (b) ? (a) : (b))
    00841 #endif
    00842    switch(state) {
    00843    case 0:
    00844       if (!ast_strlen_zero(word) && !strncasecmp(word, "on", MIN(strlen(word), 2)))
    00845          return strdup("on");
    00846    case 1:
    00847       if (!ast_strlen_zero(word) && !strncasecmp(word, "off", MIN(strlen(word), 3)))
    00848          return strdup("off");
    00849    default:
    00850       return NULL;
    00851    }
    00852    return NULL;
    00853 }
    00854
    00855 static char autoanswer_usage[] =
    00856 "Usage: autoanswer [on|off]\n"
    00857 "       Enables or disables autoanswer feature.  If used without\n"
    00858 "       argument, displays the current on/off status of autoanswer.\n"
    00859 "       The default value of autoanswer is in 'oss.conf'.\n";
    00860
    00861 static int console_answer(int fd, int argc, char *argv[])
    00862 {
    00863    struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
    00864    if (argc != 1)
    00865       return RESULT_SHOWUSAGE;
    00866    if (!oss.owner) {
    00867       ast_cli(fd, "No one is calling us\n");
    00868       return RESULT_FAILURE;
    00869    }
    00870    hookstate = 1;
    00871    cursound = -1;
    00872    ast_queue_frame(oss.owner, &f);
    00873    answer_sound();
    00874    return RESULT_SUCCESS;
    00875 }
    00876
    00877 static char sendtext_usage[] =
    00878 "Usage: send text <message>\n"
    00879 "       Sends a text message for display on the remote terminal.\n";
    00880
    00881 static int console_sendtext(int fd, int argc, char *argv[])
    00882 {
    00883    int tmparg = 2;
    00884    char text2send[256] = "";
    00885    struct ast_frame f = { 0, };
    00886    if (argc < 2)
    00887       return RESULT_SHOWUSAGE;
    00888    if (!oss.owner) {
    00889       ast_cli(fd, "No one is calling us\n");
    00890       return RESULT_FAILURE;
    00891    }
    00892    if (!ast_strlen_zero(text2send))
    00893       ast_cli(fd, "Warning: message already waiting to be sent, overwriting\n");
    00894    text2send[0] = '\0';
    00895    while(tmparg < argc) {
    00896       strncat(text2send, argv[tmparg++], sizeof(text2send) - strlen(text2send) - 1);
    00897       strncat(text2send, " ", sizeof(text2send) - strlen(text2send) - 1);
    00898    }
    00899    if (!ast_strlen_zero(text2send)) {
    00900       f.frametype = AST_FRAME_TEXT;
    00901       f.subclass = 0;
    00902       f.data = text2send;
    00903       f.datalen = strlen(text2send);
    00904       ast_queue_frame(oss.owner, &f);
    00905    }
    00906    return RESULT_SUCCESS;
    00907 }
    00908
    00909 static char answer_usage[] =
    00910 "Usage: answer\n"
    00911 "       Answers an incoming call on the console (OSS) channel.\n";
    00912
    00913 static int console_hangup(int fd, int argc, char *argv[])
    00914 {
    00915    if (argc != 1)
    00916       return RESULT_SHOWUSAGE;
    00917    cursound = -1;
    00918    if (!oss.owner && !hookstate) {
    00919       ast_cli(fd, "No call to hangup up\n");
    00920       return RESULT_FAILURE;
    00921    }
    00922    hookstate = 0;
    00923    if (oss.owner) {
    00924       ast_queue_hangup(oss.owner);
    00925    }
    00926    return RESULT_SUCCESS;
    00927 }
    00928
    00929 static int console_flash(int fd, int argc, char *argv[])
    00930 {
    00931    struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_FLASH };
    00932    if (argc != 1)
    00933       return RESULT_SHOWUSAGE;
    00934    cursound = -1;
    00935    if (!oss.owner) {
    00936       ast_cli(fd, "No call to flash\n");
    00937       return RESULT_FAILURE;
    00938    }
    00939    hookstate = 0;
    00940    if (oss.owner) {
    00941       ast_queue_frame(oss.owner, &f);
    00942    }
    00943    return RESULT_SUCCESS;
    00944 }
    00945
    00946 static char hangup_usage[] =
    00947 "Usage: hangup\n"
    00948 "       Hangs up any call currently placed on the console.\n";
    00949
    00950
    00951 static char flash_usage[] =
    00952 "Usage: flash\n"
    00953 "       Flashes the call currently placed on the console.\n";
    00954
    00955 static int console_dial(int fd, int argc, char *argv[])
    00956 {
    00957    char tmp[256], *tmp2;
    00958    char *mye, *myc;
    00959    int x;
    00960    struct ast_frame f = { AST_FRAME_DTMF, 0 };
    00961    if ((argc != 1) && (argc != 2))
    00962       return RESULT_SHOWUSAGE;
    00963    if (oss.owner) {
    00964       if (argc == 2) {
    00965          for (x=0;x<strlen(argv[1]);x++) {
    00966             f.subclass = argv[1][x];
    00967             ast_queue_frame(oss.owner, &f);
    00968          }
    00969       } else {
    00970          ast_cli(fd, "You're already in a call.  You can use this only to dial digits until you hangup\n");
    00971          return RESULT_FAILURE;
    00972       }
    00973       return RESULT_SUCCESS;
    00974    }
    00975    mye = exten;
    00976    myc = context;
    00977    if (argc == 2) {
    00978       char *stringp=NULL;
    00979       strncpy(tmp, argv[1], sizeof(tmp)-1);
    00980       stringp=tmp;
    00981       strsep(&stringp, "@");
    00982       tmp2 = strsep(&stringp, "@");
    00983       if (!ast_strlen_zero(tmp))
    00984          mye = tmp;
    00985       if (!ast_strlen_zero(tmp2))
    00986          myc = tmp2;
    00987    }
    00988    if (ast_exists_extension(NULL, myc, mye, 1, NULL)) {
    00989       strncpy(oss.exten, mye, sizeof(oss.exten)-1);
    00990       strncpy(oss.context, myc, sizeof(oss.context)-1);
    00991       hookstate = 1;
    00992       oss_new(&oss, AST_STATE_RINGING);
    00993    } else
    00994       ast_cli(fd, "No such extension '%s' in context '%s'\n", mye, myc);
    00995    return RESULT_SUCCESS;
    00996 }
    00997
    00998 static char dial_usage[] =
    00999 "Usage: dial [extension[@context]]\n"
    01000 "       Dials a given extensison (and context if specified)\n";
    01001
    01002 static int console_transfer(int fd, int argc, char *argv[])
    01003 {
    01004    char tmp[256];
    01005    char *context;
    01006    if (argc != 2)
    01007       return RESULT_SHOWUSAGE;
    01008    if (oss.owner && ast_bridged_channel(oss.owner)) {
    01009       strncpy(tmp, argv[1], sizeof(tmp) - 1);
    01010       context = strchr(tmp, '@');
    01011       if (context) {
    01012          *context = '\0';
    01013          context++;
    01014       } else
    01015          context = oss.owner->context;
    01016       if (ast_exists_extension(ast_bridged_channel(oss.owner), context, tmp, 1, ast_bridged_channel(oss.owner)->cid.cid_num)) {
    01017          ast_cli(fd, "Whee, transferring %s to %s@%s.\n",
    01018                ast_bridged_channel(oss.owner)->name, tmp, context);
    01019          if (ast_async_goto(ast_bridged_channel(oss.owner), context, tmp, 1))
    01020             ast_cli(fd, "Failed to transfer :(\n");
    01021       } else {
    01022          ast_cli(fd, "No such extension exists\n");
    01023       }
    01024    } else {
    01025       ast_cli(fd, "There is no call to transfer\n");
    01026    }
    01027    return RESULT_SUCCESS;
    01028 }
    01029
    01030 static char transfer_usage[] =
    01031 "Usage: transfer <extension>[@context]\n"
    01032 "       Transfers the currently connected call to the given extension (and\n"
    01033 "context if specified)\n";
    01034
    01035 static struct ast_cli_entry myclis[] = {
    01036    { { "answer", NULL }, console_answer, "Answer an incoming console call", answer_usage },
    01037    { { "hangup", NULL }, console_hangup, "Hangup a call on the console", hangup_usage },
    01038    { { "flash", NULL }, console_flash, "Flash a call on the console", flash_usage },
    01039    { { "dial", NULL }, console_dial, "Dial an extension on the console", dial_usage },
    01040    { { "transfer", NULL }, console_transfer, "Transfer a call to a different extension", transfer_usage },
    01041    { { "send", "text", NULL }, console_sendtext, "Send text to the remote device", sendtext_usage },
    01042    { { "autoanswer", NULL }, console_autoanswer, "Sets/displays autoanswer", autoanswer_usage, autoanswer_complete }
    01043 };
    01044
    01045 int load_module()
    01046 {
    01047    int res;
    01048    int x;
    01049    struct ast_config *cfg;
    01050    struct ast_variable *v;
    01051    res = pipe(sndcmd);
    01052    if (res) {
    01053       ast_log(LOG_ERROR, "Unable to create pipe\n");
    01054       return -1;
    01055    }
    01056    res = soundcard_init();
    01057    if (res < 0) {
    01058       if (option_verbose > 1) {
    01059          ast_verbose(VERBOSE_PREFIX_2 "No sound card detected -- console channel will be unavailable\n");
    01060          ast_verbose(VERBOSE_PREFIX_2 "Turn off OSS support by adding 'noload=chan_oss.so' in /etc/asterisk/modules.conf\n");
    01061       }
    01062       return 0;
    01063    }
    01064    if (!full_duplex)
    01065       ast_log(LOG_WARNING, "XXX I don't work right with non-full duplex sound cards XXX\n");
    01066    res = ast_channel_register(&oss_tech);
    01067    if (res < 0) {
    01068       ast_log(LOG_ERROR, "Unable to register channel class '%s'\n", type);
    01069       return -1;
    01070    }
    01071    for (x=0;x<sizeof(myclis)/sizeof(struct ast_cli_entry); x++)
    01072       ast_cli_register(myclis + x);
    01073    if ((cfg = ast_config_load(config))) {
    01074       v = ast_variable_browse(cfg, "general");
    01075       while(v) {
    01076          if (!strcasecmp(v->name, "autoanswer"))
    01077             autoanswer = ast_true(v->value);
    01078          else if (!strcasecmp(v->name, "silencesuppression"))
    01079             silencesuppression = ast_true(v->value);
    01080          else if (!strcasecmp(v->name, "silencethreshold"))
    01081             silencethreshold = atoi(v->value);
    01082          else if (!strcasecmp(v->name, "context"))
    01083             strncpy(context, v->value, sizeof(context)-1);
    01084          else if (!strcasecmp(v->name, "language"))
    01085             strncpy(language, v->value, sizeof(language)-1);
    01086          else if (!strcasecmp(v->name, "extension"))
    01087             strncpy(exten, v->value, sizeof(exten)-1);
    01088          else if (!strcasecmp(v->name, "playbackonly"))
    01089             playbackonly = ast_true(v->value);
    01090          v=v->next;
    01091       }
    01092       ast_config_destroy(cfg);
    01093    }
    01094    ast_pthread_create(&sthread, NULL, sound_thread, NULL);
    01095    return 0;
    01096 }
    01097
    01098
    01099
    01100 int unload_module()
    01101 {
    01102    int x;
    01103
    01104    ast_channel_unregister(&oss_tech);
    01105    for (x=0;x<sizeof(myclis)/sizeof(struct ast_cli_entry); x++)
    01106       ast_cli_unregister(myclis + x);
    01107    close(sounddev);
    01108    if (sndcmd[0] > 0) {
    01109       close(sndcmd[0]);
    01110       close(sndcmd[1]);
    01111    }
    01112    if (oss.owner)
    01113       ast_softhangup(oss.owner, AST_SOFTHANGUP_APPUNLOAD);
    01114    if (oss.owner)
    01115       return -1;
    01116    return 0;
    01117 }
    01118
    01119 char *description()
    01120 {
    01121    return (char *) desc;
    01122 }
    01123
    01124 int usecount()
    01125 {
    01126    return usecnt;
    01127 }
    01128
    01129 char *key()
    01130 {
    01131    return ASTERISK_GPL_KEY;
    01132 }