Version 0.1.3 from FTP
[asterisk/asterisk.git] / channels / chan_oss.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Use /dev/dsp as a channel, and the console to command it :).
5  *
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
8  * writing a driver.
9  * 
10  * Copyright (C) 1999, Mark Spencer
11  *
12  * Mark Spencer <markster@linux-support.net>
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License
16  */
17
18 #include <asterisk/frame.h>
19 #include <asterisk/logger.h>
20 #include <asterisk/channel.h>
21 #include <asterisk/module.h>
22 #include <asterisk/channel_pvt.h>
23 #include <asterisk/options.h>
24 #include <asterisk/pbx.h>
25 #include <asterisk/config.h>
26 #include <asterisk/cli.h>
27 #include <unistd.h>
28 #include <fcntl.h>
29 #include <errno.h>
30 #include <sys/ioctl.h>
31 #include <sys/time.h>
32 #include <string.h>
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <linux/soundcard.h>
36
37 /* Which device to use */
38 #define DEV_DSP "/dev/dsp"
39
40 /* Lets use 160 sample frames, just like GSM.  */
41 #define FRAME_SIZE 160
42
43 /* When you set the frame size, you have to come up with
44    the right buffer format as well. */
45 /* 5 64-byte frames = one frame */
46 #define BUFFER_FMT ((buffersize * 5) << 16) | (0x0006);
47
48 /* Don't switch between read/write modes faster than every 300 ms */
49 #define MIN_SWITCH_TIME 600
50
51 static struct timeval lasttime;
52
53 static int usecnt;
54 static int needanswer = 0;
55 static int needhangup = 0;
56 static int silencesuppression = 0;
57 static int silencethreshold = 1000;
58
59 static char digits[80] = "";
60 static char text2send[80] = "";
61
62 static pthread_mutex_t usecnt_lock = PTHREAD_MUTEX_INITIALIZER;
63
64 static char *type = "Console";
65 static char *desc = "OSS Console Channel Driver";
66 static char *tdesc = "OSS Console Channel Driver";
67 static char *config = "oss.conf";
68
69 static char context[AST_MAX_EXTENSION] = "default";
70 static char language[MAX_LANGUAGE] = "";
71 static char exten[AST_MAX_EXTENSION] = "s";
72
73 /* Some pipes to prevent overflow */
74 static int funnel[2];
75 static pthread_mutex_t sound_lock = PTHREAD_MUTEX_INITIALIZER;
76 static pthread_t silly;
77
78 static struct chan_oss_pvt {
79         /* We only have one OSS structure -- near sighted perhaps, but it
80            keeps this driver as simple as possible -- as it should be. */
81         struct ast_channel *owner;
82         char exten[AST_MAX_EXTENSION];
83         char context[AST_MAX_EXTENSION];
84 } oss;
85
86 static int time_has_passed()
87 {
88         struct timeval tv;
89         int ms;
90         gettimeofday(&tv, NULL);
91         ms = (tv.tv_sec - lasttime.tv_sec) * 1000 +
92                         (tv.tv_usec - lasttime.tv_usec) / 1000;
93         if (ms > MIN_SWITCH_TIME)
94                 return -1;
95         return 0;
96 }
97
98 /* Number of buffers...  Each is FRAMESIZE/8 ms long.  For example
99    with 160 sample frames, and a buffer size of 3, we have a 60ms buffer, 
100    usually plenty. */
101
102
103 #define MAX_BUFFER_SIZE 100
104 static int buffersize = 3;
105
106 static int full_duplex = 0;
107
108 /* Are we reading or writing (simulated full duplex) */
109 static int readmode = 1;
110
111 /* File descriptor for sound device */
112 static int sounddev = -1;
113
114 static int autoanswer = 1;
115  
116 static int calc_loudness(short *frame)
117 {
118         int sum = 0;
119         int x;
120         for (x=0;x<FRAME_SIZE;x++) {
121                 if (frame[x] < 0)
122                         sum -= frame[x];
123                 else
124                         sum += frame[x];
125         }
126         sum = sum/FRAME_SIZE;
127         return sum;
128 }
129
130 static int silence_suppress(short *buf)
131 {
132 #define SILBUF 3
133         int loudness;
134         static int silentframes = 0;
135         static char silbuf[FRAME_SIZE * 2 * SILBUF];
136         static int silbufcnt=0;
137         if (!silencesuppression)
138                 return 0;
139         loudness = calc_loudness((short *)(buf));
140         if (option_debug)
141                 ast_log(LOG_DEBUG, "loudness is %d\n", loudness);
142         if (loudness < silencethreshold) {
143                 silentframes++;
144                 silbufcnt++;
145                 /* Keep track of the last few bits of silence so we can play
146                    them as lead-in when the time is right */
147                 if (silbufcnt >= SILBUF) {
148                         /* Make way for more buffer */
149                         memmove(silbuf, silbuf + FRAME_SIZE * 2, FRAME_SIZE * 2 * (SILBUF - 1));
150                         silbufcnt--;
151                 }
152                 memcpy(silbuf + FRAME_SIZE * 2 * silbufcnt, buf, FRAME_SIZE * 2);
153                 if (silentframes > 10) {
154                         /* We've had plenty of silence, so compress it now */
155                         return 1;
156                 }
157         } else {
158                 silentframes=0;
159                 /* Write any buffered silence we have, it may have something
160                    important */
161                 if (silbufcnt) {
162                         write(funnel[1], silbuf, silbufcnt * FRAME_SIZE);
163                         silbufcnt = 0;
164                 }
165         }
166         return 0;
167 }
168
169 static void *silly_thread(void *ignore)
170 {
171         char buf[FRAME_SIZE * 2];
172         int pos=0;
173         int res=0;
174         /* Read from the sound device, and write to the pipe. */
175         for (;;) {
176                 /* Give the writer a better shot at the lock */
177 #if 0
178                 usleep(1000);
179 #endif          
180                 pthread_testcancel();
181                 pthread_mutex_lock(&sound_lock);
182                 res = read(sounddev, buf + pos, FRAME_SIZE * 2 - pos);
183                 pthread_mutex_unlock(&sound_lock);
184                 if (res > 0) {
185                         pos += res;
186                         if (pos == FRAME_SIZE * 2) {
187                                 if (needhangup || needanswer || strlen(digits) || 
188                                     !silence_suppress((short *)buf)) {
189                                         res = write(funnel[1], buf, sizeof(buf));
190                                 }
191                                 pos = 0;
192                         }
193                 } else {
194                         close(funnel[1]);
195                         break;
196                 }
197                 pthread_testcancel();
198         }
199         return NULL;
200 }
201
202 static int setformat(void)
203 {
204         int fmt, desired, res, fd = sounddev;
205         static int warnedalready = 0;
206         static int warnedalready2 = 0;
207         pthread_mutex_lock(&sound_lock);
208         fmt = AFMT_S16_LE;
209         res = ioctl(fd, SNDCTL_DSP_SETFMT, &fmt);
210         if (res < 0) {
211                 ast_log(LOG_WARNING, "Unable to set format to 16-bit signed\n");
212                 pthread_mutex_unlock(&sound_lock);
213                 return -1;
214         }
215         res = ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0);
216         if (res >= 0) {
217                 if (option_verbose > 1) 
218                         ast_verbose(VERBOSE_PREFIX_2 "Console is full duplex\n");
219                 full_duplex = -1;
220         }
221         fmt = 0;
222         res = ioctl(fd, SNDCTL_DSP_STEREO, &fmt);
223         if (res < 0) {
224                 ast_log(LOG_WARNING, "Failed to set audio device to mono\n");
225                 pthread_mutex_unlock(&sound_lock);
226                 return -1;
227         }
228         /* 8000 Hz desired */
229         desired = 8000;
230         fmt = desired;
231         res = ioctl(fd, SNDCTL_DSP_SPEED, &fmt);
232         if (res < 0) {
233                 ast_log(LOG_WARNING, "Failed to set audio device to mono\n");
234                 pthread_mutex_unlock(&sound_lock);
235                 return -1;
236         }
237         if (fmt != desired) {
238                 if (!warnedalready++)
239                         ast_log(LOG_WARNING, "Requested %d Hz, got %d Hz -- sound may be choppy\n", desired, fmt);
240         }
241 #if 1
242         fmt = BUFFER_FMT;
243         res = ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &fmt);
244         if (res < 0) {
245                 if (!warnedalready2++)
246                         ast_log(LOG_WARNING, "Unable to set fragment size -- sound may be choppy\n");
247         }
248 #endif
249         pthread_mutex_unlock(&sound_lock);
250         return 0;
251 }
252
253 static int soundcard_setoutput(int force)
254 {
255         /* Make sure the soundcard is in output mode.  */
256         int fd = sounddev;
257         if (full_duplex || (!readmode && !force))
258                 return 0;
259         pthread_mutex_lock(&sound_lock);
260         readmode = 0;
261         if (force || time_has_passed()) {
262                 ioctl(sounddev, SNDCTL_DSP_RESET);
263                 /* Keep the same fd reserved by closing the sound device and copying stdin at the same
264                    time. */
265                 /* dup2(0, sound); */ 
266                 close(sounddev);
267                 fd = open(DEV_DSP, O_WRONLY);
268                 if (fd < 0) {
269                         ast_log(LOG_WARNING, "Unable to re-open DSP device: %s\n", strerror(errno));
270                         pthread_mutex_unlock(&sound_lock);
271                         return -1;
272                 }
273                 /* dup2 will close the original and make fd be sound */
274                 if (dup2(fd, sounddev) < 0) {
275                         ast_log(LOG_WARNING, "dup2() failed: %s\n", strerror(errno));
276                         pthread_mutex_unlock(&sound_lock);
277                         return -1;
278                 }
279                 if (setformat()) {
280                         pthread_mutex_unlock(&sound_lock);
281                         return -1;
282                 }
283                 pthread_mutex_unlock(&sound_lock);
284                 return 0;
285         }
286         pthread_mutex_unlock(&sound_lock);
287         return 1;
288 }
289
290 static int soundcard_setinput(int force)
291 {
292         int fd = sounddev;
293         if (full_duplex || (readmode && !force))
294                 return 0;
295         pthread_mutex_lock(&sound_lock);
296         readmode = -1;
297         if (force || time_has_passed()) {
298                 ioctl(sounddev, SNDCTL_DSP_RESET);
299                 close(sounddev);
300                 /* dup2(0, sound); */
301                 fd = open(DEV_DSP, O_RDONLY);
302                 if (fd < 0) {
303                         ast_log(LOG_WARNING, "Unable to re-open DSP device: %s\n", strerror(errno));
304                         pthread_mutex_unlock(&sound_lock);
305                         return -1;
306                 }
307                 /* dup2 will close the original and make fd be sound */
308                 if (dup2(fd, sounddev) < 0) {
309                         ast_log(LOG_WARNING, "dup2() failed: %s\n", strerror(errno));
310                         pthread_mutex_unlock(&sound_lock);
311                         return -1;
312                 }
313                 if (setformat()) {
314                         pthread_mutex_unlock(&sound_lock);
315                         return -1;
316                 }
317                 pthread_mutex_unlock(&sound_lock);
318                 return 0;
319         }
320         pthread_mutex_unlock(&sound_lock);
321         return 1;
322 }
323
324 static int soundcard_init()
325 {
326         /* Assume it's full duplex for starters */
327         int fd = open(DEV_DSP,  O_RDWR);
328         if (fd < 0) {
329                 ast_log(LOG_ERROR, "Unable to open %s: %s\n", DEV_DSP, strerror(errno));
330                 return fd;
331         }
332         gettimeofday(&lasttime, NULL);
333         sounddev = fd;
334         setformat();
335         if (!full_duplex) 
336                 soundcard_setinput(1);
337         return sounddev;
338 }
339
340 static int oss_digit(struct ast_channel *c, char digit)
341 {
342         ast_verbose( " << Console Received digit %c >> \n", digit);
343         return 0;
344 }
345
346 static int oss_text(struct ast_channel *c, char *text)
347 {
348         ast_verbose( " << Console Received text %s >> \n", text);
349         return 0;
350 }
351
352 static int oss_call(struct ast_channel *c, char *dest, int timeout)
353 {
354         ast_verbose( " << Call placed to '%s' on console >> \n", dest);
355         if (autoanswer) {
356                 ast_verbose( " << Auto-answered >> \n" );
357                 needanswer = 1;
358         } else {
359                 ast_verbose( " << Type 'answer' to answer, or use 'autoanswer' for future calls >> \n");
360         }
361         return 0;
362 }
363
364 static int oss_answer(struct ast_channel *c)
365 {
366         ast_verbose( " << Console call has been answered >> \n");
367         c->state = AST_STATE_UP;
368         return 0;
369 }
370
371 static int oss_hangup(struct ast_channel *c)
372 {
373         c->pvt->pvt = NULL;
374         oss.owner = NULL;
375         ast_verbose( " << Hangup on console >> \n");
376         pthread_mutex_lock(&usecnt_lock);
377         usecnt--;
378         pthread_mutex_unlock(&usecnt_lock);
379         needhangup = 0;
380         needanswer = 0;
381         return 0;
382 }
383
384 static int soundcard_writeframe(short *data)
385 {       
386         /* Write an exactly FRAME_SIZE sized of frame */
387         static int bufcnt = 0;
388         static char buffer[FRAME_SIZE * 2 * MAX_BUFFER_SIZE * 5];
389         struct audio_buf_info info;
390         int res;
391         int fd = sounddev;
392         static int warned=0;
393         pthread_mutex_lock(&sound_lock);
394         if (ioctl(fd, SNDCTL_DSP_GETOSPACE, &info)) {
395                 if (!warned)
396                         ast_log(LOG_WARNING, "Error reading output space\n");
397                 bufcnt = buffersize;
398                 warned++;
399         }
400         if ((info.fragments >= buffersize * 5) && (bufcnt == buffersize)) {
401                 /* We've run out of stuff, buffer again */
402                 bufcnt = 0;
403         }
404         if (bufcnt == buffersize) {
405                 /* Write sample immediately */
406                 res = write(fd, ((void *)data), FRAME_SIZE * 2);
407         } else {
408                 /* Copy the data into our buffer */
409                 res = FRAME_SIZE * 2;
410                 memcpy(buffer + (bufcnt * FRAME_SIZE * 2), data, FRAME_SIZE * 2);
411                 bufcnt++;
412                 if (bufcnt == buffersize) {
413                         res = write(fd, ((void *)buffer), FRAME_SIZE * 2 * buffersize);
414                 }
415         }
416         pthread_mutex_unlock(&sound_lock);
417         return res;
418 }
419
420
421 static int oss_write(struct ast_channel *chan, struct ast_frame *f)
422 {
423         int res;
424         static char sizbuf[8000];
425         static int sizpos = 0;
426         int len = sizpos;
427         int pos;
428         if (!full_duplex && (strlen(digits) || needhangup || needanswer)) {
429                 /* If we're half duplex, we have to switch to read mode
430                    to honor immediate needs if necessary */
431                 res = soundcard_setinput(1);
432                 if (res < 0) {
433                         ast_log(LOG_WARNING, "Unable to set device to input mode\n");
434                         return -1;
435                 }
436                 return 0;
437         }
438         res = soundcard_setoutput(0);
439         if (res < 0) {
440                 ast_log(LOG_WARNING, "Unable to set output device\n");
441                 return -1;
442         } else if (res > 0) {
443                 /* The device is still in read mode, and it's too soon to change it,
444                    so just pretend we wrote it */
445                 return 0;
446         }
447         /* We have to digest the frame in 160-byte portions */
448         if (f->datalen > sizeof(sizbuf) - sizpos) {
449                 ast_log(LOG_WARNING, "Frame too large\n");
450                 return -1;
451         }
452         memcpy(sizbuf + sizpos, f->data, f->datalen);
453         len += f->datalen;
454         pos = 0;
455         while(len - pos > FRAME_SIZE * 2) {
456                 soundcard_writeframe((short *)(sizbuf + pos));
457                 pos += FRAME_SIZE * 2;
458         }
459         if (len - pos) 
460                 memmove(sizbuf, sizbuf + pos, len - pos);
461         sizpos = len - pos;
462         return 0;
463 }
464
465 static struct ast_frame *oss_read(struct ast_channel *chan)
466 {
467         static struct ast_frame f;
468         static char buf[FRAME_SIZE * 2 + AST_FRIENDLY_OFFSET];
469         static int readpos = 0;
470         int res;
471         
472 #if 0
473         ast_log(LOG_DEBUG, "oss_read()\n");
474 #endif
475         
476         f.frametype = AST_FRAME_NULL;
477         f.subclass = 0;
478         f.timelen = 0;
479         f.datalen = 0;
480         f.data = NULL;
481         f.offset = 0;
482         f.src = type;
483         f.mallocd = 0;
484         
485         if (needhangup) {
486                 return NULL;
487         }
488         if (strlen(text2send)) {
489                 f.frametype = AST_FRAME_TEXT;
490                 f.subclass = 0;
491                 f.data = text2send;
492                 f.datalen = strlen(text2send);
493                 strcpy(text2send,"");
494                 return &f;
495         }
496         if (strlen(digits)) {
497                 f.frametype = AST_FRAME_DTMF;
498                 f.subclass = digits[0];
499                 for (res=0;res<strlen(digits);res++)
500                         digits[res] = digits[res + 1];
501                 return &f;
502         }
503         
504         if (needanswer) {
505                 needanswer = 0;
506                 f.frametype = AST_FRAME_CONTROL;
507                 f.subclass = AST_CONTROL_ANSWER;
508                 chan->state = AST_STATE_UP;
509                 return &f;
510         }
511         
512         res = soundcard_setinput(0);
513         if (res < 0) {
514                 ast_log(LOG_WARNING, "Unable to set input mode\n");
515                 return NULL;
516         }
517         if (res > 0) {
518                 /* Theoretically shouldn't happen, but anyway, return a NULL frame */
519                 return &f;
520         }
521         res = read(funnel[0], buf + AST_FRIENDLY_OFFSET + readpos, FRAME_SIZE * 2 - readpos);
522         if (res < 0) {
523                 ast_log(LOG_WARNING, "Error reading from sound device: %s\n", strerror(errno));
524                 return NULL;
525         }
526         readpos += res;
527         
528         if (readpos == FRAME_SIZE * 2) {
529                 /* A real frame */
530                 readpos = 0;
531                 f.frametype = AST_FRAME_VOICE;
532                 f.subclass = AST_FORMAT_SLINEAR;
533                 f.timelen = FRAME_SIZE / 8;
534                 f.datalen = FRAME_SIZE * 2;
535                 f.data = buf + AST_FRIENDLY_OFFSET;
536                 f.offset = AST_FRIENDLY_OFFSET;
537                 f.src = type;
538                 f.mallocd = 0;
539         }
540         return &f;
541 }
542
543 static struct ast_channel *oss_new(struct chan_oss_pvt *p, int state)
544 {
545         struct ast_channel *tmp;
546         tmp = ast_channel_alloc();
547         if (tmp) {
548                 snprintf(tmp->name, sizeof(tmp->name), "OSS/%s", DEV_DSP + 5);
549                 tmp->type = type;
550                 tmp->fd = funnel[0];
551                 tmp->format = AST_FORMAT_SLINEAR;
552                 tmp->pvt->pvt = p;
553                 tmp->pvt->send_digit = oss_digit;
554                 tmp->pvt->send_text = oss_text;
555                 tmp->pvt->hangup = oss_hangup;
556                 tmp->pvt->answer = oss_answer;
557                 tmp->pvt->read = oss_read;
558                 tmp->pvt->call = oss_call;
559                 tmp->pvt->write = oss_write;
560                 if (strlen(p->context))
561                         strncpy(tmp->context, p->context, sizeof(tmp->context));
562                 if (strlen(p->exten))
563                         strncpy(tmp->exten, p->exten, sizeof(tmp->exten));
564                 if (strlen(language))
565                         strncpy(tmp->language, language, sizeof(tmp->language));
566                 p->owner = tmp;
567                 tmp->state = state;
568                 pthread_mutex_lock(&usecnt_lock);
569                 usecnt++;
570                 pthread_mutex_unlock(&usecnt_lock);
571                 ast_update_use_count();
572                 if (state != AST_STATE_DOWN) {
573                         if (ast_pbx_start(tmp)) {
574                                 ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
575                                 ast_hangup(tmp);
576                                 tmp = NULL;
577                         }
578                 }
579         }
580         return tmp;
581 }
582
583 static struct ast_channel *oss_request(char *type, int format, void *data)
584 {
585         int oldformat = format;
586         struct ast_channel *tmp;
587         format &= AST_FORMAT_SLINEAR;
588         if (!format) {
589                 ast_log(LOG_NOTICE, "Asked to get a channel of format '%d'\n", oldformat);
590                 return NULL;
591         }
592         if (oss.owner) {
593                 ast_log(LOG_NOTICE, "Already have a call on the OSS channel\n");
594                 return NULL;
595         }
596         tmp= oss_new(&oss, AST_STATE_DOWN);
597         if (!tmp) {
598                 ast_log(LOG_WARNING, "Unable to create new OSS channel\n");
599         }
600         return tmp;
601 }
602
603 static int console_autoanswer(int fd, int argc, char *argv[])
604 {
605         if ((argc != 1) && (argc != 2))
606                 return RESULT_SHOWUSAGE;
607         if (argc == 1) {
608                 ast_cli(fd, "Auto answer is %s.\n", autoanswer ? "on" : "off");
609                 return RESULT_SUCCESS;
610         } else {
611                 if (!strcasecmp(argv[1], "on"))
612                         autoanswer = -1;
613                 else if (!strcasecmp(argv[1], "off"))
614                         autoanswer = 0;
615                 else
616                         return RESULT_SHOWUSAGE;
617         }
618         return RESULT_SUCCESS;
619 }
620
621 static char *autoanswer_complete(char *line, char *word, int pos, int state)
622 {
623 #ifndef MIN
624 #define MIN(a,b) ((a) < (b) ? (a) : (b))
625 #endif
626         switch(state) {
627         case 0:
628                 if (strlen(word) && !strncasecmp(word, "on", MIN(strlen(word), 2)))
629                         return strdup("on");
630         case 1:
631                 if (strlen(word) && !strncasecmp(word, "off", MIN(strlen(word), 3)))
632                         return strdup("off");
633         default:
634                 return NULL;
635         }
636         return NULL;
637 }
638
639 static char autoanswer_usage[] =
640 "Usage: autoanswer [on|off]\n"
641 "       Enables or disables autoanswer feature.  If used without\n"
642 "       argument, displays the current on/off status of autoanswer.\n"
643 "       The default value of autoanswer is in 'oss.conf'.\n";
644
645 static int console_answer(int fd, int argc, char *argv[])
646 {
647         if (argc != 1)
648                 return RESULT_SHOWUSAGE;
649         if (!oss.owner) {
650                 ast_cli(fd, "No one is calling us\n");
651                 return RESULT_FAILURE;
652         }
653         needanswer++;
654         return RESULT_SUCCESS;
655 }
656
657 static char sendtext_usage[] =
658 "Usage: send text <message>\n"
659 "       Sends a text message for display on the remote terminal.\n";
660
661 static int console_sendtext(int fd, int argc, char *argv[])
662 {
663         int tmparg = 1;
664         if (argc < 1)
665                 return RESULT_SHOWUSAGE;
666         if (!oss.owner) {
667                 ast_cli(fd, "No one is calling us\n");
668                 return RESULT_FAILURE;
669         }
670         if (strlen(text2send))
671                 ast_cli(fd, "Warning: message already waiting to be sent, overwriting\n");
672         strcpy(text2send, "");
673         while(tmparg <= argc) {
674                 strncat(text2send, argv[tmparg++], sizeof(text2send) - strlen(text2send));
675                 strncat(text2send, " ", sizeof(text2send) - strlen(text2send));
676         }
677         needanswer++;
678         return RESULT_SUCCESS;
679 }
680
681 static char answer_usage[] =
682 "Usage: answer\n"
683 "       Answers an incoming call on the console (OSS) channel.\n";
684
685 static int console_hangup(int fd, int argc, char *argv[])
686 {
687         if (argc != 1)
688                 return RESULT_SHOWUSAGE;
689         if (!oss.owner) {
690                 ast_cli(fd, "No call to hangup up\n");
691                 return RESULT_FAILURE;
692         }
693         needhangup++;
694         return RESULT_SUCCESS;
695 }
696
697 static char hangup_usage[] =
698 "Usage: hangup\n"
699 "       Hangs up any call currently placed on the console.\n";
700
701
702 static int console_dial(int fd, int argc, char *argv[])
703 {
704         char tmp[256], *tmp2;
705         char *mye, *myc;
706         if ((argc != 1) && (argc != 2))
707                 return RESULT_SHOWUSAGE;
708         if (oss.owner) {
709                 if (argc == 2)
710                         strncat(digits, argv[1], sizeof(digits) - strlen(digits));
711                 else {
712                         ast_cli(fd, "You're already in a call.  You can use this only to dial digits until you hangup\n");
713                         return RESULT_FAILURE;
714                 }
715                 return RESULT_SUCCESS;
716         }
717         mye = exten;
718         myc = context;
719         if (argc == 2) {
720                 strncpy(tmp, argv[1], sizeof(tmp));
721                 strtok(tmp, "@");
722                 tmp2 = strtok(NULL, "@");
723                 if (strlen(tmp))
724                         mye = tmp;
725                 if (tmp2 && strlen(tmp2))
726                         myc = tmp2;
727         }
728         if (ast_exists_extension(NULL, myc, mye, 1)) {
729                 strncpy(oss.exten, mye, sizeof(oss.exten));
730                 strncpy(oss.context, myc, sizeof(oss.context));
731                 oss_new(&oss, AST_STATE_UP);
732         } else
733                 ast_cli(fd, "No such extension '%s' in context '%s'\n", mye, myc);
734         return RESULT_SUCCESS;
735 }
736
737 static char dial_usage[] =
738 "Usage: dial [extension[@context]]\n"
739 "       Dials a given extensison (";
740
741
742 static struct ast_cli_entry myclis[] = {
743         { { "answer", NULL }, console_answer, "Answer an incoming console call", answer_usage },
744         { { "hangup", NULL }, console_hangup, "Hangup a call on the console", hangup_usage },
745         { { "dial", NULL }, console_dial, "Dial an extension on the console", dial_usage },
746         { { "send text", NULL }, console_sendtext, "Send text to the remote device", sendtext_usage },
747         { { "autoanswer", NULL }, console_autoanswer, "Sets/displays autoanswer", autoanswer_usage, autoanswer_complete }
748 };
749
750 int load_module()
751 {
752         int res;
753         int x;
754         int flags;
755         struct ast_config *cfg = ast_load(config);
756         struct ast_variable *v;
757         res = pipe(funnel);
758         if (res) {
759                 ast_log(LOG_ERROR, "Unable to create pipe\n");
760                 return -1;
761         }
762         /* We make the funnel so that writes to the funnel don't block...
763            Our "silly" thread can read to its heart content, preventing
764            recording overruns */
765         flags = fcntl(funnel[1], F_GETFL);
766 #if 0
767         fcntl(funnel[0], F_SETFL, flags | O_NONBLOCK);
768 #endif
769         fcntl(funnel[1], F_SETFL, flags | O_NONBLOCK);
770         res = soundcard_init();
771         if (res < 0) {
772                 close(funnel[1]);
773                 close(funnel[0]);
774                 return -1;
775         }
776         if (!full_duplex)
777                 ast_log(LOG_WARNING, "XXX I don't work right with non-full duplex sound cards XXX\n");
778         pthread_create(&silly, NULL, silly_thread, NULL);
779         res = ast_channel_register(type, tdesc, AST_FORMAT_SLINEAR, oss_request);
780         if (res < 0) {
781                 ast_log(LOG_ERROR, "Unable to register channel class '%s'\n", type);
782                 return -1;
783         }
784         for (x=0;x<sizeof(myclis)/sizeof(struct ast_cli_entry); x++)
785                 ast_cli_register(myclis + x);
786         if (cfg) {
787                 v = ast_variable_browse(cfg, "general");
788                 while(v) {
789                         if (!strcasecmp(v->name, "autoanswer"))
790                                 autoanswer = ast_true(v->value);
791                         else if (!strcasecmp(v->name, "silencesuppression"))
792                                 silencesuppression = ast_true(v->value);
793                         else if (!strcasecmp(v->name, "silencethreshold"))
794                                 silencethreshold = atoi(v->value);
795                         else if (!strcasecmp(v->name, "context"))
796                                 strncpy(context, v->value, sizeof(context));
797                         else if (!strcasecmp(v->name, "language"))
798                                 strncpy(language, v->value, sizeof(language));
799                         else if (!strcasecmp(v->name, "extension"))
800                                 strncpy(exten, v->value, sizeof(exten));
801                         v=v->next;
802                 }
803                 ast_destroy(cfg);
804         }
805         return 0;
806 }
807
808
809
810 int unload_module()
811 {
812         int x;
813         for (x=0;x<sizeof(myclis)/sizeof(struct ast_cli_entry); x++)
814                 ast_cli_unregister(myclis + x);
815         close(sounddev);
816         if (funnel[0] > 0) {
817                 close(funnel[0]);
818                 close(funnel[1]);
819         }
820         if (silly) {
821                 pthread_cancel(silly);
822                 pthread_join(silly, NULL);
823         }
824         if (oss.owner)
825                 ast_softhangup(oss.owner);
826         if (oss.owner)
827                 return -1;
828         return 0;
829 }
830
831 char *description()
832 {
833         return desc;
834 }
835
836 int usecount()
837 {
838         int res;
839         pthread_mutex_lock(&usecnt_lock);
840         res = usecnt;
841         pthread_mutex_unlock(&usecnt_lock);
842         return res;
843 }