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