Sat Nov 25 00:45:33 2006

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 }

Generated on Sat Nov 25 00:45:33 2006 for Asterisk - the Open Source PBX by  doxygen 1.4.6