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