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
00033
00034
00035
00036
00037
00038
00039 #include "asterisk.h"
00040
00041 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 159571 $")
00042
00043 #include <stdio.h>
00044 #include <ctype.h>
00045 #include <math.h>
00046 #include <string.h>
00047 #include <unistd.h>
00048 #include <sys/ioctl.h>
00049 #include <fcntl.h>
00050 #include <sys/time.h>
00051 #include <stdlib.h>
00052 #include <errno.h>
00053
00054 #ifdef __linux
00055 #include <linux/soundcard.h>
00056 #elif defined(__FreeBSD__)
00057 #include <sys/soundcard.h>
00058 #else
00059 #include <soundcard.h>
00060 #endif
00061
00062 #include "asterisk/lock.h"
00063 #include "asterisk/frame.h"
00064 #include "asterisk/logger.h"
00065 #include "asterisk/callerid.h"
00066 #include "asterisk/channel.h"
00067 #include "asterisk/module.h"
00068 #include "asterisk/options.h"
00069 #include "asterisk/pbx.h"
00070 #include "asterisk/config.h"
00071 #include "asterisk/cli.h"
00072 #include "asterisk/utils.h"
00073 #include "asterisk/causes.h"
00074 #include "asterisk/endian.h"
00075 #include "asterisk/stringfields.h"
00076 #include "asterisk/abstract_jb.h"
00077 #include "asterisk/musiconhold.h"
00078
00079
00080 #include "busy_tone.h"
00081 #include "ring_tone.h"
00082 #include "ring10.h"
00083 #include "answer.h"
00084
00085
00086 static struct ast_jb_conf default_jbconf =
00087 {
00088 .flags = 0,
00089 .max_size = -1,
00090 .resync_threshold = -1,
00091 .impl = "",
00092 };
00093 static struct ast_jb_conf global_jbconf;
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
00133
00134
00135
00136
00137
00138
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
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213 #define M_START(var, val) \
00214 char *__s = var; char *__val = val;
00215 #define M_END(x) x;
00216 #define M_F(tag, f) if (!strcasecmp((__s), tag)) { f; } else
00217 #define M_BOOL(tag, dst) M_F(tag, (dst) = ast_true(__val) )
00218 #define M_UINT(tag, dst) M_F(tag, (dst) = strtoul(__val, NULL, 0) )
00219 #define M_STR(tag, dst) M_F(tag, ast_copy_string(dst, __val, sizeof(dst)))
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251 #define FRAME_SIZE 160
00252 #define QUEUE_SIZE 10
00253
00254 #if defined(__FreeBSD__)
00255 #define FRAGS 0x8
00256 #else
00257 #define FRAGS ( ( (6 * 5) << 16 ) | 0x6 )
00258 #endif
00259
00260
00261
00262
00263
00264 #define TEXT_SIZE 256
00265
00266 #if 0
00267 #define TRYOPEN 1
00268 #endif
00269 #define O_CLOSE 0x444
00270
00271 #if defined( __OpenBSD__ ) || defined( __NetBSD__ )
00272 #define DEV_DSP "/dev/audio"
00273 #else
00274 #define DEV_DSP "/dev/dsp"
00275 #endif
00276
00277 #ifndef MIN
00278 #define MIN(a,b) ((a) < (b) ? (a) : (b))
00279 #endif
00280 #ifndef MAX
00281 #define MAX(a,b) ((a) > (b) ? (a) : (b))
00282 #endif
00283
00284 static char *config = "oss.conf";
00285
00286 static int oss_debug;
00287
00288
00289
00290
00291
00292
00293 struct sound {
00294 int ind;
00295 char *desc;
00296 short *data;
00297 int datalen;
00298 int samplen;
00299 int silencelen;
00300 int repeat;
00301 };
00302
00303 static struct sound sounds[] = {
00304 { AST_CONTROL_RINGING, "RINGING", ringtone, sizeof(ringtone)/2, 16000, 32000, 1 },
00305 { AST_CONTROL_BUSY, "BUSY", busy, sizeof(busy)/2, 4000, 4000, 1 },
00306 { AST_CONTROL_CONGESTION, "CONGESTION", busy, sizeof(busy)/2, 2000, 2000, 1 },
00307 { AST_CONTROL_RING, "RING10", ring10, sizeof(ring10)/2, 16000, 32000, 1 },
00308 { AST_CONTROL_ANSWER, "ANSWER", answer, sizeof(answer)/2, 2200, 0, 0 },
00309 { -1, NULL, 0, 0, 0, 0 },
00310 };
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320 struct chan_oss_pvt {
00321 struct chan_oss_pvt *next;
00322
00323 char *name;
00324
00325
00326
00327
00328
00329
00330
00331 int sndcmd[2];
00332 int cursound;
00333 int sampsent;
00334 int nosound;
00335
00336 int total_blocks;
00337 int sounddev;
00338 enum { M_UNSET, M_FULL, M_READ, M_WRITE } duplex;
00339 int autoanswer;
00340 int autohangup;
00341 int hookstate;
00342 char *mixer_cmd;
00343 unsigned int queuesize;
00344 unsigned int frags;
00345
00346 int warned;
00347 #define WARN_used_blocks 1
00348 #define WARN_speed 2
00349 #define WARN_frag 4
00350 int w_errors;
00351 struct timeval lastopen;
00352
00353 int overridecontext;
00354 int mute;
00355
00356
00357
00358
00359 #define BOOST_SCALE (1<<9)
00360 #define BOOST_MAX 40
00361 int boost;
00362 char device[64];
00363
00364 pthread_t sthread;
00365
00366 struct ast_channel *owner;
00367 char ext[AST_MAX_EXTENSION];
00368 char ctx[AST_MAX_CONTEXT];
00369 char language[MAX_LANGUAGE];
00370 char cid_name[256];
00371 char cid_num[256];
00372 char mohinterpret[MAX_MUSICCLASS];
00373
00374
00375 char oss_write_buf[FRAME_SIZE * 2];
00376 int oss_write_dst;
00377
00378
00379
00380 char oss_read_buf[FRAME_SIZE * 2 + AST_FRIENDLY_OFFSET];
00381 int readpos;
00382 struct ast_frame read_f;
00383 };
00384
00385 static struct chan_oss_pvt oss_default = {
00386 .cursound = -1,
00387 .sounddev = -1,
00388 .duplex = M_UNSET,
00389 .autoanswer = 1,
00390 .autohangup = 1,
00391 .queuesize = QUEUE_SIZE,
00392 .frags = FRAGS,
00393 .ext = "s",
00394 .ctx = "default",
00395 .readpos = AST_FRIENDLY_OFFSET,
00396 .lastopen = { 0, 0 },
00397 .boost = BOOST_SCALE,
00398 };
00399
00400 static char *oss_active;
00401
00402 static int setformat(struct chan_oss_pvt *o, int mode);
00403
00404 static struct ast_channel *oss_request(const char *type, int format, void *data
00405 , int *cause);
00406 static int oss_digit_begin(struct ast_channel *c, char digit);
00407 static int oss_digit_end(struct ast_channel *c, char digit, unsigned int duration);
00408 static int oss_text(struct ast_channel *c, const char *text);
00409 static int oss_hangup(struct ast_channel *c);
00410 static int oss_answer(struct ast_channel *c);
00411 static struct ast_frame *oss_read(struct ast_channel *chan);
00412 static int oss_call(struct ast_channel *c, char *dest, int timeout);
00413 static int oss_write(struct ast_channel *chan, struct ast_frame *f);
00414 static int oss_indicate(struct ast_channel *chan, int cond, const void *data, size_t datalen);
00415 static int oss_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
00416 static char tdesc[] = "OSS Console Channel Driver";
00417
00418 static const struct ast_channel_tech oss_tech = {
00419 .type = "Console",
00420 .description = tdesc,
00421 .capabilities = AST_FORMAT_SLINEAR,
00422 .requester = oss_request,
00423 .send_digit_begin = oss_digit_begin,
00424 .send_digit_end = oss_digit_end,
00425 .send_text = oss_text,
00426 .hangup = oss_hangup,
00427 .answer = oss_answer,
00428 .read = oss_read,
00429 .call = oss_call,
00430 .write = oss_write,
00431 .indicate = oss_indicate,
00432 .fixup = oss_fixup,
00433 };
00434
00435
00436
00437
00438 static struct chan_oss_pvt *find_desc(char *dev)
00439 {
00440 struct chan_oss_pvt *o = NULL;
00441
00442 if (!dev)
00443 ast_log(LOG_WARNING, "null dev\n");
00444
00445 for (o = oss_default.next; o && o->name && dev && strcmp(o->name, dev) != 0; o = o->next);
00446
00447 if (!o)
00448 ast_log(LOG_WARNING, "could not find <%s>\n", dev ? dev : "--no-device--");
00449
00450 return o;
00451 }
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462 static char *ast_ext_ctx(const char *src, char **ext, char **ctx)
00463 {
00464 struct chan_oss_pvt *o = find_desc(oss_active);
00465
00466 if (ext == NULL || ctx == NULL)
00467 return NULL;
00468
00469 *ext = *ctx = NULL;
00470
00471 if (src && *src != '\0')
00472 *ext = ast_strdup(src);
00473
00474 if (*ext == NULL)
00475 return NULL;
00476
00477 if (!o->overridecontext) {
00478
00479 *ctx = strrchr(*ext, '@');
00480 if (*ctx)
00481 *(*ctx)++ = '\0';
00482 }
00483
00484 return *ext;
00485 }
00486
00487
00488
00489
00490 static int used_blocks(struct chan_oss_pvt *o)
00491 {
00492 struct audio_buf_info info;
00493
00494 if (ioctl(o->sounddev, SNDCTL_DSP_GETOSPACE, &info)) {
00495 if (!(o->warned & WARN_used_blocks)) {
00496 ast_log(LOG_WARNING, "Error reading output space\n");
00497 o->warned |= WARN_used_blocks;
00498 }
00499 return 1;
00500 }
00501
00502 if (o->total_blocks == 0) {
00503 if (0)
00504 ast_log(LOG_WARNING, "fragtotal %d size %d avail %d\n", info.fragstotal, info.fragsize, info.fragments);
00505 o->total_blocks = info.fragments;
00506 }
00507
00508 return o->total_blocks - info.fragments;
00509 }
00510
00511
00512 static int soundcard_writeframe(struct chan_oss_pvt *o, short *data)
00513 {
00514 int res;
00515
00516 if (o->sounddev < 0)
00517 setformat(o, O_RDWR);
00518 if (o->sounddev < 0)
00519 return 0;
00520
00521
00522
00523
00524
00525
00526 res = used_blocks(o);
00527 if (res > o->queuesize) {
00528 if (o->w_errors++ == 0 && (oss_debug & 0x4))
00529 ast_log(LOG_WARNING, "write: used %d blocks (%d)\n", res, o->w_errors);
00530 return 0;
00531 }
00532 o->w_errors = 0;
00533 return write(o->sounddev, ((void *) data), FRAME_SIZE * 2);
00534 }
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546 static void send_sound(struct chan_oss_pvt *o)
00547 {
00548 short myframe[FRAME_SIZE];
00549 int ofs, l, start;
00550 int l_sampsent = o->sampsent;
00551 struct sound *s;
00552
00553 if (o->cursound < 0)
00554 return;
00555
00556 s = &sounds[o->cursound];
00557
00558 for (ofs = 0; ofs < FRAME_SIZE; ofs += l) {
00559 l = s->samplen - l_sampsent;
00560 if (l > 0) {
00561 start = l_sampsent % s->datalen;
00562 if (l > FRAME_SIZE - ofs)
00563 l = FRAME_SIZE - ofs;
00564 if (l > s->datalen - start)
00565 l = s->datalen - start;
00566 bcopy(s->data + start, myframe + ofs, l * 2);
00567 if (0)
00568 ast_log(LOG_WARNING, "send_sound sound %d/%d of %d into %d\n", l_sampsent, l, s->samplen, ofs);
00569 l_sampsent += l;
00570 } else {
00571 static const short silence[FRAME_SIZE] = { 0, };
00572
00573 l += s->silencelen;
00574 if (l > 0) {
00575 if (l > FRAME_SIZE - ofs)
00576 l = FRAME_SIZE - ofs;
00577 bcopy(silence, myframe + ofs, l * 2);
00578 l_sampsent += l;
00579 } else {
00580 if (s->repeat == 0) {
00581 o->cursound = -1;
00582 o->nosound = 0;
00583 if (ofs < FRAME_SIZE)
00584 bcopy(silence, myframe + ofs, (FRAME_SIZE - ofs) * 2);
00585 }
00586 l_sampsent = 0;
00587 }
00588 }
00589 }
00590 l = soundcard_writeframe(o, myframe);
00591 if (l > 0)
00592 o->sampsent = l_sampsent;
00593 }
00594
00595 static void *sound_thread(void *arg)
00596 {
00597 char ign[4096];
00598 struct chan_oss_pvt *o = (struct chan_oss_pvt *) arg;
00599
00600
00601
00602
00603
00604 if (read(o->sounddev, ign, sizeof(ign)) < 0) {
00605 }
00606 for (;;) {
00607 fd_set rfds, wfds;
00608 int maxfd, res;
00609
00610 FD_ZERO(&rfds);
00611 FD_ZERO(&wfds);
00612 FD_SET(o->sndcmd[0], &rfds);
00613 maxfd = o->sndcmd[0];
00614 if (o->cursound > -1 && o->sounddev < 0)
00615 setformat(o, O_RDWR);
00616 else if (o->cursound == -1 && o->owner == NULL)
00617 setformat(o, O_CLOSE);
00618 if (o->sounddev > -1) {
00619 if (!o->owner) {
00620 FD_SET(o->sounddev, &rfds);
00621 maxfd = MAX(o->sounddev, maxfd);
00622 }
00623 if (o->cursound > -1) {
00624 FD_SET(o->sounddev, &wfds);
00625 maxfd = MAX(o->sounddev, maxfd);
00626 }
00627 }
00628
00629 res = ast_select(maxfd + 1, &rfds, &wfds, NULL, NULL);
00630 if (res < 1) {
00631 ast_log(LOG_WARNING, "select failed: %s\n", strerror(errno));
00632 sleep(1);
00633 continue;
00634 }
00635 if (FD_ISSET(o->sndcmd[0], &rfds)) {
00636
00637 int i, what = -1;
00638
00639 if (read(o->sndcmd[0], &what, sizeof(what)) != sizeof(what)) {
00640 ast_log(LOG_WARNING, "read() failed: %s\n", strerror(errno));
00641 continue;
00642 }
00643 for (i = 0; sounds[i].ind != -1; i++) {
00644 if (sounds[i].ind == what) {
00645 o->cursound = i;
00646 o->sampsent = 0;
00647 o->nosound = 1;
00648 break;
00649 }
00650 }
00651 if (sounds[i].ind == -1)
00652 ast_log(LOG_WARNING, "invalid sound index: %d\n", what);
00653 }
00654 if (o->sounddev > -1) {
00655 if (FD_ISSET(o->sounddev, &rfds))
00656 if (read(o->sounddev, ign, sizeof(ign)) < 0) {
00657 }
00658 if (FD_ISSET(o->sounddev, &wfds))
00659 send_sound(o);
00660 }
00661 }
00662 return NULL;
00663 }
00664
00665
00666
00667
00668
00669
00670 static int setformat(struct chan_oss_pvt *o, int mode)
00671 {
00672 int fmt, desired, res, fd;
00673
00674 if (o->sounddev >= 0) {
00675 ioctl(o->sounddev, SNDCTL_DSP_RESET, 0);
00676 close(o->sounddev);
00677 o->duplex = M_UNSET;
00678 o->sounddev = -1;
00679 }
00680 if (mode == O_CLOSE)
00681 return 0;
00682 if (ast_tvdiff_ms(ast_tvnow(), o->lastopen) < 1000)
00683 return -1;
00684 o->lastopen = ast_tvnow();
00685 fd = o->sounddev = open(o->device, mode | O_NONBLOCK);
00686 if (fd < 0) {
00687 ast_log(LOG_WARNING, "Unable to re-open DSP device %s: %s\n", o->device, strerror(errno));
00688 return -1;
00689 }
00690 if (o->owner)
00691 o->owner->fds[0] = fd;
00692
00693 #if __BYTE_ORDER == __LITTLE_ENDIAN
00694 fmt = AFMT_S16_LE;
00695 #else
00696 fmt = AFMT_S16_BE;
00697 #endif
00698 res = ioctl(fd, SNDCTL_DSP_SETFMT, &fmt);
00699 if (res < 0) {
00700 ast_log(LOG_WARNING, "Unable to set format to 16-bit signed\n");
00701 return -1;
00702 }
00703 switch (mode) {
00704 case O_RDWR:
00705 res = ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0);
00706
00707 res = ioctl(fd, SNDCTL_DSP_GETCAPS, &fmt);
00708 if (res == 0 && (fmt & DSP_CAP_DUPLEX)) {
00709 if (option_verbose > 1)
00710 ast_verbose(VERBOSE_PREFIX_2 "Console is full duplex\n");
00711 o->duplex = M_FULL;
00712 };
00713 break;
00714 case O_WRONLY:
00715 o->duplex = M_WRITE;
00716 break;
00717 case O_RDONLY:
00718 o->duplex = M_READ;
00719 break;
00720 }
00721
00722 fmt = 0;
00723 res = ioctl(fd, SNDCTL_DSP_STEREO, &fmt);
00724 if (res < 0) {
00725 ast_log(LOG_WARNING, "Failed to set audio device to mono\n");
00726 return -1;
00727 }
00728 fmt = desired = DEFAULT_SAMPLE_RATE;
00729 res = ioctl(fd, SNDCTL_DSP_SPEED, &fmt);
00730
00731 if (res < 0) {
00732 ast_log(LOG_WARNING, "Failed to set audio device to mono\n");
00733 return -1;
00734 }
00735 if (fmt != desired) {
00736 if (!(o->warned & WARN_speed)) {
00737 ast_log(LOG_WARNING,
00738 "Requested %d Hz, got %d Hz -- sound may be choppy\n",
00739 desired, fmt);
00740 o->warned |= WARN_speed;
00741 }
00742 }
00743
00744
00745
00746
00747 if (o->frags) {
00748 fmt = o->frags;
00749 res = ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &fmt);
00750 if (res < 0) {
00751 if (!(o->warned & WARN_frag)) {
00752 ast_log(LOG_WARNING,
00753 "Unable to set fragment size -- sound may be choppy\n");
00754 o->warned |= WARN_frag;
00755 }
00756 }
00757 }
00758
00759 res = PCM_ENABLE_INPUT | PCM_ENABLE_OUTPUT;
00760 res = ioctl(fd, SNDCTL_DSP_SETTRIGGER, &res);
00761
00762 return 0;
00763 }
00764
00765
00766
00767
00768 static int oss_digit_begin(struct ast_channel *c, char digit)
00769 {
00770 return 0;
00771 }
00772
00773 static int oss_digit_end(struct ast_channel *c, char digit, unsigned int duration)
00774 {
00775
00776 ast_verbose(" << Console Received digit %c of duration %u ms >> \n",
00777 digit, duration);
00778 return 0;
00779 }
00780
00781 static int oss_text(struct ast_channel *c, const char *text)
00782 {
00783
00784 ast_verbose(" << Console Received text %s >> \n", text);
00785 return 0;
00786 }
00787
00788
00789 static void ring(struct chan_oss_pvt *o, int x)
00790 {
00791 if (write(o->sndcmd[1], &x, sizeof(x)) < 0) {
00792 ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
00793 }
00794 }
00795
00796
00797
00798
00799
00800 static int oss_call(struct ast_channel *c, char *dest, int timeout)
00801 {
00802 struct chan_oss_pvt *o = c->tech_pvt;
00803 struct ast_frame f = { 0, };
00804
00805 ast_verbose(" << Call to device '%s' dnid '%s' rdnis '%s' on console from '%s' <%s> >>\n", dest, c->cid.cid_dnid, c->cid.cid_rdnis, c->cid.cid_name, c->cid.cid_num);
00806 if (o->autoanswer) {
00807 ast_verbose(" << Auto-answered >> \n");
00808 f.frametype = AST_FRAME_CONTROL;
00809 f.subclass = AST_CONTROL_ANSWER;
00810 ast_queue_frame(c, &f);
00811 } else {
00812 ast_verbose("<< Type 'answer' to answer, or use 'autoanswer' for future calls >> \n");
00813 f.frametype = AST_FRAME_CONTROL;
00814 f.subclass = AST_CONTROL_RINGING;
00815 ast_queue_frame(c, &f);
00816 ring(o, AST_CONTROL_RING);
00817 }
00818 return 0;
00819 }
00820
00821
00822
00823
00824 static int oss_answer(struct ast_channel *c)
00825 {
00826 struct chan_oss_pvt *o = c->tech_pvt;
00827
00828 ast_verbose(" << Console call has been answered >> \n");
00829 #if 0
00830
00831 ring(o, AST_CONTROL_ANSWER);
00832 #endif
00833 ast_setstate(c, AST_STATE_UP);
00834 o->cursound = -1;
00835 o->nosound = 0;
00836 return 0;
00837 }
00838
00839 static int oss_hangup(struct ast_channel *c)
00840 {
00841 struct chan_oss_pvt *o = c->tech_pvt;
00842
00843 o->cursound = -1;
00844 o->nosound = 0;
00845 c->tech_pvt = NULL;
00846 o->owner = NULL;
00847 ast_verbose(" << Hangup on console >> \n");
00848 ast_module_unref(ast_module_info->self);
00849 if (o->hookstate) {
00850 if (o->autoanswer || o->autohangup) {
00851
00852 o->hookstate = 0;
00853 setformat(o, O_CLOSE);
00854 } else {
00855
00856 ring(o, AST_CONTROL_CONGESTION);
00857 }
00858 }
00859 return 0;
00860 }
00861
00862
00863 static int oss_write(struct ast_channel *c, struct ast_frame *f)
00864 {
00865 int src;
00866 struct chan_oss_pvt *o = c->tech_pvt;
00867
00868
00869 if (o->nosound)
00870 return 0;
00871
00872 o->cursound = -1;
00873
00874
00875
00876
00877
00878
00879 src = 0;
00880 while (src < f->datalen) {
00881
00882 int l = sizeof(o->oss_write_buf) - o->oss_write_dst;
00883
00884 if (f->datalen - src >= l) {
00885 memcpy(o->oss_write_buf + o->oss_write_dst, f->data + src, l);
00886 soundcard_writeframe(o, (short *) o->oss_write_buf);
00887 src += l;
00888 o->oss_write_dst = 0;
00889 } else {
00890 l = f->datalen - src;
00891 memcpy(o->oss_write_buf + o->oss_write_dst, f->data + src, l);
00892 src += l;
00893 o->oss_write_dst += l;
00894 }
00895 }
00896 return 0;
00897 }
00898
00899 static struct ast_frame *oss_read(struct ast_channel *c)
00900 {
00901 int res;
00902 struct chan_oss_pvt *o = c->tech_pvt;
00903 struct ast_frame *f = &o->read_f;
00904
00905
00906
00907 bzero(f, sizeof(struct ast_frame));
00908 f->frametype = AST_FRAME_NULL;
00909 f->src = oss_tech.type;
00910
00911 res = read(o->sounddev, o->oss_read_buf + o->readpos, sizeof(o->oss_read_buf) - o->readpos);
00912 if (res < 0)
00913 return f;
00914
00915 o->readpos += res;
00916 if (o->readpos < sizeof(o->oss_read_buf))
00917 return f;
00918
00919 if (o->mute)
00920 return f;
00921
00922 o->readpos = AST_FRIENDLY_OFFSET;
00923 if (c->_state != AST_STATE_UP)
00924 return f;
00925
00926 f->frametype = AST_FRAME_VOICE;
00927 f->subclass = AST_FORMAT_SLINEAR;
00928 f->samples = FRAME_SIZE;
00929 f->datalen = FRAME_SIZE * 2;
00930 f->data = o->oss_read_buf + AST_FRIENDLY_OFFSET;
00931 if (o->boost != BOOST_SCALE) {
00932 int i, x;
00933 int16_t *p = (int16_t *) f->data;
00934 for (i = 0; i < f->samples; i++) {
00935 x = (p[i] * o->boost) / BOOST_SCALE;
00936 if (x > 32767)
00937 x = 32767;
00938 else if (x < -32768)
00939 x = -32768;
00940 p[i] = x;
00941 }
00942 }
00943
00944 f->offset = AST_FRIENDLY_OFFSET;
00945 return f;
00946 }
00947
00948 static int oss_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
00949 {
00950 struct chan_oss_pvt *o = newchan->tech_pvt;
00951 o->owner = newchan;
00952 return 0;
00953 }
00954
00955 static int oss_indicate(struct ast_channel *c, int cond, const void *data, size_t datalen)
00956 {
00957 struct chan_oss_pvt *o = c->tech_pvt;
00958 int res = -1;
00959
00960 switch (cond) {
00961 case AST_CONTROL_BUSY:
00962 case AST_CONTROL_CONGESTION:
00963 case AST_CONTROL_RINGING:
00964 res = cond;
00965 break;
00966
00967 case -1:
00968 o->cursound = -1;
00969 o->nosound = 0;
00970 return 0;
00971
00972 case AST_CONTROL_VIDUPDATE:
00973 res = -1;
00974 break;
00975 case AST_CONTROL_HOLD:
00976 ast_verbose(" << Console Has Been Placed on Hold >> \n");
00977 ast_moh_start(c, data, o->mohinterpret);
00978 break;
00979 case AST_CONTROL_UNHOLD:
00980 ast_verbose(" << Console Has Been Retrieved from Hold >> \n");
00981 ast_moh_stop(c);
00982 break;
00983 case AST_CONTROL_SRCUPDATE:
00984 break;
00985 default:
00986 ast_log(LOG_WARNING, "Don't know how to display condition %d on %s\n", cond, c->name);
00987 return -1;
00988 }
00989
00990 if (res > -1)
00991 ring(o, res);
00992
00993 return 0;
00994 }
00995
00996
00997
00998
00999 static struct ast_channel *oss_new(struct chan_oss_pvt *o, char *ext, char *ctx, int state)
01000 {
01001 struct ast_channel *c;
01002
01003 c = ast_channel_alloc(1, state, o->cid_num, o->cid_name, "", ext, ctx, 0, "Console/%s", o->device + 5);
01004 if (c == NULL)
01005 return NULL;
01006 c->tech = &oss_tech;
01007 if (o->sounddev < 0)
01008 setformat(o, O_RDWR);
01009 c->fds[0] = o->sounddev;
01010 c->nativeformats = AST_FORMAT_SLINEAR;
01011 c->readformat = AST_FORMAT_SLINEAR;
01012 c->writeformat = AST_FORMAT_SLINEAR;
01013 c->tech_pvt = o;
01014
01015 if (!ast_strlen_zero(o->language))
01016 ast_string_field_set(c, language, o->language);
01017
01018
01019 c->cid.cid_ani = ast_strdup(o->cid_num);
01020 if (!ast_strlen_zero(ext))
01021 c->cid.cid_dnid = ast_strdup(ext);
01022
01023 o->owner = c;
01024 ast_module_ref(ast_module_info->self);
01025 ast_jb_configure(c, &global_jbconf);
01026 if (state != AST_STATE_DOWN) {
01027 if (ast_pbx_start(c)) {
01028 ast_log(LOG_WARNING, "Unable to start PBX on %s\n", c->name);
01029 ast_hangup(c);
01030 o->owner = c = NULL;
01031
01032
01033 }
01034 }
01035
01036 return c;
01037 }
01038
01039 static struct ast_channel *oss_request(const char *type, int format, void *data, int *cause)
01040 {
01041 struct ast_channel *c;
01042 struct chan_oss_pvt *o = find_desc(data);
01043
01044 ast_log(LOG_WARNING, "oss_request ty <%s> data 0x%p <%s>\n", type, data, (char *) data);
01045 if (o == NULL) {
01046 ast_log(LOG_NOTICE, "Device %s not found\n", (char *) data);
01047
01048 return NULL;
01049 }
01050 if ((format & AST_FORMAT_SLINEAR) == 0) {
01051 ast_log(LOG_NOTICE, "Format 0x%x unsupported\n", format);
01052 return NULL;
01053 }
01054 if (o->owner) {
01055 ast_log(LOG_NOTICE, "Already have a call (chan %p) on the OSS channel\n", o->owner);
01056 *cause = AST_CAUSE_BUSY;
01057 return NULL;
01058 }
01059 c = oss_new(o, NULL, NULL, AST_STATE_DOWN);
01060 if (c == NULL) {
01061 ast_log(LOG_WARNING, "Unable to create new OSS channel\n");
01062 return NULL;
01063 }
01064 return c;
01065 }
01066
01067 static int console_autoanswer_deprecated(int fd, int argc, char *argv[])
01068 {
01069 struct chan_oss_pvt *o = find_desc(oss_active);
01070
01071 if (argc == 1) {
01072 ast_cli(fd, "Auto answer is %s.\n", o->autoanswer ? "on" : "off");
01073 return RESULT_SUCCESS;
01074 }
01075 if (argc != 2)
01076 return RESULT_SHOWUSAGE;
01077 if (o == NULL) {
01078 ast_log(LOG_WARNING, "Cannot find device %s (should not happen!)\n", oss_active);
01079 return RESULT_FAILURE;
01080 }
01081 if (!strcasecmp(argv[1], "on"))
01082 o->autoanswer = -1;
01083 else if (!strcasecmp(argv[1], "off"))
01084 o->autoanswer = 0;
01085 else
01086 return RESULT_SHOWUSAGE;
01087 return RESULT_SUCCESS;
01088 }
01089
01090 static int console_autoanswer(int fd, int argc, char *argv[])
01091 {
01092 struct chan_oss_pvt *o = find_desc(oss_active);
01093
01094 if (argc == 2) {
01095 ast_cli(fd, "Auto answer is %s.\n", o->autoanswer ? "on" : "off");
01096 return RESULT_SUCCESS;
01097 }
01098 if (argc != 3)
01099 return RESULT_SHOWUSAGE;
01100 if (o == NULL) {
01101 ast_log(LOG_WARNING, "Cannot find device %s (should not happen!)\n",
01102 oss_active);
01103 return RESULT_FAILURE;
01104 }
01105 if (!strcasecmp(argv[2], "on"))
01106 o->autoanswer = -1;
01107 else if (!strcasecmp(argv[2], "off"))
01108 o->autoanswer = 0;
01109 else
01110 return RESULT_SHOWUSAGE;
01111 return RESULT_SUCCESS;
01112 }
01113
01114 static char *autoanswer_complete_deprecated(const char *line, const char *word, int pos, int state)
01115 {
01116 static char *choices[] = { "on", "off", NULL };
01117
01118 return (pos != 2) ? NULL : ast_cli_complete(word, choices, state);
01119 }
01120
01121 static char *autoanswer_complete(const char *line, const char *word, int pos, int state)
01122 {
01123 static char *choices[] = { "on", "off", NULL };
01124
01125 return (pos != 3) ? NULL : ast_cli_complete(word, choices, state);
01126 }
01127
01128 static char autoanswer_usage[] =
01129 "Usage: console autoanswer [on|off]\n"
01130 " Enables or disables autoanswer feature. If used without\n"
01131 " argument, displays the current on/off status of autoanswer.\n"
01132 " The default value of autoanswer is in 'oss.conf'.\n";
01133
01134
01135
01136
01137 static int console_answer_deprecated(int fd, int argc, char *argv[])
01138 {
01139 struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
01140 struct chan_oss_pvt *o = find_desc(oss_active);
01141
01142 if (argc != 1)
01143 return RESULT_SHOWUSAGE;
01144 if (!o->owner) {
01145 ast_cli(fd, "No one is calling us\n");
01146 return RESULT_FAILURE;
01147 }
01148 o->hookstate = 1;
01149 o->cursound = -1;
01150 o->nosound = 0;
01151 ast_queue_frame(o->owner, &f);
01152 #if 0
01153
01154 ring(o, AST_CONTROL_ANSWER);
01155 #endif
01156 return RESULT_SUCCESS;
01157 }
01158
01159 static int console_answer(int fd, int argc, char *argv[])
01160 {
01161 struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
01162 struct chan_oss_pvt *o = find_desc(oss_active);
01163
01164 if (argc != 2)
01165 return RESULT_SHOWUSAGE;
01166 if (!o->owner) {
01167 ast_cli(fd, "No one is calling us\n");
01168 return RESULT_FAILURE;
01169 }
01170 o->hookstate = 1;
01171 o->cursound = -1;
01172 o->nosound = 0;
01173 ast_queue_frame(o->owner, &f);
01174 #if 0
01175
01176 ring(o, AST_CONTROL_ANSWER);
01177 #endif
01178 return RESULT_SUCCESS;
01179 }
01180
01181 static char answer_usage[] =
01182 "Usage: console answer\n"
01183 " Answers an incoming call on the console (OSS) channel.\n";
01184
01185
01186
01187
01188
01189 static int console_sendtext_deprecated(int fd, int argc, char *argv[])
01190 {
01191 struct chan_oss_pvt *o = find_desc(oss_active);
01192 char buf[TEXT_SIZE];
01193
01194 if (argc < 2)
01195 return RESULT_SHOWUSAGE;
01196 if (!o->owner) {
01197 ast_cli(fd, "Not in a call\n");
01198 return RESULT_FAILURE;
01199 }
01200 ast_join(buf, sizeof(buf) - 1, argv + 2);
01201 if (!ast_strlen_zero(buf)) {
01202 struct ast_frame f = { 0, };
01203 int i = strlen(buf);
01204 buf[i] = '\n';
01205 f.frametype = AST_FRAME_TEXT;
01206 f.subclass = 0;
01207 f.data = buf;
01208 f.datalen = i + 1;
01209 ast_queue_frame(o->owner, &f);
01210 }
01211 return RESULT_SUCCESS;
01212 }
01213
01214 static int console_sendtext(int fd, int argc, char *argv[])
01215 {
01216 struct chan_oss_pvt *o = find_desc(oss_active);
01217 char buf[TEXT_SIZE];
01218
01219 if (argc < 3)
01220 return RESULT_SHOWUSAGE;
01221 if (!o->owner) {
01222 ast_cli(fd, "Not in a call\n");
01223 return RESULT_FAILURE;
01224 }
01225 ast_join(buf, sizeof(buf) - 1, argv + 3);
01226 if (!ast_strlen_zero(buf)) {
01227 struct ast_frame f = { 0, };
01228 int i = strlen(buf);
01229 buf[i] = '\n';
01230 f.frametype = AST_FRAME_TEXT;
01231 f.subclass = 0;
01232 f.data = buf;
01233 f.datalen = i + 1;
01234 ast_queue_frame(o->owner, &f);
01235 }
01236 return RESULT_SUCCESS;
01237 }
01238
01239 static char sendtext_usage[] =
01240 "Usage: console send text <message>\n"
01241 " Sends a text message for display on the remote terminal.\n";
01242
01243 static int console_hangup_deprecated(int fd, int argc, char *argv[])
01244 {
01245 struct chan_oss_pvt *o = find_desc(oss_active);
01246
01247 if (argc != 1)
01248 return RESULT_SHOWUSAGE;
01249 o->cursound = -1;
01250 o->nosound = 0;
01251 if (!o->owner && !o->hookstate) {
01252 ast_cli(fd, "No call to hang up\n");
01253 return RESULT_FAILURE;
01254 }
01255 o->hookstate = 0;
01256 if (o->owner)
01257 ast_queue_hangup(o->owner);
01258 setformat(o, O_CLOSE);
01259 return RESULT_SUCCESS;
01260 }
01261
01262 static int console_hangup(int fd, int argc, char *argv[])
01263 {
01264 struct chan_oss_pvt *o = find_desc(oss_active);
01265
01266 if (argc != 2)
01267 return RESULT_SHOWUSAGE;
01268 o->cursound = -1;
01269 o->nosound = 0;
01270 if (!o->owner && !o->hookstate) {
01271 ast_cli(fd, "No call to hang up\n");
01272 return RESULT_FAILURE;
01273 }
01274 o->hookstate = 0;
01275 if (o->owner)
01276 ast_queue_hangup(o->owner);
01277 setformat(o, O_CLOSE);
01278 return RESULT_SUCCESS;
01279 }
01280
01281 static char hangup_usage[] =
01282 "Usage: console hangup\n"
01283 " Hangs up any call currently placed on the console.\n";
01284
01285 static int console_flash_deprecated(int fd, int argc, char *argv[])
01286 {
01287 struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_FLASH };
01288 struct chan_oss_pvt *o = find_desc(oss_active);
01289
01290 if (argc != 1)
01291 return RESULT_SHOWUSAGE;
01292 o->cursound = -1;
01293 o->nosound = 0;
01294 if (!o->owner) {
01295 ast_cli(fd, "No call to flash\n");
01296 return RESULT_FAILURE;
01297 }
01298 o->hookstate = 0;
01299 if (o->owner)
01300 ast_queue_frame(o->owner, &f);
01301 return RESULT_SUCCESS;
01302 }
01303
01304 static int console_flash(int fd, int argc, char *argv[])
01305 {
01306 struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_FLASH };
01307 struct chan_oss_pvt *o = find_desc(oss_active);
01308
01309 if (argc != 2)
01310 return RESULT_SHOWUSAGE;
01311 o->cursound = -1;
01312 o->nosound = 0;
01313 if (!o->owner) {
01314 ast_cli(fd, "No call to flash\n");
01315 return RESULT_FAILURE;
01316 }
01317 o->hookstate = 0;
01318 if (o->owner)
01319 ast_queue_frame(o->owner, &f);
01320 return RESULT_SUCCESS;
01321 }
01322
01323 static char flash_usage[] =
01324 "Usage: console flash\n"
01325 " Flashes the call currently placed on the console.\n";
01326
01327 static int console_dial_deprecated(int fd, int argc, char *argv[])
01328 {
01329 char *s = NULL, *mye = NULL, *myc = NULL;
01330 struct chan_oss_pvt *o = find_desc(oss_active);
01331
01332 if (argc != 1 && argc != 2)
01333 return RESULT_SHOWUSAGE;
01334 if (o->owner) {
01335 int i;
01336 struct ast_frame f = { AST_FRAME_DTMF, 0 };
01337
01338 if (argc == 1) {
01339 ast_cli(fd, "Already in a call. You can only dial digits until you hangup.\n");
01340 return RESULT_FAILURE;
01341 }
01342 s = argv[1];
01343
01344 for (i = 0; i < strlen(s); i++) {
01345 f.subclass = s[i];
01346 ast_queue_frame(o->owner, &f);
01347 }
01348 return RESULT_SUCCESS;
01349 }
01350
01351 if (argc == 2)
01352 s = ast_ext_ctx(argv[1], &mye, &myc);
01353
01354 if (mye == NULL)
01355 mye = o->ext;
01356 if (myc == NULL)
01357 myc = o->ctx;
01358 if (ast_exists_extension(NULL, myc, mye, 1, NULL)) {
01359 o->hookstate = 1;
01360 oss_new(o, mye, myc, AST_STATE_RINGING);
01361 } else
01362 ast_cli(fd, "No such extension '%s' in context '%s'\n", mye, myc);
01363 if (s)
01364 free(s);
01365 return RESULT_SUCCESS;
01366 }
01367
01368 static int console_dial(int fd, int argc, char *argv[])
01369 {
01370 char *s = NULL, *mye = NULL, *myc = NULL;
01371 struct chan_oss_pvt *o = find_desc(oss_active);
01372
01373 if (argc != 2 && argc != 3)
01374 return RESULT_SHOWUSAGE;
01375 if (o->owner) {
01376 int i;
01377 struct ast_frame f = { AST_FRAME_DTMF, 0 };
01378
01379 if (argc == 2) {
01380 ast_cli(fd, "Already in a call. You can only dial digits until you hangup.\n");
01381 return RESULT_FAILURE;
01382 }
01383 s = argv[2];
01384
01385 for (i = 0; i < strlen(s); i++) {
01386 f.subclass = s[i];
01387 ast_queue_frame(o->owner, &f);
01388 }
01389 return RESULT_SUCCESS;
01390 }
01391
01392 if (argc == 3)
01393 s = ast_ext_ctx(argv[2], &mye, &myc);
01394
01395 if (mye == NULL)
01396 mye = o->ext;
01397 if (myc == NULL)
01398 myc = o->ctx;
01399 if (ast_exists_extension(NULL, myc, mye, 1, NULL)) {
01400 o->hookstate = 1;
01401 oss_new(o, mye, myc, AST_STATE_RINGING);
01402 } else
01403 ast_cli(fd, "No such extension '%s' in context '%s'\n", mye, myc);
01404 if (s)
01405 free(s);
01406 return RESULT_SUCCESS;
01407 }
01408
01409 static char dial_usage[] =
01410 "Usage: console dial [extension[@context]]\n"
01411 " Dials a given extension (and context if specified)\n";
01412
01413 static int __console_mute_unmute(int mute)
01414 {
01415 struct chan_oss_pvt *o = find_desc(oss_active);
01416
01417 o->mute = mute;
01418 return RESULT_SUCCESS;
01419 }
01420
01421 static int console_mute_deprecated(int fd, int argc, char *argv[])
01422 {
01423 if (argc != 1)
01424 return RESULT_SHOWUSAGE;
01425
01426 return __console_mute_unmute(1);
01427 }
01428
01429 static int console_mute(int fd, int argc, char *argv[])
01430 {
01431 if (argc != 2)
01432 return RESULT_SHOWUSAGE;
01433
01434 return __console_mute_unmute(1);
01435 }
01436
01437 static char mute_usage[] =
01438 "Usage: console mute\nMutes the microphone\n";
01439
01440 static int console_unmute_deprecated(int fd, int argc, char *argv[])
01441 {
01442 if (argc != 1)
01443 return RESULT_SHOWUSAGE;
01444
01445 return __console_mute_unmute(0);
01446 }
01447
01448 static int console_unmute(int fd, int argc, char *argv[])
01449 {
01450 if (argc != 2)
01451 return RESULT_SHOWUSAGE;
01452
01453 return __console_mute_unmute(0);
01454 }
01455
01456 static char unmute_usage[] =
01457 "Usage: console unmute\nUnmutes the microphone\n";
01458
01459 static int console_transfer_deprecated(int fd, int argc, char *argv[])
01460 {
01461 struct chan_oss_pvt *o = find_desc(oss_active);
01462 struct ast_channel *b = NULL;
01463 char *tmp, *ext, *ctx;
01464
01465 if (argc != 2)
01466 return RESULT_SHOWUSAGE;
01467 if (o == NULL)
01468 return RESULT_FAILURE;
01469 if (o->owner ==NULL || (b = ast_bridged_channel(o->owner)) == NULL) {
01470 ast_cli(fd, "There is no call to transfer\n");
01471 return RESULT_SUCCESS;
01472 }
01473
01474 tmp = ast_ext_ctx(argv[1], &ext, &ctx);
01475 if (ctx == NULL)
01476 ctx = o->owner->context;
01477 if (!ast_exists_extension(b, ctx, ext, 1, b->cid.cid_num))
01478 ast_cli(fd, "No such extension exists\n");
01479 else {
01480 ast_cli(fd, "Whee, transferring %s to %s@%s.\n",
01481 b->name, ext, ctx);
01482 if (ast_async_goto(b, ctx, ext, 1))
01483 ast_cli(fd, "Failed to transfer :(\n");
01484 }
01485 if (tmp)
01486 free(tmp);
01487 return RESULT_SUCCESS;
01488 }
01489
01490 static int console_transfer(int fd, int argc, char *argv[])
01491 {
01492 struct chan_oss_pvt *o = find_desc(oss_active);
01493 struct ast_channel *b = NULL;
01494 char *tmp, *ext, *ctx;
01495
01496 if (argc != 3)
01497 return RESULT_SHOWUSAGE;
01498 if (o == NULL)
01499 return RESULT_FAILURE;
01500 if (o->owner == NULL || (b = ast_bridged_channel(o->owner)) == NULL) {
01501 ast_cli(fd, "There is no call to transfer\n");
01502 return RESULT_SUCCESS;
01503 }
01504
01505 tmp = ast_ext_ctx(argv[2], &ext, &ctx);
01506 if (ctx == NULL)
01507 ctx = o->owner->context;
01508 if (!ast_exists_extension(b, ctx, ext, 1, b->cid.cid_num))
01509 ast_cli(fd, "No such extension exists\n");
01510 else {
01511 ast_cli(fd, "Whee, transferring %s to %s@%s.\n", b->name, ext, ctx);
01512 if (ast_async_goto(b, ctx, ext, 1))
01513 ast_cli(fd, "Failed to transfer :(\n");
01514 }
01515 if (tmp)
01516 free(tmp);
01517 return RESULT_SUCCESS;
01518 }
01519
01520 static char transfer_usage[] =
01521 "Usage: console transfer <extension>[@context]\n"
01522 " Transfers the currently connected call to the given extension (and\n"
01523 "context if specified)\n";
01524
01525 static int console_active_deprecated(int fd, int argc, char *argv[])
01526 {
01527 if (argc == 1)
01528 ast_cli(fd, "active console is [%s]\n", oss_active);
01529 else if (argc != 2)
01530 return RESULT_SHOWUSAGE;
01531 else {
01532 struct chan_oss_pvt *o;
01533 if (strcmp(argv[1], "show") == 0) {
01534 for (o = oss_default.next; o; o = o->next)
01535 ast_cli(fd, "device [%s] exists\n", o->name);
01536 return RESULT_SUCCESS;
01537 }
01538 o = find_desc(argv[1]);
01539 if (o == NULL)
01540 ast_cli(fd, "No device [%s] exists\n", argv[1]);
01541 else
01542 oss_active = o->name;
01543 }
01544 return RESULT_SUCCESS;
01545 }
01546
01547 static int console_active(int fd, int argc, char *argv[])
01548 {
01549 if (argc == 2)
01550 ast_cli(fd, "active console is [%s]\n", oss_active);
01551 else if (argc != 3)
01552 return RESULT_SHOWUSAGE;
01553 else {
01554 struct chan_oss_pvt *o;
01555 if (strcmp(argv[2], "show") == 0) {
01556 for (o = oss_default.next; o; o = o->next)
01557 ast_cli(fd, "device [%s] exists\n", o->name);
01558 return RESULT_SUCCESS;
01559 }
01560 o = find_desc(argv[2]);
01561 if (o == NULL)
01562 ast_cli(fd, "No device [%s] exists\n", argv[2]);
01563 else
01564 oss_active = o->name;
01565 }
01566 return RESULT_SUCCESS;
01567 }
01568
01569 static char active_usage[] =
01570 "Usage: console active [device]\n"
01571 " If used without a parameter, displays which device is the current\n"
01572 "console. If a device is specified, the console sound device is changed to\n"
01573 "the device specified.\n";
01574
01575
01576
01577
01578 static void store_boost(struct chan_oss_pvt *o, char *s)
01579 {
01580 double boost = 0;
01581 if (sscanf(s, "%lf", &boost) != 1) {
01582 ast_log(LOG_WARNING, "invalid boost <%s>\n", s);
01583 return;
01584 }
01585 if (boost < -BOOST_MAX) {
01586 ast_log(LOG_WARNING, "boost %s too small, using %d\n", s, -BOOST_MAX);
01587 boost = -BOOST_MAX;
01588 } else if (boost > BOOST_MAX) {
01589 ast_log(LOG_WARNING, "boost %s too large, using %d\n", s, BOOST_MAX);
01590 boost = BOOST_MAX;
01591 }
01592 boost = exp(log(10) * boost / 20) * BOOST_SCALE;
01593 o->boost = boost;
01594 ast_log(LOG_WARNING, "setting boost %s to %d\n", s, o->boost);
01595 }
01596
01597 static int do_boost(int fd, int argc, char *argv[])
01598 {
01599 struct chan_oss_pvt *o = find_desc(oss_active);
01600
01601 if (argc == 2)
01602 ast_cli(fd, "boost currently %5.1f\n", 20 * log10(((double) o->boost / (double) BOOST_SCALE)));
01603 else if (argc == 3)
01604 store_boost(o, argv[2]);
01605 return RESULT_SUCCESS;
01606 }
01607
01608 static struct ast_cli_entry cli_oss_answer_deprecated = {
01609 { "answer", NULL },
01610 console_answer_deprecated, NULL,
01611 NULL };
01612
01613 static struct ast_cli_entry cli_oss_hangup_deprecated = {
01614 { "hangup", NULL },
01615 console_hangup_deprecated, NULL,
01616 NULL };
01617
01618 static struct ast_cli_entry cli_oss_flash_deprecated = {
01619 { "flash", NULL },
01620 console_flash_deprecated, NULL,
01621 NULL };
01622
01623 static struct ast_cli_entry cli_oss_dial_deprecated = {
01624 { "dial", NULL },
01625 console_dial_deprecated, NULL,
01626 NULL };
01627
01628 static struct ast_cli_entry cli_oss_mute_deprecated = {
01629 { "mute", NULL },
01630 console_mute_deprecated, NULL,
01631 NULL };
01632
01633 static struct ast_cli_entry cli_oss_unmute_deprecated = {
01634 { "unmute", NULL },
01635 console_unmute_deprecated, NULL,
01636 NULL };
01637
01638 static struct ast_cli_entry cli_oss_transfer_deprecated = {
01639 { "transfer", NULL },
01640 console_transfer_deprecated, NULL,
01641 NULL };
01642
01643 static struct ast_cli_entry cli_oss_send_text_deprecated = {
01644 { "send", "text", NULL },
01645 console_sendtext_deprecated, NULL,
01646 NULL };
01647
01648 static struct ast_cli_entry cli_oss_autoanswer_deprecated = {
01649 { "autoanswer", NULL },
01650 console_autoanswer_deprecated, NULL,
01651 NULL, autoanswer_complete_deprecated };
01652
01653 static struct ast_cli_entry cli_oss_boost_deprecated = {
01654 { "oss", "boost", NULL },
01655 do_boost, NULL,
01656 NULL };
01657
01658 static struct ast_cli_entry cli_oss_active_deprecated = {
01659 { "console", NULL },
01660 console_active_deprecated, NULL,
01661 NULL };
01662
01663 static struct ast_cli_entry cli_oss[] = {
01664 { { "console", "answer", NULL },
01665 console_answer, "Answer an incoming console call",
01666 answer_usage, NULL, &cli_oss_answer_deprecated },
01667
01668 { { "console", "hangup", NULL },
01669 console_hangup, "Hangup a call on the console",
01670 hangup_usage, NULL, &cli_oss_hangup_deprecated },
01671
01672 { { "console", "flash", NULL },
01673 console_flash, "Flash a call on the console",
01674 flash_usage, NULL, &cli_oss_flash_deprecated },
01675
01676 { { "console", "dial", NULL },
01677 console_dial, "Dial an extension on the console",
01678 dial_usage, NULL, &cli_oss_dial_deprecated },
01679
01680 { { "console", "mute", NULL },
01681 console_mute, "Disable mic input",
01682 mute_usage, NULL, &cli_oss_mute_deprecated },
01683
01684 { { "console", "unmute", NULL },
01685 console_unmute, "Enable mic input",
01686 unmute_usage, NULL, &cli_oss_unmute_deprecated },
01687
01688 { { "console", "transfer", NULL },
01689 console_transfer, "Transfer a call to a different extension",
01690 transfer_usage, NULL, &cli_oss_transfer_deprecated },
01691
01692 { { "console", "send", "text", NULL },
01693 console_sendtext, "Send text to the remote device",
01694 sendtext_usage, NULL, &cli_oss_send_text_deprecated },
01695
01696 { { "console", "autoanswer", NULL },
01697 console_autoanswer, "Sets/displays autoanswer",
01698 autoanswer_usage, autoanswer_complete, &cli_oss_autoanswer_deprecated },
01699
01700 { { "console", "boost", NULL },
01701 do_boost, "Sets/displays mic boost in dB",
01702 NULL, NULL, &cli_oss_boost_deprecated },
01703
01704 { { "console", "active", NULL },
01705 console_active, "Sets/displays active console",
01706 active_usage, NULL, &cli_oss_active_deprecated },
01707 };
01708
01709
01710
01711
01712
01713
01714 static void store_mixer(struct chan_oss_pvt *o, char *s)
01715 {
01716 int i;
01717
01718 for (i = 0; i < strlen(s); i++) {
01719 if (!isalnum(s[i]) && index(" \t-/", s[i]) == NULL) {
01720 ast_log(LOG_WARNING, "Suspect char %c in mixer cmd, ignoring:\n\t%s\n", s[i], s);
01721 return;
01722 }
01723 }
01724 if (o->mixer_cmd)
01725 free(o->mixer_cmd);
01726 o->mixer_cmd = ast_strdup(s);
01727 ast_log(LOG_WARNING, "setting mixer %s\n", s);
01728 }
01729
01730
01731
01732
01733 static void store_callerid(struct chan_oss_pvt *o, char *s)
01734 {
01735 ast_callerid_split(s, o->cid_name, sizeof(o->cid_name), o->cid_num, sizeof(o->cid_num));
01736 }
01737
01738
01739
01740
01741 static struct chan_oss_pvt *store_config(struct ast_config *cfg, char *ctg)
01742 {
01743 struct ast_variable *v;
01744 struct chan_oss_pvt *o;
01745
01746 if (ctg == NULL) {
01747 o = &oss_default;
01748 ctg = "general";
01749 } else {
01750 if (!(o = ast_calloc(1, sizeof(*o))))
01751 return NULL;
01752 *o = oss_default;
01753
01754 if (strcmp(ctg, "general") == 0) {
01755 o->name = ast_strdup("dsp");
01756 oss_active = o->name;
01757 goto openit;
01758 }
01759 o->name = ast_strdup(ctg);
01760 }
01761
01762 strcpy(o->mohinterpret, "default");
01763
01764 o->lastopen = ast_tvnow();
01765
01766 for (v = ast_variable_browse(cfg, ctg); v; v = v->next) {
01767 M_START(v->name, v->value);
01768
01769
01770 if (!ast_jb_read_conf(&global_jbconf, v->name, v->value))
01771 continue;
01772
01773 M_BOOL("autoanswer", o->autoanswer)
01774 M_BOOL("autohangup", o->autohangup)
01775 M_BOOL("overridecontext", o->overridecontext)
01776 M_STR("device", o->device)
01777 M_UINT("frags", o->frags)
01778 M_UINT("debug", oss_debug)
01779 M_UINT("queuesize", o->queuesize)
01780 M_STR("context", o->ctx)
01781 M_STR("language", o->language)
01782 M_STR("mohinterpret", o->mohinterpret)
01783 M_STR("extension", o->ext)
01784 M_F("mixer", store_mixer(o, v->value))
01785 M_F("callerid", store_callerid(o, v->value))
01786 M_F("boost", store_boost(o, v->value))
01787 M_END(;
01788 );
01789 }
01790 if (ast_strlen_zero(o->device))
01791 ast_copy_string(o->device, DEV_DSP, sizeof(o->device));
01792 if (o->mixer_cmd) {
01793 char *cmd;
01794
01795 if (asprintf(&cmd, "mixer %s", o->mixer_cmd) < 0) {
01796 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
01797 } else {
01798 ast_log(LOG_WARNING, "running [%s]\n", cmd);
01799 if (system(cmd) < 0) {
01800 ast_log(LOG_WARNING, "system() failed: %s\n", strerror(errno));
01801 }
01802 free(cmd);
01803 }
01804 }
01805 if (o == &oss_default)
01806 return NULL;
01807
01808 openit:
01809 #if TRYOPEN
01810 if (setformat(o, O_RDWR) < 0) {
01811 if (option_verbose > 0) {
01812 ast_verbose(VERBOSE_PREFIX_2 "Device %s not detected\n", ctg);
01813 ast_verbose(VERBOSE_PREFIX_2 "Turn off OSS support by adding " "'noload=chan_oss.so' in /etc/asterisk/modules.conf\n");
01814 }
01815 goto error;
01816 }
01817 if (o->duplex != M_FULL)
01818 ast_log(LOG_WARNING, "XXX I don't work right with non " "full-duplex sound cards XXX\n");
01819 #endif
01820 if (pipe(o->sndcmd) != 0) {
01821 ast_log(LOG_ERROR, "Unable to create pipe\n");
01822 goto error;
01823 }
01824 ast_pthread_create_background(&o->sthread, NULL, sound_thread, o);
01825
01826 if (o != &oss_default) {
01827 o->next = oss_default.next;
01828 oss_default.next = o;
01829 }
01830 return o;
01831
01832 error:
01833 if (o != &oss_default)
01834 free(o);
01835 return NULL;
01836 }
01837
01838 static int load_module(void)
01839 {
01840 struct ast_config *cfg = NULL;
01841 char *ctg = NULL;
01842
01843
01844 memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
01845
01846
01847 if (!(cfg = ast_config_load(config))) {
01848 ast_log(LOG_NOTICE, "Unable to load config %s\n", config);
01849 return AST_MODULE_LOAD_DECLINE;
01850 }
01851
01852 do {
01853 store_config(cfg, ctg);
01854 } while ( (ctg = ast_category_browse(cfg, ctg)) != NULL);
01855
01856 ast_config_destroy(cfg);
01857
01858 if (find_desc(oss_active) == NULL) {
01859 ast_log(LOG_NOTICE, "Device %s not found\n", oss_active);
01860
01861
01862 return AST_MODULE_LOAD_FAILURE;
01863 }
01864
01865 if (ast_channel_register(&oss_tech)) {
01866 ast_log(LOG_ERROR, "Unable to register channel type 'OSS'\n");
01867 return AST_MODULE_LOAD_FAILURE;
01868 }
01869
01870 ast_cli_register_multiple(cli_oss, sizeof(cli_oss) / sizeof(struct ast_cli_entry));
01871
01872 return AST_MODULE_LOAD_SUCCESS;
01873 }
01874
01875
01876 static int unload_module(void)
01877 {
01878 struct chan_oss_pvt *o;
01879
01880 ast_channel_unregister(&oss_tech);
01881 ast_cli_unregister_multiple(cli_oss, sizeof(cli_oss) / sizeof(struct ast_cli_entry));
01882
01883 for (o = oss_default.next; o; o = o->next) {
01884 close(o->sounddev);
01885 if (o->sndcmd[0] > 0) {
01886 close(o->sndcmd[0]);
01887 close(o->sndcmd[1]);
01888 }
01889 if (o->owner)
01890 ast_softhangup(o->owner, AST_SOFTHANGUP_APPUNLOAD);
01891 if (o->owner)
01892 return -1;
01893
01894
01895 }
01896 return 0;
01897 }
01898
01899 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "OSS Console Channel Driver");