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;
009