00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
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
00069 #if defined( __OpenBSD__ ) || defined( __NetBSD__ )
00070 #define DEV_DSP "/dev/audio"
00071 #else
00072 #define DEV_DSP "/dev/dsp"
00073 #endif
00074
00075
00076 #define FRAME_SIZE 160
00077
00078
00079
00080
00081 #define BUFFER_FMT ((buffersize * 10) << 16) | (0x0006);
00082
00083
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
00127 static int sndcmd[2];
00128
00129 static struct chan_oss_pvt {
00130
00131
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
00177
00178
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
00188 static int readmode = 1;
00189
00190
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
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
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
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
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
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
00343
00344 if (silbufcnt >= SILBUF) {
00345
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
00352 return 1;
00353 }
00354 } else {
00355 silentframes=0;
00356
00357
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
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
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
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
00433
00434
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
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
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
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
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
00563 hookstate = 0;
00564 } else {
00565
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
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
00591 bufcnt = 0;
00592 }
00593 if (bufcnt == buffersize) {
00594
00595 res = write(fd, ((void *)data), FRAME_SIZE * 2);
00596 } else {
00597
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
00617 if (nosound)
00618 return 0;
00619
00620 cursound = -1;
00621 if (!full_duplex && !playbackonly) {
00622
00623
00624
00625
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
00639
00640 return 0;
00641 }
00642
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
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
00703 readpos = 0;
00704 if (chan->_state != AST_STATE_UP) {
00705
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 }