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: 291862 $")
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 #include <signal.h>
00054
00055 #ifdef __linux
00056 #include <linux/soundcard.h>
00057 #elif defined(__FreeBSD__)
00058 #include <sys/soundcard.h>
00059 #else
00060 #include <soundcard.h>
00061 #endif
00062
00063 #include "asterisk/lock.h"
00064 #include "asterisk/frame.h"
00065 #include "asterisk/logger.h"
00066 #include "asterisk/callerid.h"
00067 #include "asterisk/channel.h"
00068 #include "asterisk/module.h"
00069 #include "asterisk/options.h"
00070 #include "asterisk/pbx.h"
00071 #include "asterisk/config.h"
00072 #include "asterisk/cli.h"
00073 #include "asterisk/utils.h"
00074 #include "asterisk/causes.h"
00075 #include "asterisk/endian.h"
00076 #include "asterisk/stringfields.h"
00077 #include "asterisk/abstract_jb.h"
00078 #include "asterisk/musiconhold.h"
00079
00080
00081 #include "busy_tone.h"
00082 #include "ring_tone.h"
00083 #include "ring10.h"
00084 #include "answer.h"
00085
00086
00087 static struct ast_jb_conf default_jbconf =
00088 {
00089 .flags = 0,
00090 .max_size = -1,
00091 .resync_threshold = -1,
00092 .impl = "",
00093 };
00094 static struct ast_jb_conf global_jbconf;
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
00214 #define M_START(var, val) \
00215 char *__s = var; char *__val = val;
00216 #define M_END(x) x;
00217 #define M_F(tag, f) if (!strcasecmp((__s), tag)) { f; } else
00218 #define M_BOOL(tag, dst) M_F(tag, (dst) = ast_true(__val) )
00219 #define M_UINT(tag, dst) M_F(tag, (dst) = strtoul(__val, NULL, 0) )
00220 #define M_STR(tag, dst) M_F(tag, ast_copy_string(dst, __val, sizeof(dst)))
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
00252 #define FRAME_SIZE 160
00253 #define QUEUE_SIZE 10
00254
00255 #if defined(__FreeBSD__)
00256 #define FRAGS 0x8
00257 #else
00258 #define FRAGS ( ( (6 * 5) << 16 ) | 0x6 )
00259 #endif
00260
00261
00262
00263
00264
00265 #define TEXT_SIZE 256
00266
00267 #if 0
00268 #define TRYOPEN 1
00269 #endif
00270 #define O_CLOSE 0x444
00271
00272 #if defined( __OpenBSD__ ) || defined( __NetBSD__ )
00273 #define DEV_DSP "/dev/audio"
00274 #else
00275 #define DEV_DSP "/dev/dsp"
00276 #endif
00277
00278 #ifndef MIN
00279 #define MIN(a,b) ((a) < (b) ? (a) : (b))
00280 #endif
00281 #ifndef MAX
00282 #define MAX(a,b) ((a) > (b) ? (a) : (b))
00283 #endif
00284
00285 static char *config = "oss.conf";
00286
00287 static int oss_debug;
00288
00289
00290
00291
00292
00293
00294 struct sound {
00295 int ind;
00296 char *desc;
00297 short *data;
00298 int datalen;
00299 int samplen;
00300 int silencelen;
00301 int repeat;
00302 };
00303
00304 static struct sound sounds[] = {
00305 { AST_CONTROL_RINGING, "RINGING", ringtone, sizeof(ringtone)/2, 16000, 32000, 1 },
00306 { AST_CONTROL_BUSY, "BUSY", busy, sizeof(busy)/2, 4000, 4000, 1 },
00307 { AST_CONTROL_CONGESTION, "CONGESTION", busy, sizeof(busy)/2, 2000, 2000, 1 },
00308 { AST_CONTROL_RING, "RING10", ring10, sizeof(ring10)/2, 16000, 32000, 1 },
00309 { AST_CONTROL_ANSWER, "ANSWER", answer, sizeof(answer)/2, 2200, 0, 0 },
00310 { -1, NULL, 0, 0, 0, 0 },
00311 };
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321 struct chan_oss_pvt {
00322 struct chan_oss_pvt *next;
00323
00324 char *name;
00325
00326
00327
00328
00329
00330
00331
00332 int sndcmd[2];
00333 int cursound;
00334 int sampsent;
00335 int nosound;
00336
00337 int total_blocks;
00338 int sounddev;
00339 enum { M_UNSET, M_FULL, M_READ, M_WRITE } duplex;
00340 int autoanswer;
00341 int autohangup;
00342 int hookstate;
00343 char *mixer_cmd;
00344 unsigned int queuesize;
00345 unsigned int frags;
00346
00347 int warned;
00348 #define WARN_used_blocks 1
00349 #define WARN_speed 2
00350 #define WARN_frag 4
00351 int w_errors;
00352 struct timeval lastopen;
00353
00354 int overridecontext;
00355 int mute;
00356
00357
00358
00359
00360 #define BOOST_SCALE (1<<9)
00361 #define BOOST_MAX 40
00362 int boost;
00363 char device[64];
00364
00365 pthread_t sthread;
00366
00367 struct ast_channel *owner;
00368 char ext[AST_MAX_EXTENSION];
00369 char ctx[AST_MAX_CONTEXT];
00370 char language[MAX_LANGUAGE];
00371 char cid_name[256];
00372 char cid_num[256];
00373 char mohinterpret[MAX_MUSICCLASS];
00374
00375
00376 char oss_write_buf[FRAME_SIZE * 2];
00377 int oss_write_dst;
00378
00379
00380
00381 char oss_read_buf[FRAME_SIZE * 2 + AST_FRIENDLY_OFFSET];
00382 int readpos;
00383 struct ast_frame read_f;
00384 };
00385
00386 static struct chan_oss_pvt oss_default = {
00387 .cursound = -1,
00388 .sounddev = -1,
00389 .duplex = M_UNSET,
00390 .autoanswer = 1,
00391 .autohangup = 1,
00392 .queuesize = QUEUE_SIZE,
00393 .frags = FRAGS,
00394 .ext = "s",
00395 .ctx = "default",
00396 .readpos = AST_FRIENDLY_OFFSET,
00397 .lastopen = { 0, 0 },
00398 .boost = BOOST_SCALE,
00399 };
00400
00401 static char *oss_active;
00402
00403 static int setformat(struct chan_oss_pvt *o, int mode);
00404
00405 static struct ast_channel *oss_request(const char *type, int format, void *data, 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 int res;
00608 struct pollfd pfd[2] = { { .fd = o->sndcmd[0], .events = POLLIN }, { .fd = o->sounddev, .events = 0 } };
00609
00610 pthread_testcancel();
00611
00612 if (o->cursound > -1 && o->sounddev < 0) {
00613 setformat(o, O_RDWR);
00614 } else if (o->cursound == -1 && o->owner == NULL) {
00615 setformat(o, O_CLOSE);
00616 }
00617 if (o->sounddev > -1) {
00618 if (!o->owner) {
00619 pfd[1].events |= POLLIN;
00620 }
00621 if (o->cursound > -1) {
00622 pfd[1].events |= POLLOUT;
00623 }
00624 }
00625 res = ast_poll(pfd, 2, -1);
00626 pthread_testcancel();
00627 if (res < 1) {
00628 ast_log(LOG_WARNING, "poll() failed: %s\n", strerror(errno));
00629 sleep(1);
00630 continue;
00631 }
00632 if (pfd[0].revents & POLLIN) {
00633
00634 int i, what = -1;
00635
00636 if (read(o->sndcmd[0], &what, sizeof(what)) != sizeof(what)) {
00637 pthread_testcancel();
00638 ast_log(LOG_WARNING, "read() failed: %s\n", strerror(errno));
00639 continue;
00640 }
00641 for (i = 0; sounds[i].ind != -1; i++) {
00642 if (sounds[i].ind == what) {
00643 o->cursound = i;
00644 o->sampsent = 0;
00645 o->nosound = 1;
00646 break;
00647 }
00648 }
00649 if (sounds[i].ind == -1)
00650 ast_log(LOG_WARNING, "invalid sound index: %d\n", what);
00651 }
00652 if (o->sounddev > -1) {
00653 if (pfd[1].revents & POLLIN) {
00654 if (read(o->sounddev, ign, sizeof(ign)) < 0) {
00655 }
00656 }
00657 if (pfd[1].revents & POLLOUT) {
00658 send_sound(o);
00659 }
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 o->hookstate = 1;
00812 } else {
00813 ast_verbose("<< Type 'answer' to answer, or use 'autoanswer' for future calls >> \n");
00814 f.frametype = AST_FRAME_CONTROL;
00815 f.subclass = AST_CONTROL_RINGING;
00816 ast_queue_frame(c, &f);
00817 ring(o, AST_CONTROL_RING);
00818 }
00819 return 0;
00820 }
00821
00822
00823
00824
00825 static int oss_answer(struct ast_channel *c)
00826 {
00827 struct chan_oss_pvt *o = c->tech_pvt;
00828
00829 ast_verbose(" << Console call has been answered >> \n");
00830 #if 0
00831
00832 ring(o, AST_CONTROL_ANSWER);
00833 #endif
00834 ast_setstate(c, AST_STATE_UP);
00835 o->cursound = -1;
00836 o->nosound = 0;
00837 o->hookstate = 1;
00838 return 0;
00839 }
00840
00841 static int oss_hangup(struct ast_channel *c)
00842 {
00843 struct chan_oss_pvt *o = c->tech_pvt;
00844
00845 o->cursound = -1;
00846 o->nosound = 0;
00847 c->tech_pvt = NULL;
00848 o->owner = NULL;
00849 ast_verbose(" << Hangup on console >> \n");
00850 ast_module_unref(ast_module_info->self);
00851 if (o->hookstate) {
00852 if (o->autoanswer || o->autohangup) {
00853
00854 o->hookstate = 0;
00855 setformat(o, O_CLOSE);
00856 } else {
00857
00858 ring(o, AST_CONTROL_CONGESTION);
00859 }
00860 }
00861 return 0;
00862 }
00863
00864
00865 static int oss_write(struct ast_channel *c, struct ast_frame *f)
00866 {
00867 int src;
00868 struct chan_oss_pvt *o = c->tech_pvt;
00869
00870
00871 if (o->nosound)
00872 return 0;
00873
00874 o->cursound = -1;
00875
00876
00877
00878
00879
00880
00881 src = 0;
00882 while (src < f->datalen) {
00883
00884 int l = sizeof(o->oss_write_buf) - o->oss_write_dst;
00885
00886 if (f->datalen - src >= l) {
00887 memcpy(o->oss_write_buf + o->oss_write_dst, f->data + src, l);
00888 soundcard_writeframe(o, (short *) o->oss_write_buf);
00889 src += l;
00890 o->oss_write_dst = 0;
00891 } else {
00892 l = f->datalen - src;
00893 memcpy(o->oss_write_buf + o->oss_write_dst, f->data + src, l);
00894 src += l;
00895 o->oss_write_dst += l;
00896 }
00897 }
00898 return 0;
00899 }
00900
00901 static struct ast_frame *oss_read(struct ast_channel *c)
00902 {
00903 int res;
00904 struct chan_oss_pvt *o = c->tech_pvt;
00905 struct ast_frame *f = &o->read_f;
00906
00907
00908
00909 bzero(f, sizeof(struct ast_frame));
00910 f->frametype = AST_FRAME_NULL;
00911 f->src = oss_tech.type;
00912
00913 res = read(o->sounddev, o->oss_read_buf + o->readpos, sizeof(o->oss_read_buf) - o->readpos);
00914 if (res < 0)
00915 return f;
00916
00917 o->readpos += res;
00918 if (o->readpos < sizeof(o->oss_read_buf))
00919 return f;
00920
00921 if (o->mute)
00922 return f;
00923
00924 o->readpos = AST_FRIENDLY_OFFSET;
00925 if (c->_state != AST_STATE_UP)
00926 return f;
00927
00928 f->frametype = AST_FRAME_VOICE;
00929 f->subclass = AST_FORMAT_SLINEAR;
00930 f->samples = FRAME_SIZE;
00931 f->datalen = FRAME_SIZE * 2;
00932 f->data = o->oss_read_buf + AST_FRIENDLY_OFFSET;
00933 if (o->boost != BOOST_SCALE) {
00934 int i, x;
00935 int16_t *p = (int16_t *) f->data;
00936 for (i = 0; i < f->samples; i++) {
00937 x = (p[i] * o->boost) / BOOST_SCALE;
00938 if (x > 32767)
00939 x = 32767;
00940 else if (x < -32768)
00941 x = -32768;
00942 p[i] = x;
00943 }
00944 }
00945
00946 f->offset = AST_FRIENDLY_OFFSET;
00947 return f;
00948 }
00949
00950 static int oss_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
00951 {
00952 struct chan_oss_pvt *o = newchan->tech_pvt;
00953 o->owner = newchan;
00954 return 0;
00955 }
00956
00957 static int oss_indicate(struct ast_channel *c, int cond, const void *data, size_t datalen)
00958 {
00959 struct chan_oss_pvt *o = c->tech_pvt;
00960 int res = -1;
00961
00962 switch (cond) {
00963 case AST_CONTROL_BUSY:
00964 case AST_CONTROL_CONGESTION:
00965 case AST_CONTROL_RINGING:
00966 res = cond;
00967 break;
00968
00969 case -1:
00970 o->cursound = -1;
00971 o->nosound = 0;
00972 return 0;
00973
00974 case AST_CONTROL_VIDUPDATE:
00975 res = -1;
00976 break;
00977 case AST_CONTROL_HOLD:
00978 ast_verbose(" << Console Has Been Placed on Hold >> \n");
00979 ast_moh_start(c, data, o->mohinterpret);
00980 break;
00981 case AST_CONTROL_UNHOLD:
00982 ast_verbose(" << Console Has Been Retrieved from Hold >> \n");
00983 ast_moh_stop(c);
00984 break;
00985 case AST_CONTROL_SRCUPDATE:
00986 break;
00987 default:
00988 ast_log(LOG_WARNING, "Don't know how to display condition %d on %s\n", cond, c->name);
00989 return -1;
00990 }
00991
00992 if (res > -1)
00993 ring(o, res);
00994
00995 return 0;
00996 }
00997
00998
00999
01000
01001 static struct ast_channel *oss_new(struct chan_oss_pvt *o, char *ext, char *ctx, int state)
01002 {
01003 struct ast_channel *c;
01004
01005 c = ast_channel_alloc(1, state, o->cid_num, o->cid_name, "", ext, ctx, 0, "Console/%s", o->device + 5);
01006 if (c == NULL)
01007 return NULL;
01008 c->tech = &oss_tech;
01009 if (o->sounddev < 0)
01010 setformat(o, O_RDWR);
01011 c->fds[0] = o->sounddev;
01012 c->nativeformats = AST_FORMAT_SLINEAR;
01013 c->readformat = AST_FORMAT_SLINEAR;
01014 c->writeformat = AST_FORMAT_SLINEAR;
01015 c->tech_pvt = o;
01016
01017 if (!ast_strlen_zero(o->language))
01018 ast_string_field_set(c, language, o->language);
01019
01020
01021 c->cid.cid_ani = ast_strdup(o->cid_num);
01022 if (!ast_strlen_zero(ext))
01023 c->cid.cid_dnid = ast_strdup(ext);
01024
01025 o->owner = c;
01026 ast_module_ref(ast_module_info->self);
01027 ast_jb_configure(c, &global_jbconf);
01028 if (state != AST_STATE_DOWN) {
01029 if (ast_pbx_start(c)) {
01030 ast_log(LOG_WARNING, "Unable to start PBX on %s\n", c->name);
01031 ast_hangup(c);
01032 o->owner = c = NULL;
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, "%30lf", &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]) && strchr(" \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_DECLINE;
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, *next;
01879
01880 ast_channel_unregister(&oss_tech);
01881 ast_cli_unregister_multiple(cli_oss, sizeof(cli_oss) / sizeof(struct ast_cli_entry));
01882
01883 o = oss_default.next;
01884 while (o) {
01885 if (o->owner) {
01886 ast_softhangup(o->owner, AST_SOFTHANGUP_APPUNLOAD);
01887
01888 sched_yield();
01889 }
01890 if (o->owner) {
01891 return -1;
01892 }
01893 oss_default.next = o->next;
01894 if (o->sthread > 0) {
01895 pthread_cancel(o->sthread);
01896 pthread_kill(o->sthread, SIGURG);
01897 pthread_join(o->sthread, NULL);
01898 }
01899 close(o->sounddev);
01900 if (o->sndcmd[0] > 0) {
01901 close(o->sndcmd[0]);
01902 close(o->sndcmd[1]);
01903 }
01904 next = o->next;
01905 if (o->sthread > 0) {
01906 ast_free(o);
01907 }
01908 o = next;
01909 }
01910 return 0;
01911 }
01912
01913 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "OSS Console Channel Driver");