2 * Asterisk -- A telephony toolkit for Linux.
4 * Use /dev/dsp as a channel, and the console to command it :).
6 * The full-duplex "simulation" is pretty weak. This is generally a
7 * VERY BADLY WRITTEN DRIVER so please don't use it as a model for
10 * Copyright (C) 1999 - 2005, Digium, Inc.
12 * Mark Spencer <markster@digium.com>
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License
18 #include <asterisk/lock.h>
19 #include <asterisk/frame.h>
20 #include <asterisk/logger.h>
21 #include <asterisk/channel.h>
22 #include <asterisk/module.h>
23 #include <asterisk/channel_pvt.h>
24 #include <asterisk/options.h>
25 #include <asterisk/pbx.h>
26 #include <asterisk/config.h>
27 #include <asterisk/cli.h>
28 #include <asterisk/utils.h>
29 #include <asterisk/causes.h>
33 #include <sys/ioctl.h>
39 #include <linux/soundcard.h>
40 #elif defined(__FreeBSD__)
41 #include <sys/soundcard.h>
43 #include <soundcard.h>
50 /* Which device to use */
51 #if defined( __OpenBSD__ ) || defined( __NetBSD__ )
52 #define DEV_DSP "/dev/audio"
54 #define DEV_DSP "/dev/dsp"
57 /* Lets use 160 sample frames, just like GSM. */
58 #define FRAME_SIZE 160
60 /* When you set the frame size, you have to come up with
61 the right buffer format as well. */
62 /* 5 64-byte frames = one frame */
63 #define BUFFER_FMT ((buffersize * 10) << 16) | (0x0006);
65 /* Don't switch between read/write modes faster than every 300 ms */
66 #define MIN_SWITCH_TIME 600
68 static struct timeval lasttime;
71 static int silencesuppression = 0;
72 static int silencethreshold = 1000;
73 static int playbackonly = 0;
76 AST_MUTEX_DEFINE_STATIC(usecnt_lock);
78 static char *type = "Console";
79 static char *desc = "OSS Console Channel Driver";
80 static char *tdesc = "OSS Console Channel Driver";
81 static char *config = "oss.conf";
83 static char context[AST_MAX_EXTENSION] = "default";
84 static char language[MAX_LANGUAGE] = "";
85 static char exten[AST_MAX_EXTENSION] = "s";
87 static int hookstate=0;
89 static short silence[FRAME_SIZE] = {0, };
100 static struct sound sounds[] = {
101 { AST_CONTROL_RINGING, ringtone, sizeof(ringtone)/2, 16000, 32000, 1 },
102 { AST_CONTROL_BUSY, busy, sizeof(busy)/2, 4000, 4000, 1 },
103 { AST_CONTROL_CONGESTION, busy, sizeof(busy)/2, 2000, 2000, 1 },
104 { AST_CONTROL_RING, ring10, sizeof(ring10)/2, 16000, 32000, 1 },
105 { AST_CONTROL_ANSWER, answer, sizeof(answer)/2, 2200, 0, 0 },
108 /* Sound command pipe */
109 static int sndcmd[2];
111 static struct chan_oss_pvt {
112 /* We only have one OSS structure -- near sighted perhaps, but it
113 keeps this driver as simple as possible -- as it should be. */
114 struct ast_channel *owner;
115 char exten[AST_MAX_EXTENSION];
116 char context[AST_MAX_EXTENSION];
119 static int time_has_passed(void)
123 gettimeofday(&tv, NULL);
124 ms = (tv.tv_sec - lasttime.tv_sec) * 1000 +
125 (tv.tv_usec - lasttime.tv_usec) / 1000;
126 if (ms > MIN_SWITCH_TIME)
131 /* Number of buffers... Each is FRAMESIZE/8 ms long. For example
132 with 160 sample frames, and a buffer size of 3, we have a 60ms buffer,
135 static pthread_t sthread;
137 #define MAX_BUFFER_SIZE 100
138 static int buffersize = 3;
140 static int full_duplex = 0;
142 /* Are we reading or writing (simulated full duplex) */
143 static int readmode = 1;
145 /* File descriptor for sound device */
146 static int sounddev = -1;
148 static int autoanswer = 1;
151 static int calc_loudness(short *frame)
155 for (x=0;x<FRAME_SIZE;x++) {
161 sum = sum/FRAME_SIZE;
166 static int cursound = -1;
167 static int sampsent = 0;
168 static int silencelen=0;
170 static int nosound=0;
172 static int send_sound(void)
174 short myframe[FRAME_SIZE];
175 int total = FRAME_SIZE;
182 res = ioctl(sounddev, SNDCTL_DSP_GETOSPACE ,&abi);
184 ast_log(LOG_WARNING, "Unable to read output space\n");
187 /* Calculate how many samples we can send, max */
188 if (total > (abi.fragments * abi.fragsize / 2))
189 total = abi.fragments * abi.fragsize / 2;
191 if (sampsent < sounds[cursound].samplen) {
195 if (amt > (sounds[cursound].datalen - offset))
196 amt = sounds[cursound].datalen - offset;
197 memcpy(myframe + myoff, sounds[cursound].data + offset, amt * 2);
202 if (offset >= sounds[cursound].datalen)
205 /* Set it up for silence */
206 if (sampsent >= sounds[cursound].samplen)
207 silencelen = sounds[cursound].silencelen;
210 if (silencelen > 0) {
214 if (sounds[cursound].repeat) {
225 res = write(sounddev, frame, res * 2);
233 static void *sound_thread(void *unused)
240 if (read(sounddev, ign, sizeof(sounddev)) < 0)
241 ast_log(LOG_WARNING, "Read error on sound device: %s\n", strerror(errno));
246 FD_SET(sndcmd[0], &rfds);
248 FD_SET(sounddev, &rfds);
253 FD_SET(sounddev, &wfds);
257 res = ast_select(max + 1, &rfds, &wfds, NULL, NULL);
259 ast_log(LOG_WARNING, "select failed: %s\n", strerror(errno));
262 if (FD_ISSET(sndcmd[0], &rfds)) {
263 read(sndcmd[0], &cursound, sizeof(cursound));
268 if (FD_ISSET(sounddev, &rfds)) {
270 if (read(sounddev, ign, sizeof(ign)) < 0)
271 ast_log(LOG_WARNING, "Read error on sound device: %s\n", strerror(errno));
273 if (FD_ISSET(sounddev, &wfds))
275 ast_log(LOG_WARNING, "Failed to write sound\n");
282 static int silence_suppress(short *buf)
286 static int silentframes = 0;
287 static char silbuf[FRAME_SIZE * 2 * SILBUF];
288 static int silbufcnt=0;
289 if (!silencesuppression)
291 loudness = calc_loudness((short *)(buf));
293 ast_log(LOG_DEBUG, "loudness is %d\n", loudness);
294 if (loudness < silencethreshold) {
297 /* Keep track of the last few bits of silence so we can play
298 them as lead-in when the time is right */
299 if (silbufcnt >= SILBUF) {
300 /* Make way for more buffer */
301 memmove(silbuf, silbuf + FRAME_SIZE * 2, FRAME_SIZE * 2 * (SILBUF - 1));
304 memcpy(silbuf + FRAME_SIZE * 2 * silbufcnt, buf, FRAME_SIZE * 2);
305 if (silentframes > 10) {
306 /* We've had plenty of silence, so compress it now */
311 /* Write any buffered silence we have, it may have something
314 write(sounddev, silbuf, silbufcnt * FRAME_SIZE);
322 static int setformat(void)
324 int fmt, desired, res, fd = sounddev;
325 static int warnedalready = 0;
326 static int warnedalready2 = 0;
328 res = ioctl(fd, SNDCTL_DSP_SETFMT, &fmt);
330 ast_log(LOG_WARNING, "Unable to set format to 16-bit signed\n");
333 res = ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0);
335 /* Check to see if duplex set (FreeBSD Bug)*/
336 res = ioctl(fd, SNDCTL_DSP_GETCAPS, &fmt);
338 if ((fmt & DSP_CAP_DUPLEX) && !res) {
339 if (option_verbose > 1)
340 ast_verbose(VERBOSE_PREFIX_2 "Console is full duplex\n");
344 res = ioctl(fd, SNDCTL_DSP_STEREO, &fmt);
346 ast_log(LOG_WARNING, "Failed to set audio device to mono\n");
349 /* 8000 Hz desired */
352 res = ioctl(fd, SNDCTL_DSP_SPEED, &fmt);
354 ast_log(LOG_WARNING, "Failed to set audio device to mono\n");
357 if (fmt != desired) {
358 if (!warnedalready++)
359 ast_log(LOG_WARNING, "Requested %d Hz, got %d Hz -- sound may be choppy\n", desired, fmt);
363 res = ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &fmt);
365 if (!warnedalready2++)
366 ast_log(LOG_WARNING, "Unable to set fragment size -- sound may be choppy\n");
372 static int soundcard_setoutput(int force)
374 /* Make sure the soundcard is in output mode. */
376 if (full_duplex || (!readmode && !force))
379 if (force || time_has_passed()) {
380 ioctl(sounddev, SNDCTL_DSP_RESET, 0);
381 /* Keep the same fd reserved by closing the sound device and copying stdin at the same
383 /* dup2(0, sound); */
385 fd = open(DEV_DSP, O_WRONLY |O_NONBLOCK);
387 ast_log(LOG_WARNING, "Unable to re-open DSP device: %s\n", strerror(errno));
390 /* dup2 will close the original and make fd be sound */
391 if (dup2(fd, sounddev) < 0) {
392 ast_log(LOG_WARNING, "dup2() failed: %s\n", strerror(errno));
403 static int soundcard_setinput(int force)
406 if (full_duplex || (readmode && !force))
409 if (force || time_has_passed()) {
410 ioctl(sounddev, SNDCTL_DSP_RESET, 0);
412 /* dup2(0, sound); */
413 fd = open(DEV_DSP, O_RDONLY | O_NONBLOCK);
415 ast_log(LOG_WARNING, "Unable to re-open DSP device: %s\n", strerror(errno));
418 /* dup2 will close the original and make fd be sound */
419 if (dup2(fd, sounddev) < 0) {
420 ast_log(LOG_WARNING, "dup2() failed: %s\n", strerror(errno));
431 static int soundcard_init(void)
433 /* Assume it's full duplex for starters */
434 int fd = open(DEV_DSP, O_RDWR | O_NONBLOCK);
436 ast_log(LOG_WARNING, "Unable to open %s: %s\n", DEV_DSP, strerror(errno));
439 gettimeofday(&lasttime, NULL);
443 soundcard_setinput(1);
447 static int oss_digit(struct ast_channel *c, char digit)
449 ast_verbose( " << Console Received digit %c >> \n", digit);
453 static int oss_text(struct ast_channel *c, char *text)
455 ast_verbose( " << Console Received text %s >> \n", text);
459 static int oss_call(struct ast_channel *c, char *dest, int timeout)
462 struct ast_frame f = { 0, };
463 ast_verbose( " << Call placed to '%s' on console >> \n", dest);
465 ast_verbose( " << Auto-answered >> \n" );
466 f.frametype = AST_FRAME_CONTROL;
467 f.subclass = AST_CONTROL_ANSWER;
468 ast_queue_frame(c, &f);
471 ast_verbose( " << Type 'answer' to answer, or use 'autoanswer' for future calls >> \n");
472 f.frametype = AST_FRAME_CONTROL;
473 f.subclass = AST_CONTROL_RINGING;
474 ast_queue_frame(c, &f);
475 write(sndcmd[1], &res, sizeof(res));
480 static void answer_sound(void)
485 write(sndcmd[1], &res, sizeof(res));
489 static int oss_answer(struct ast_channel *c)
491 ast_verbose( " << Console call has been answered >> \n");
493 ast_setstate(c, AST_STATE_UP);
499 static int oss_hangup(struct ast_channel *c)
505 ast_verbose( " << Hangup on console >> \n");
506 ast_mutex_lock(&usecnt_lock);
508 ast_mutex_unlock(&usecnt_lock);
511 /* Assume auto-hangup too */
514 /* Make congestion noise */
516 write(sndcmd[1], &res, sizeof(res));
522 static int soundcard_writeframe(short *data)
524 /* Write an exactly FRAME_SIZE sized of frame */
525 static int bufcnt = 0;
526 static short buffer[FRAME_SIZE * MAX_BUFFER_SIZE * 5];
527 struct audio_buf_info info;
531 if (ioctl(fd, SNDCTL_DSP_GETOSPACE, &info)) {
533 ast_log(LOG_WARNING, "Error reading output space\n");
537 if ((info.fragments >= buffersize * 5) && (bufcnt == buffersize)) {
538 /* We've run out of stuff, buffer again */
541 if (bufcnt == buffersize) {
542 /* Write sample immediately */
543 res = write(fd, ((void *)data), FRAME_SIZE * 2);
545 /* Copy the data into our buffer */
546 res = FRAME_SIZE * 2;
547 memcpy(buffer + (bufcnt * FRAME_SIZE), data, FRAME_SIZE * 2);
549 if (bufcnt == buffersize) {
550 res = write(fd, ((void *)buffer), FRAME_SIZE * 2 * buffersize);
557 static int oss_write(struct ast_channel *chan, struct ast_frame *f)
560 static char sizbuf[8000];
561 static int sizpos = 0;
564 /* Immediately return if no sound is enabled */
567 /* Stop any currently playing sound */
569 if (!full_duplex && !playbackonly) {
570 /* If we're half duplex, we have to switch to read mode
571 to honor immediate needs if necessary. But if we are in play
572 back only mode, then we don't switch because the console
573 is only being used one way -- just to playback something. */
574 res = soundcard_setinput(1);
576 ast_log(LOG_WARNING, "Unable to set device to input mode\n");
581 res = soundcard_setoutput(0);
583 ast_log(LOG_WARNING, "Unable to set output device\n");
585 } else if (res > 0) {
586 /* The device is still in read mode, and it's too soon to change it,
587 so just pretend we wrote it */
590 /* We have to digest the frame in 160-byte portions */
591 if (f->datalen > sizeof(sizbuf) - sizpos) {
592 ast_log(LOG_WARNING, "Frame too large\n");
595 memcpy(sizbuf + sizpos, f->data, f->datalen);
598 while(len - pos > FRAME_SIZE * 2) {
599 soundcard_writeframe((short *)(sizbuf + pos));
600 pos += FRAME_SIZE * 2;
603 memmove(sizbuf, sizbuf + pos, len - pos);
608 static struct ast_frame *oss_read(struct ast_channel *chan)
610 static struct ast_frame f;
611 static char buf[FRAME_SIZE * 2 + AST_FRIENDLY_OFFSET];
612 static int readpos = 0;
616 ast_log(LOG_DEBUG, "oss_read()\n");
619 f.frametype = AST_FRAME_NULL;
627 f.delivery.tv_sec = 0;
628 f.delivery.tv_usec = 0;
630 res = soundcard_setinput(0);
632 ast_log(LOG_WARNING, "Unable to set input mode\n");
636 /* Theoretically shouldn't happen, but anyway, return a NULL frame */
639 res = read(sounddev, buf + AST_FRIENDLY_OFFSET + readpos, FRAME_SIZE * 2 - readpos);
641 ast_log(LOG_WARNING, "Error reading from sound device (If you're running 'artsd' then kill it): %s\n", strerror(errno));
649 if (readpos >= FRAME_SIZE * 2) {
652 if (chan->_state != AST_STATE_UP) {
653 /* Don't transmit unless it's up */
656 f.frametype = AST_FRAME_VOICE;
657 f.subclass = AST_FORMAT_SLINEAR;
658 f.samples = FRAME_SIZE;
659 f.datalen = FRAME_SIZE * 2;
660 f.data = buf + AST_FRIENDLY_OFFSET;
661 f.offset = AST_FRIENDLY_OFFSET;
664 f.delivery.tv_sec = 0;
665 f.delivery.tv_usec = 0;
667 { static int fd = -1;
669 fd = open("output.raw", O_RDWR | O_TRUNC | O_CREAT);
670 write(fd, f.data, f.datalen);
677 static int oss_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
679 struct chan_oss_pvt *p = newchan->pvt->pvt;
684 static int oss_indicate(struct ast_channel *chan, int cond)
688 case AST_CONTROL_BUSY:
691 case AST_CONTROL_CONGESTION:
694 case AST_CONTROL_RINGING:
701 ast_log(LOG_WARNING, "Don't know how to display condition %d on %s\n", cond, chan->name);
705 write(sndcmd[1], &res, sizeof(res));
710 static struct ast_channel *oss_new(struct chan_oss_pvt *p, int state)
712 struct ast_channel *tmp;
713 tmp = ast_channel_alloc(1);
715 snprintf(tmp->name, sizeof(tmp->name), "OSS/%s", DEV_DSP + 5);
717 tmp->fds[0] = sounddev;
718 tmp->nativeformats = AST_FORMAT_SLINEAR;
719 tmp->readformat = AST_FORMAT_SLINEAR;
720 tmp->writeformat = AST_FORMAT_SLINEAR;
722 tmp->pvt->send_digit = oss_digit;
723 tmp->pvt->send_text = oss_text;
724 tmp->pvt->hangup = oss_hangup;
725 tmp->pvt->answer = oss_answer;
726 tmp->pvt->read = oss_read;
727 tmp->pvt->call = oss_call;
728 tmp->pvt->write = oss_write;
729 tmp->pvt->indicate = oss_indicate;
730 tmp->pvt->fixup = oss_fixup;
731 if (strlen(p->context))
732 strncpy(tmp->context, p->context, sizeof(tmp->context)-1);
733 if (strlen(p->exten))
734 strncpy(tmp->exten, p->exten, sizeof(tmp->exten)-1);
735 if (strlen(language))
736 strncpy(tmp->language, language, sizeof(tmp->language)-1);
738 ast_setstate(tmp, state);
739 ast_mutex_lock(&usecnt_lock);
741 ast_mutex_unlock(&usecnt_lock);
742 ast_update_use_count();
743 if (state != AST_STATE_DOWN) {
744 if (ast_pbx_start(tmp)) {
745 ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
754 static struct ast_channel *oss_request(const char *type, int format, void *data, int *cause)
756 int oldformat = format;
757 struct ast_channel *tmp;
758 format &= AST_FORMAT_SLINEAR;
760 ast_log(LOG_NOTICE, "Asked to get a channel of format '%d'\n", oldformat);
764 ast_log(LOG_NOTICE, "Already have a call on the OSS channel\n");
765 *cause = AST_CAUSE_BUSY;
768 tmp= oss_new(&oss, AST_STATE_DOWN);
770 ast_log(LOG_WARNING, "Unable to create new OSS channel\n");
775 static int console_autoanswer(int fd, int argc, char *argv[])
777 if ((argc != 1) && (argc != 2))
778 return RESULT_SHOWUSAGE;
780 ast_cli(fd, "Auto answer is %s.\n", autoanswer ? "on" : "off");
781 return RESULT_SUCCESS;
783 if (!strcasecmp(argv[1], "on"))
785 else if (!strcasecmp(argv[1], "off"))
788 return RESULT_SHOWUSAGE;
790 return RESULT_SUCCESS;
793 static char *autoanswer_complete(char *line, char *word, int pos, int state)
796 #define MIN(a,b) ((a) < (b) ? (a) : (b))
800 if (strlen(word) && !strncasecmp(word, "on", MIN(strlen(word), 2)))
803 if (strlen(word) && !strncasecmp(word, "off", MIN(strlen(word), 3)))
804 return strdup("off");
811 static char autoanswer_usage[] =
812 "Usage: autoanswer [on|off]\n"
813 " Enables or disables autoanswer feature. If used without\n"
814 " argument, displays the current on/off status of autoanswer.\n"
815 " The default value of autoanswer is in 'oss.conf'.\n";
817 static int console_answer(int fd, int argc, char *argv[])
819 struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
821 return RESULT_SHOWUSAGE;
823 ast_cli(fd, "No one is calling us\n");
824 return RESULT_FAILURE;
828 ast_queue_frame(oss.owner, &f);
830 return RESULT_SUCCESS;
833 static char sendtext_usage[] =
834 "Usage: send text <message>\n"
835 " Sends a text message for display on the remote terminal.\n";
837 static int console_sendtext(int fd, int argc, char *argv[])
840 char text2send[256] = "";
841 struct ast_frame f = { 0, };
843 return RESULT_SHOWUSAGE;
845 ast_cli(fd, "No one is calling us\n");
846 return RESULT_FAILURE;
848 if (strlen(text2send))
849 ast_cli(fd, "Warning: message already waiting to be sent, overwriting\n");
851 while(tmparg < argc) {
852 strncat(text2send, argv[tmparg++], sizeof(text2send) - strlen(text2send) - 1);
853 strncat(text2send, " ", sizeof(text2send) - strlen(text2send) - 1);
855 if (strlen(text2send)) {
856 f.frametype = AST_FRAME_TEXT;
859 f.datalen = strlen(text2send);
860 ast_queue_frame(oss.owner, &f);
862 return RESULT_SUCCESS;
865 static char answer_usage[] =
867 " Answers an incoming call on the console (OSS) channel.\n";
869 static int console_hangup(int fd, int argc, char *argv[])
872 return RESULT_SHOWUSAGE;
874 if (!oss.owner && !hookstate) {
875 ast_cli(fd, "No call to hangup up\n");
876 return RESULT_FAILURE;
880 ast_queue_hangup(oss.owner);
882 return RESULT_SUCCESS;
885 static int console_flash(int fd, int argc, char *argv[])
887 struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_FLASH };
889 return RESULT_SHOWUSAGE;
892 ast_cli(fd, "No call to flash\n");
893 return RESULT_FAILURE;
897 ast_queue_frame(oss.owner, &f);
899 return RESULT_SUCCESS;
902 static char hangup_usage[] =
904 " Hangs up any call currently placed on the console.\n";
907 static char flash_usage[] =
909 " Flashes the call currently placed on the console.\n";
911 static int console_dial(int fd, int argc, char *argv[])
913 char tmp[256], *tmp2;
916 struct ast_frame f = { AST_FRAME_DTMF, 0 };
917 if ((argc != 1) && (argc != 2))
918 return RESULT_SHOWUSAGE;
921 for (x=0;x<strlen(argv[1]);x++) {
922 f.subclass = argv[1][x];
923 ast_queue_frame(oss.owner, &f);
926 ast_cli(fd, "You're already in a call. You can use this only to dial digits until you hangup\n");
927 return RESULT_FAILURE;
929 return RESULT_SUCCESS;
935 strncpy(tmp, argv[1], sizeof(tmp)-1);
937 strsep(&stringp, "@");
938 tmp2 = strsep(&stringp, "@");
941 if (tmp2 && strlen(tmp2))
944 if (ast_exists_extension(NULL, myc, mye, 1, NULL)) {
945 strncpy(oss.exten, mye, sizeof(oss.exten)-1);
946 strncpy(oss.context, myc, sizeof(oss.context)-1);
948 oss_new(&oss, AST_STATE_RINGING);
950 ast_cli(fd, "No such extension '%s' in context '%s'\n", mye, myc);
951 return RESULT_SUCCESS;
954 static char dial_usage[] =
955 "Usage: dial [extension[@context]]\n"
956 " Dials a given extensison (and context if specified)\n";
958 static int console_transfer(int fd, int argc, char *argv[])
963 return RESULT_SHOWUSAGE;
964 if (oss.owner && ast_bridged_channel(oss.owner)) {
965 strncpy(tmp, argv[1], sizeof(tmp) - 1);
966 context = strchr(tmp, '@');
971 context = oss.owner->context;
972 if (ast_exists_extension(ast_bridged_channel(oss.owner), context, tmp, 1, ast_bridged_channel(oss.owner)->cid.cid_num)) {
973 ast_cli(fd, "Whee, transferring %s to %s@%s.\n",
974 ast_bridged_channel(oss.owner)->name, tmp, context);
975 if (ast_async_goto(ast_bridged_channel(oss.owner), context, tmp, 1))
976 ast_cli(fd, "Failed to transfer :(\n");
978 ast_cli(fd, "No such extension exists\n");
981 ast_cli(fd, "There is no call to transfer\n");
983 return RESULT_SUCCESS;
986 static char transfer_usage[] =
987 "Usage: transfer <extension>[@context]\n"
988 " Transfers the currently connected call to the given extension (and\n"
989 "context if specified)\n";
991 static struct ast_cli_entry myclis[] = {
992 { { "answer", NULL }, console_answer, "Answer an incoming console call", answer_usage },
993 { { "hangup", NULL }, console_hangup, "Hangup a call on the console", hangup_usage },
994 { { "flash", NULL }, console_flash, "Flash a call on the console", flash_usage },
995 { { "dial", NULL }, console_dial, "Dial an extension on the console", dial_usage },
996 { { "transfer", NULL }, console_transfer, "Transfer a call to a different extension", transfer_usage },
997 { { "send", "text", NULL }, console_sendtext, "Send text to the remote device", sendtext_usage },
998 { { "autoanswer", NULL }, console_autoanswer, "Sets/displays autoanswer", autoanswer_usage, autoanswer_complete }
1005 struct ast_config *cfg;
1006 struct ast_variable *v;
1009 ast_log(LOG_ERROR, "Unable to create pipe\n");
1012 res = soundcard_init();
1014 if (option_verbose > 1) {
1015 ast_verbose(VERBOSE_PREFIX_2 "No sound card detected -- console channel will be unavailable\n");
1016 ast_verbose(VERBOSE_PREFIX_2 "Turn off OSS support by adding 'noload=chan_oss.so' in /etc/asterisk/modules.conf\n");
1021 ast_log(LOG_WARNING, "XXX I don't work right with non-full duplex sound cards XXX\n");
1022 res = ast_channel_register(type, tdesc, AST_FORMAT_SLINEAR, oss_request);
1024 ast_log(LOG_ERROR, "Unable to register channel class '%s'\n", type);
1027 for (x=0;x<sizeof(myclis)/sizeof(struct ast_cli_entry); x++)
1028 ast_cli_register(myclis + x);
1029 if ((cfg = ast_load(config))) {
1030 v = ast_variable_browse(cfg, "general");
1032 if (!strcasecmp(v->name, "autoanswer"))
1033 autoanswer = ast_true(v->value);
1034 else if (!strcasecmp(v->name, "silencesuppression"))
1035 silencesuppression = ast_true(v->value);
1036 else if (!strcasecmp(v->name, "silencethreshold"))
1037 silencethreshold = atoi(v->value);
1038 else if (!strcasecmp(v->name, "context"))
1039 strncpy(context, v->value, sizeof(context)-1);
1040 else if (!strcasecmp(v->name, "language"))
1041 strncpy(language, v->value, sizeof(language)-1);
1042 else if (!strcasecmp(v->name, "extension"))
1043 strncpy(exten, v->value, sizeof(exten)-1);
1044 else if (!strcasecmp(v->name, "playbackonly"))
1045 playbackonly = ast_true(v->value);
1050 ast_pthread_create(&sthread, NULL, sound_thread, NULL);
1059 for (x=0;x<sizeof(myclis)/sizeof(struct ast_cli_entry); x++)
1060 ast_cli_unregister(myclis + x);
1062 if (sndcmd[0] > 0) {
1067 ast_softhangup(oss.owner, AST_SOFTHANGUP_APPUNLOAD);
1081 ast_mutex_lock(&usecnt_lock);
1083 ast_mutex_unlock(&usecnt_lock);
1089 return ASTERISK_GPL_KEY;