297c578c1e692fe440bb175f7a8e36d144e1716c
[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 #include "busy.h"
37 #include "ringtone.h"
38 #include "ring10.h"
39 #include "answer.h"
40
41 /* Which device to use */
42 #define DEV_DSP "/dev/dsp"
43
44 /* Lets use 160 sample frames, just like GSM.  */
45 #define FRAME_SIZE 160
46
47 /* When you set the frame size, you have to come up with
48    the right buffer format as well. */
49 /* 5 64-byte frames = one frame */
50 #define BUFFER_FMT ((buffersize * 10) << 16) | (0x0006);
51
52 /* Don't switch between read/write modes faster than every 300 ms */
53 #define MIN_SWITCH_TIME 600
54
55 static struct timeval lasttime;
56
57 static int usecnt;
58 static int needanswer = 0;
59 static int needringing = 0;
60 static int needhangup = 0;
61 static int silencesuppression = 0;
62 static int silencethreshold = 1000;
63
64 static char digits[80] = "";
65 static char text2send[80] = "";
66
67 static pthread_mutex_t usecnt_lock = PTHREAD_MUTEX_INITIALIZER;
68
69 static char *type = "Console";
70 static char *desc = "OSS Console Channel Driver";
71 static char *tdesc = "OSS Console Channel Driver";
72 static char *config = "oss.conf";
73
74 static char context[AST_MAX_EXTENSION] = "default";
75 static char language[MAX_LANGUAGE] = "";
76 static char exten[AST_MAX_EXTENSION] = "s";
77
78 /* Command pipe */
79 static int cmd[2];
80
81 int hookstate=0;
82
83 static short silence[FRAME_SIZE] = {0, };
84
85 struct sound {
86         int ind;
87         short *data;
88         int datalen;
89         int samplen;
90         int silencelen;
91         int repeat;
92 };
93
94 static struct sound sounds[] = {
95         { AST_CONTROL_RINGING, ringtone, sizeof(ringtone)/2, 16000, 32000, 1 },
96         { AST_CONTROL_BUSY, busy, sizeof(busy)/2, 4000, 4000, 1 },
97         { AST_CONTROL_CONGESTION, busy, sizeof(busy)/2, 2000, 2000, 1 },
98         { AST_CONTROL_RING, ring10, sizeof(ring10)/2, 16000, 32000, 1 },
99         { AST_CONTROL_ANSWER, answer, sizeof(answer)/2, 2200, 0, 0 },
100 };
101
102 /* Sound command pipe */
103 static int sndcmd[2];
104
105 static struct chan_oss_pvt {
106         /* We only have one OSS structure -- near sighted perhaps, but it
107            keeps this driver as simple as possible -- as it should be. */
108         struct ast_channel *owner;
109         char exten[AST_MAX_EXTENSION];
110         char context[AST_MAX_EXTENSION];
111 } oss;
112
113 static int time_has_passed()
114 {
115         struct timeval tv;
116         int ms;
117         gettimeofday(&tv, NULL);
118         ms = (tv.tv_sec - lasttime.tv_sec) * 1000 +
119                         (tv.tv_usec - lasttime.tv_usec) / 1000;
120         if (ms > MIN_SWITCH_TIME)
121                 return -1;
122         return 0;
123 }
124
125 /* Number of buffers...  Each is FRAMESIZE/8 ms long.  For example
126    with 160 sample frames, and a buffer size of 3, we have a 60ms buffer, 
127    usually plenty. */
128
129 pthread_t sthread;
130
131 #define MAX_BUFFER_SIZE 100
132 static int buffersize = 3;
133
134 static int full_duplex = 0;
135
136 /* Are we reading or writing (simulated full duplex) */
137 static int readmode = 1;
138
139 /* File descriptor for sound device */
140 static int sounddev = -1;
141
142 static int autoanswer = 1;
143  
144 static int calc_loudness(short *frame)
145 {
146         int sum = 0;
147         int x;
148         for (x=0;x<FRAME_SIZE;x++) {
149                 if (frame[x] < 0)
150                         sum -= frame[x];
151                 else
152                         sum += frame[x];
153         }
154         sum = sum/FRAME_SIZE;
155         return sum;
156 }
157
158 static int cursound = -1;
159 static int sampsent = 0;
160 static int silencelen=0;
161 static int offset=0;
162 static int nosound=0;
163
164 static int send_sound(void)
165 {
166         short myframe[FRAME_SIZE];
167         int total = FRAME_SIZE;
168         short *frame = NULL;
169         int amt=0;
170         int res;
171         int myoff;
172         audio_buf_info abi;
173         if (cursound > -1) {
174                 res = ioctl(sounddev, SNDCTL_DSP_GETOSPACE ,&abi);
175                 if (res) {
176                         ast_log(LOG_WARNING, "Unable to read output space\n");
177                         return -1;
178                 }
179                 /* Calculate how many samples we can send, max */
180                 if (total > (abi.fragments * abi.fragsize / 2)) 
181                         total = abi.fragments * abi.fragsize / 2;
182                 res = total;
183                 if (sampsent < sounds[cursound].samplen) {
184                         myoff=0;
185                         while(total) {
186                                 amt = total;
187                                 if (amt > (sounds[cursound].datalen - offset)) 
188                                         amt = sounds[cursound].datalen - offset;
189                                 memcpy(myframe + myoff, sounds[cursound].data + offset, amt * 2);
190                                 total -= amt;
191                                 offset += amt;
192                                 sampsent += amt;
193                                 myoff += amt;
194                                 if (offset >= sounds[cursound].datalen)
195                                         offset = 0;
196                         }
197                         /* Set it up for silence */
198                         if (sampsent >= sounds[cursound].samplen) 
199                                 silencelen = sounds[cursound].silencelen;
200                         frame = myframe;
201                 } else {
202                         if (silencelen > 0) {
203                                 frame = silence;
204                                 silencelen -= res;
205                         } else {
206                                 if (sounds[cursound].repeat) {
207                                         /* Start over */
208                                         sampsent = 0;
209                                         offset = 0;
210                                 } else {
211                                         cursound = -1;
212                                         nosound = 0;
213                                 }
214                         }
215                 }
216                 res = write(sounddev, frame, res * 2);
217                 if (res > 0)
218                         return 0;
219                 return res;
220         }
221         return 0;
222 }
223
224 static void *sound_thread(void *unused)
225 {
226         fd_set rfds;
227         fd_set wfds;
228         int max;
229         int res;
230         for(;;) {
231                 FD_ZERO(&rfds);
232                 FD_ZERO(&wfds);
233                 max = sndcmd[0];
234                 FD_SET(sndcmd[0], &rfds);
235                 if (cursound > -1) {
236                         FD_SET(sounddev, &wfds);
237                         if (sounddev > max)
238                                 max = sounddev;
239                 }
240                 res = select(max + 1, &rfds, &wfds, NULL, NULL);
241                 if (res < 1) {
242                         ast_log(LOG_WARNING, "select failed: %s\n", strerror(errno));
243                         continue;
244                 }
245                 if (FD_ISSET(sndcmd[0], &rfds)) {
246                         read(sndcmd[0], &cursound, sizeof(cursound));
247                         silencelen = 0;
248                         offset = 0;
249                         sampsent = 0;
250                 }
251                 if (FD_ISSET(sounddev, &wfds))
252                         if (send_sound())
253                                 ast_log(LOG_WARNING, "Failed to write sound\n");
254         }
255         /* Never reached */
256         return NULL;
257 }
258
259 #if 0
260 static int silence_suppress(short *buf)
261 {
262 #define SILBUF 3
263         int loudness;
264         static int silentframes = 0;
265         static char silbuf[FRAME_SIZE * 2 * SILBUF];
266         static int silbufcnt=0;
267         if (!silencesuppression)
268                 return 0;
269         loudness = calc_loudness((short *)(buf));
270         if (option_debug)
271                 ast_log(LOG_DEBUG, "loudness is %d\n", loudness);
272         if (loudness < silencethreshold) {
273                 silentframes++;
274                 silbufcnt++;
275                 /* Keep track of the last few bits of silence so we can play
276                    them as lead-in when the time is right */
277                 if (silbufcnt >= SILBUF) {
278                         /* Make way for more buffer */
279                         memmove(silbuf, silbuf + FRAME_SIZE * 2, FRAME_SIZE * 2 * (SILBUF - 1));
280                         silbufcnt--;
281                 }
282                 memcpy(silbuf + FRAME_SIZE * 2 * silbufcnt, buf, FRAME_SIZE * 2);
283                 if (silentframes > 10) {
284                         /* We've had plenty of silence, so compress it now */
285                         return 1;
286                 }
287         } else {
288                 silentframes=0;
289                 /* Write any buffered silence we have, it may have something
290                    important */
291                 if (silbufcnt) {
292                         write(sounddev, silbuf, silbufcnt * FRAME_SIZE);
293                         silbufcnt = 0;
294                 }
295         }
296         return 0;
297 }
298 #endif
299
300 static int setformat(void)
301 {
302         int fmt, desired, res, fd = sounddev;
303         static int warnedalready = 0;
304         static int warnedalready2 = 0;
305         fmt = AFMT_S16_LE;
306         res = ioctl(fd, SNDCTL_DSP_SETFMT, &fmt);
307         if (res < 0) {
308                 ast_log(LOG_WARNING, "Unable to set format to 16-bit signed\n");
309                 return -1;
310         }
311         res = ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0);
312         if (res >= 0) {
313                 if (option_verbose > 1) 
314                         ast_verbose(VERBOSE_PREFIX_2 "Console is full duplex\n");
315                 full_duplex = -1;
316         }
317         fmt = 0;
318         res = ioctl(fd, SNDCTL_DSP_STEREO, &fmt);
319         if (res < 0) {
320                 ast_log(LOG_WARNING, "Failed to set audio device to mono\n");
321                 return -1;
322         }
323         /* 8000 Hz desired */
324         desired = 8000;
325         fmt = desired;
326         res = ioctl(fd, SNDCTL_DSP_SPEED, &fmt);
327         if (res < 0) {
328                 ast_log(LOG_WARNING, "Failed to set audio device to mono\n");
329                 return -1;
330         }
331         if (fmt != desired) {
332                 if (!warnedalready++)
333                         ast_log(LOG_WARNING, "Requested %d Hz, got %d Hz -- sound may be choppy\n", desired, fmt);
334         }
335 #if 1
336         fmt = BUFFER_FMT;
337         res = ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &fmt);
338         if (res < 0) {
339                 if (!warnedalready2++)
340                         ast_log(LOG_WARNING, "Unable to set fragment size -- sound may be choppy\n");
341         }
342 #endif
343         return 0;
344 }
345
346 static int soundcard_setoutput(int force)
347 {
348         /* Make sure the soundcard is in output mode.  */
349         int fd = sounddev;
350         if (full_duplex || (!readmode && !force))
351                 return 0;
352         readmode = 0;
353         if (force || time_has_passed()) {
354                 ioctl(sounddev, SNDCTL_DSP_RESET);
355                 /* Keep the same fd reserved by closing the sound device and copying stdin at the same
356                    time. */
357                 /* dup2(0, sound); */ 
358                 close(sounddev);
359                 fd = open(DEV_DSP, O_WRONLY |O_NONBLOCK);
360                 if (fd < 0) {
361                         ast_log(LOG_WARNING, "Unable to re-open DSP device: %s\n", strerror(errno));
362                         return -1;
363                 }
364                 /* dup2 will close the original and make fd be sound */
365                 if (dup2(fd, sounddev) < 0) {
366                         ast_log(LOG_WARNING, "dup2() failed: %s\n", strerror(errno));
367                         return -1;
368                 }
369                 if (setformat()) {
370                         return -1;
371                 }
372                 return 0;
373         }
374         return 1;
375 }
376
377 static int soundcard_setinput(int force)
378 {
379         int fd = sounddev;
380         if (full_duplex || (readmode && !force))
381                 return 0;
382         readmode = -1;
383         if (force || time_has_passed()) {
384                 ioctl(sounddev, SNDCTL_DSP_RESET);
385                 close(sounddev);
386                 /* dup2(0, sound); */
387                 fd = open(DEV_DSP, O_RDONLY | O_NONBLOCK);
388                 if (fd < 0) {
389                         ast_log(LOG_WARNING, "Unable to re-open DSP device: %s\n", strerror(errno));
390                         return -1;
391                 }
392                 /* dup2 will close the original and make fd be sound */
393                 if (dup2(fd, sounddev) < 0) {
394                         ast_log(LOG_WARNING, "dup2() failed: %s\n", strerror(errno));
395                         return -1;
396                 }
397                 if (setformat()) {
398                         return -1;
399                 }
400                 return 0;
401         }
402         return 1;
403 }
404
405 static int soundcard_init()
406 {
407         /* Assume it's full duplex for starters */
408         int fd = open(DEV_DSP,  O_RDWR | O_NONBLOCK);
409         if (fd < 0) {
410                 ast_log(LOG_WARNING, "Unable to open %s: %s\n", DEV_DSP, strerror(errno));
411                 return fd;
412         }
413         gettimeofday(&lasttime, NULL);
414         sounddev = fd;
415         setformat();
416         if (!full_duplex) 
417                 soundcard_setinput(1);
418         return sounddev;
419 }
420
421 static int oss_digit(struct ast_channel *c, char digit)
422 {
423         ast_verbose( " << Console Received digit %c >> \n", digit);
424         return 0;
425 }
426
427 static int oss_text(struct ast_channel *c, char *text)
428 {
429         ast_verbose( " << Console Received text %s >> \n", text);
430         return 0;
431 }
432
433 static int oss_call(struct ast_channel *c, char *dest, int timeout)
434 {
435         int res = 3;
436         ast_verbose( " << Call placed to '%s' on console >> \n", dest);
437         if (autoanswer) {
438                 ast_verbose( " << Auto-answered >> \n" );
439                 needanswer = 1;
440         } else {
441                 ast_verbose( " << Type 'answer' to answer, or use 'autoanswer' for future calls >> \n");
442                 needringing = 1;
443                 write(sndcmd[1], &res, sizeof(res));
444         }
445         return 0;
446 }
447
448 static void answer_sound(void)
449 {
450         int res;
451         nosound = 1;
452         res = 4;
453         write(sndcmd[1], &res, sizeof(res));
454         
455 }
456
457 static int oss_answer(struct ast_channel *c)
458 {
459         ast_verbose( " << Console call has been answered >> \n");
460         answer_sound();
461         c->state = AST_STATE_UP;
462         cursound = -1;
463         return 0;
464 }
465
466 static int oss_hangup(struct ast_channel *c)
467 {
468         int res;
469         cursound = -1;
470         c->pvt->pvt = NULL;
471         oss.owner = NULL;
472         ast_verbose( " << Hangup on console >> \n");
473         ast_pthread_mutex_lock(&usecnt_lock);
474         usecnt--;
475         ast_pthread_mutex_unlock(&usecnt_lock);
476         needhangup = 0;
477         needanswer = 0;
478         if (hookstate) {
479                 if (autoanswer) {
480                         /* Assume auto-hangup too */
481                         hookstate = 0;
482                 } else {
483                         /* Make congestion noise */
484                         res = 2;
485                         write(sndcmd[1], &res, sizeof(res));
486                 }
487         }
488         return 0;
489 }
490
491 static int soundcard_writeframe(short *data)
492 {       
493         /* Write an exactly FRAME_SIZE sized of frame */
494         static int bufcnt = 0;
495         static short buffer[FRAME_SIZE * MAX_BUFFER_SIZE * 5];
496         struct audio_buf_info info;
497         int res;
498         int fd = sounddev;
499         static int warned=0;
500         if (ioctl(fd, SNDCTL_DSP_GETOSPACE, &info)) {
501                 if (!warned)
502                         ast_log(LOG_WARNING, "Error reading output space\n");
503                 bufcnt = buffersize;
504                 warned++;
505         }
506         if ((info.fragments >= buffersize * 5) && (bufcnt == buffersize)) {
507                 /* We've run out of stuff, buffer again */
508                 bufcnt = 0;
509         }
510         if (bufcnt == buffersize) {
511                 /* Write sample immediately */
512                 res = write(fd, ((void *)data), FRAME_SIZE * 2);
513         } else {
514                 /* Copy the data into our buffer */
515                 res = FRAME_SIZE * 2;
516                 memcpy(buffer + (bufcnt * FRAME_SIZE), data, FRAME_SIZE * 2);
517                 bufcnt++;
518                 if (bufcnt == buffersize) {
519                         res = write(fd, ((void *)buffer), FRAME_SIZE * 2 * buffersize);
520                 }
521         }
522         return res;
523 }
524
525
526 static int oss_write(struct ast_channel *chan, struct ast_frame *f)
527 {
528         int res;
529         static char sizbuf[8000];
530         static int sizpos = 0;
531         int len = sizpos;
532         int pos;
533         /* Immediately return if no sound is enabled */
534         if (nosound)
535                 return 0;
536         /* Stop any currently playing sound */
537         cursound = -1;
538         if (!full_duplex && (strlen(digits) || needhangup || needanswer)) {
539                 /* If we're half duplex, we have to switch to read mode
540                    to honor immediate needs if necessary */
541                 res = soundcard_setinput(1);
542                 if (res < 0) {
543                         ast_log(LOG_WARNING, "Unable to set device to input mode\n");
544                         return -1;
545                 }
546                 return 0;
547         }
548         res = soundcard_setoutput(0);
549         if (res < 0) {
550                 ast_log(LOG_WARNING, "Unable to set output device\n");
551                 return -1;
552         } else if (res > 0) {
553                 /* The device is still in read mode, and it's too soon to change it,
554                    so just pretend we wrote it */
555                 return 0;
556         }
557         /* We have to digest the frame in 160-byte portions */
558         if (f->datalen > sizeof(sizbuf) - sizpos) {
559                 ast_log(LOG_WARNING, "Frame too large\n");
560                 return -1;
561         }
562         memcpy(sizbuf + sizpos, f->data, f->datalen);
563         len += f->datalen;
564         pos = 0;
565         while(len - pos > FRAME_SIZE * 2) {
566                 soundcard_writeframe((short *)(sizbuf + pos));
567                 pos += FRAME_SIZE * 2;
568         }
569         if (len - pos) 
570                 memmove(sizbuf, sizbuf + pos, len - pos);
571         sizpos = len - pos;
572         return 0;
573 }
574
575 static struct ast_frame *oss_read(struct ast_channel *chan)
576 {
577         static struct ast_frame f;
578         static char buf[FRAME_SIZE * 2 + AST_FRIENDLY_OFFSET];
579         static int readpos = 0;
580         int res;
581         int b;
582         int nonull=0;
583         
584 #if 0
585         ast_log(LOG_DEBUG, "oss_read()\n");
586 #endif
587         
588         /* Acknowledge any pending cmd */
589         res = read(cmd[0], &b, sizeof(b));
590         if (res > 0)
591                 nonull = 1;
592         
593         f.frametype = AST_FRAME_NULL;
594         f.subclass = 0;
595         f.timelen = 0;
596         f.datalen = 0;
597         f.data = NULL;
598         f.offset = 0;
599         f.src = type;
600         f.mallocd = 0;
601         
602         if (needringing) {
603                 f.frametype = AST_FRAME_CONTROL;
604                 f.subclass = AST_CONTROL_RINGING;
605                 needringing = 0;
606                 return &f;
607         }
608         
609         if (needhangup) {
610                 needhangup = 0;
611                 return NULL;
612         }
613         if (strlen(text2send)) {
614                 f.frametype = AST_FRAME_TEXT;
615                 f.subclass = 0;
616                 f.data = text2send;
617                 f.datalen = strlen(text2send);
618                 strcpy(text2send,"");
619                 return &f;
620         }
621         if (strlen(digits)) {
622                 f.frametype = AST_FRAME_DTMF;
623                 f.subclass = digits[0];
624                 for (res=0;res<strlen(digits);res++)
625                         digits[res] = digits[res + 1];
626                 return &f;
627         }
628         
629         if (needanswer) {
630                 needanswer = 0;
631                 f.frametype = AST_FRAME_CONTROL;
632                 f.subclass = AST_CONTROL_ANSWER;
633                 chan->state = AST_STATE_UP;
634                 return &f;
635         }
636         
637         if (nonull)
638                 return &f;
639                 
640         res = soundcard_setinput(0);
641         if (res < 0) {
642                 ast_log(LOG_WARNING, "Unable to set input mode\n");
643                 return NULL;
644         }
645         if (res > 0) {
646                 /* Theoretically shouldn't happen, but anyway, return a NULL frame */
647                 return &f;
648         }
649         res = read(sounddev, buf + AST_FRIENDLY_OFFSET + readpos, FRAME_SIZE * 2 - readpos);
650         if (res < 0) {
651                 ast_log(LOG_WARNING, "Error reading from sound device (If you're running 'artsd' then kill it): %s\n", strerror(errno));
652 #if 0
653                 CRASH;
654 #endif          
655                 return NULL;
656         }
657         readpos += res;
658         
659         if (readpos >= FRAME_SIZE * 2) {
660                 /* A real frame */
661                 readpos = 0;
662                 if (chan->state != AST_STATE_UP) {
663                         /* Don't transmit unless it's up */
664                         return &f;
665                 }
666                 f.frametype = AST_FRAME_VOICE;
667                 f.subclass = AST_FORMAT_SLINEAR;
668                 f.timelen = FRAME_SIZE / 8;
669                 f.datalen = FRAME_SIZE * 2;
670                 f.data = buf + AST_FRIENDLY_OFFSET;
671                 f.offset = AST_FRIENDLY_OFFSET;
672                 f.src = type;
673                 f.mallocd = 0;
674 #if 0
675                 { static int fd = -1;
676                   if (fd < 0)
677                         fd = open("output.raw", O_RDWR | O_TRUNC | O_CREAT);
678                   write(fd, f.data, f.datalen);
679                 }
680 #endif          
681         }
682         return &f;
683 }
684
685 static int oss_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
686 {
687         struct chan_oss_pvt *p = newchan->pvt->pvt;
688         p->owner = newchan;
689         return 0;
690 }
691
692 static int oss_indicate(struct ast_channel *chan, int cond)
693 {
694         int res;
695         switch(cond) {
696         case AST_CONTROL_BUSY:
697                 res = 1;
698                 break;
699         case AST_CONTROL_CONGESTION:
700                 res = 2;
701                 break;
702         case AST_CONTROL_RINGING:
703                 res = 0;
704                 break;
705         default:
706                 ast_log(LOG_WARNING, "Don't know how to display condition %d on %s\n", cond, chan->name);
707                 return -1;
708         }
709         if (res > -1) {
710                 write(sndcmd[1], &res, sizeof(res));
711         }
712         return 0;       
713 }
714
715 static struct ast_channel *oss_new(struct chan_oss_pvt *p, int state)
716 {
717         struct ast_channel *tmp;
718         tmp = ast_channel_alloc();
719         if (tmp) {
720                 snprintf(tmp->name, sizeof(tmp->name), "OSS/%s", DEV_DSP + 5);
721                 tmp->type = type;
722                 tmp->fds[0] = sounddev;
723                 tmp->fds[1] = cmd[0];
724                 tmp->nativeformats = AST_FORMAT_SLINEAR;
725                 tmp->pvt->pvt = p;
726                 tmp->pvt->send_digit = oss_digit;
727                 tmp->pvt->send_text = oss_text;
728                 tmp->pvt->hangup = oss_hangup;
729                 tmp->pvt->answer = oss_answer;
730                 tmp->pvt->read = oss_read;
731                 tmp->pvt->call = oss_call;
732                 tmp->pvt->write = oss_write;
733                 tmp->pvt->indicate = oss_indicate;
734                 tmp->pvt->fixup = oss_fixup;
735                 if (strlen(p->context))
736                         strncpy(tmp->context, p->context, sizeof(tmp->context)-1);
737                 if (strlen(p->exten))
738                         strncpy(tmp->exten, p->exten, sizeof(tmp->exten)-1);
739                 if (strlen(language))
740                         strncpy(tmp->language, language, sizeof(tmp->language)-1);
741                 p->owner = tmp;
742                 tmp->state = state;
743                 ast_pthread_mutex_lock(&usecnt_lock);
744                 usecnt++;
745                 ast_pthread_mutex_unlock(&usecnt_lock);
746                 ast_update_use_count();
747                 if (state != AST_STATE_DOWN) {
748                         if (ast_pbx_start(tmp)) {
749                                 ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
750                                 ast_hangup(tmp);
751                                 tmp = NULL;
752                         }
753                 }
754         }
755         return tmp;
756 }
757
758 static struct ast_channel *oss_request(char *type, int format, void *data)
759 {
760         int oldformat = format;
761         struct ast_channel *tmp;
762         format &= AST_FORMAT_SLINEAR;
763         if (!format) {
764                 ast_log(LOG_NOTICE, "Asked to get a channel of format '%d'\n", oldformat);
765                 return NULL;
766         }
767         if (oss.owner) {
768                 ast_log(LOG_NOTICE, "Already have a call on the OSS channel\n");
769                 return NULL;
770         }
771         tmp= oss_new(&oss, AST_STATE_DOWN);
772         if (!tmp) {
773                 ast_log(LOG_WARNING, "Unable to create new OSS channel\n");
774         }
775         return tmp;
776 }
777
778 static int console_autoanswer(int fd, int argc, char *argv[])
779 {
780         if ((argc != 1) && (argc != 2))
781                 return RESULT_SHOWUSAGE;
782         if (argc == 1) {
783                 ast_cli(fd, "Auto answer is %s.\n", autoanswer ? "on" : "off");
784                 return RESULT_SUCCESS;
785         } else {
786                 if (!strcasecmp(argv[1], "on"))
787                         autoanswer = -1;
788                 else if (!strcasecmp(argv[1], "off"))
789                         autoanswer = 0;
790                 else
791                         return RESULT_SHOWUSAGE;
792         }
793         return RESULT_SUCCESS;
794 }
795
796 static char *autoanswer_complete(char *line, char *word, int pos, int state)
797 {
798 #ifndef MIN
799 #define MIN(a,b) ((a) < (b) ? (a) : (b))
800 #endif
801         switch(state) {
802         case 0:
803                 if (strlen(word) && !strncasecmp(word, "on", MIN(strlen(word), 2)))
804                         return strdup("on");
805         case 1:
806                 if (strlen(word) && !strncasecmp(word, "off", MIN(strlen(word), 3)))
807                         return strdup("off");
808         default:
809                 return NULL;
810         }
811         return NULL;
812 }
813
814 static char autoanswer_usage[] =
815 "Usage: autoanswer [on|off]\n"
816 "       Enables or disables autoanswer feature.  If used without\n"
817 "       argument, displays the current on/off status of autoanswer.\n"
818 "       The default value of autoanswer is in 'oss.conf'.\n";
819
820 static int console_answer(int fd, int argc, char *argv[])
821 {
822         if (argc != 1)
823                 return RESULT_SHOWUSAGE;
824         if (!oss.owner) {
825                 ast_cli(fd, "No one is calling us\n");
826                 return RESULT_FAILURE;
827         }
828         hookstate = 1;
829         cursound = -1;
830         needanswer++;
831         answer_sound();
832         return RESULT_SUCCESS;
833 }
834
835 static char sendtext_usage[] =
836 "Usage: send text <message>\n"
837 "       Sends a text message for display on the remote terminal.\n";
838
839 static int console_sendtext(int fd, int argc, char *argv[])
840 {
841         int tmparg = 1;
842         if (argc < 1)
843                 return RESULT_SHOWUSAGE;
844         if (!oss.owner) {
845                 ast_cli(fd, "No one is calling us\n");
846                 return RESULT_FAILURE;
847         }
848         if (strlen(text2send))
849                 ast_cli(fd, "Warning: message already waiting to be sent, overwriting\n");
850         strcpy(text2send, "");
851         while(tmparg <= argc) {
852                 strncat(text2send, argv[tmparg++], sizeof(text2send) - strlen(text2send));
853                 strncat(text2send, " ", sizeof(text2send) - strlen(text2send));
854         }
855         needanswer++;
856         return RESULT_SUCCESS;
857 }
858
859 static char answer_usage[] =
860 "Usage: answer\n"
861 "       Answers an incoming call on the console (OSS) channel.\n";
862
863 static int console_hangup(int fd, int argc, char *argv[])
864 {
865         if (argc != 1)
866                 return RESULT_SHOWUSAGE;
867         cursound = -1;
868         if (!oss.owner && !hookstate) {
869                 ast_cli(fd, "No call to hangup up\n");
870                 return RESULT_FAILURE;
871         }
872         hookstate = 0;
873         if (oss.owner)
874                 needhangup++;
875         return RESULT_SUCCESS;
876 }
877
878 static char hangup_usage[] =
879 "Usage: hangup\n"
880 "       Hangs up any call currently placed on the console.\n";
881
882
883 static int console_dial(int fd, int argc, char *argv[])
884 {
885         char tmp[256], *tmp2;
886         char *mye, *myc;
887         int b = 0;
888         if ((argc != 1) && (argc != 2))
889                 return RESULT_SHOWUSAGE;
890         if (oss.owner) {
891                 if (argc == 2) {
892                         strncat(digits, argv[1], sizeof(digits) - strlen(digits));
893                         /* Wake up the polling thread */
894                         write(cmd[1], &b, sizeof(b));
895                 } else {
896                         ast_cli(fd, "You're already in a call.  You can use this only to dial digits until you hangup\n");
897                         return RESULT_FAILURE;
898                 }
899                 return RESULT_SUCCESS;
900         }
901         mye = exten;
902         myc = context;
903         if (argc == 2) {
904                 strncpy(tmp, argv[1], sizeof(tmp)-1);
905                 strtok(tmp, "@");
906                 tmp2 = strtok(NULL, "@");
907                 if (strlen(tmp))
908                         mye = tmp;
909                 if (tmp2 && strlen(tmp2))
910                         myc = tmp2;
911         }
912         if (ast_exists_extension(NULL, myc, mye, 1, NULL)) {
913                 strncpy(oss.exten, mye, sizeof(oss.exten)-1);
914                 strncpy(oss.context, myc, sizeof(oss.context)-1);
915                 hookstate = 1;
916                 oss_new(&oss, AST_STATE_UP);
917         } else
918                 ast_cli(fd, "No such extension '%s' in context '%s'\n", mye, myc);
919         return RESULT_SUCCESS;
920 }
921
922 static char dial_usage[] =
923 "Usage: dial [extension[@context]]\n"
924 "       Dials a given extensison (";
925
926
927 static struct ast_cli_entry myclis[] = {
928         { { "answer", NULL }, console_answer, "Answer an incoming console call", answer_usage },
929         { { "hangup", NULL }, console_hangup, "Hangup a call on the console", hangup_usage },
930         { { "dial", NULL }, console_dial, "Dial an extension on the console", dial_usage },
931         { { "send text", NULL }, console_sendtext, "Send text to the remote device", sendtext_usage },
932         { { "autoanswer", NULL }, console_autoanswer, "Sets/displays autoanswer", autoanswer_usage, autoanswer_complete }
933 };
934
935 int load_module()
936 {
937         int res;
938         int x;
939         int flags;
940         struct ast_config *cfg = ast_load(config);
941         struct ast_variable *v;
942         res = pipe(cmd);
943         res = pipe(sndcmd);
944         if (res) {
945                 ast_log(LOG_ERROR, "Unable to create pipe\n");
946                 return -1;
947         }
948         flags = fcntl(cmd[0], F_GETFL);
949         fcntl(cmd[0], F_SETFL, flags | O_NONBLOCK);
950         flags = fcntl(cmd[1], F_GETFL);
951         fcntl(cmd[1], F_SETFL, flags | O_NONBLOCK);
952         res = soundcard_init();
953         if (res < 0) {
954                 close(cmd[1]);
955                 close(cmd[0]);
956                 if (option_verbose > 1) {
957                         ast_verbose(VERBOSE_PREFIX_2 "No sound card detected -- console channel will be unavailable\n");
958                         ast_verbose(VERBOSE_PREFIX_2 "Turn off OSS support by adding 'noload=chan_oss.so' in /etc/asterisk/modules.conf\n");
959                 }
960                 return 0;
961         }
962         if (!full_duplex)
963                 ast_log(LOG_WARNING, "XXX I don't work right with non-full duplex sound cards XXX\n");
964         res = ast_channel_register(type, tdesc, AST_FORMAT_SLINEAR, oss_request);
965         if (res < 0) {
966                 ast_log(LOG_ERROR, "Unable to register channel class '%s'\n", type);
967                 return -1;
968         }
969         for (x=0;x<sizeof(myclis)/sizeof(struct ast_cli_entry); x++)
970                 ast_cli_register(myclis + x);
971         if (cfg) {
972                 v = ast_variable_browse(cfg, "general");
973                 while(v) {
974                         if (!strcasecmp(v->name, "autoanswer"))
975                                 autoanswer = ast_true(v->value);
976                         else if (!strcasecmp(v->name, "silencesuppression"))
977                                 silencesuppression = ast_true(v->value);
978                         else if (!strcasecmp(v->name, "silencethreshold"))
979                                 silencethreshold = atoi(v->value);
980                         else if (!strcasecmp(v->name, "context"))
981                                 strncpy(context, v->value, sizeof(context)-1);
982                         else if (!strcasecmp(v->name, "language"))
983                                 strncpy(language, v->value, sizeof(language)-1);
984                         else if (!strcasecmp(v->name, "extension"))
985                                 strncpy(exten, v->value, sizeof(exten)-1);
986                         v=v->next;
987                 }
988                 ast_destroy(cfg);
989         }
990         pthread_create(&sthread, NULL, sound_thread, NULL);
991         return 0;
992 }
993
994
995
996 int unload_module()
997 {
998         int x;
999         for (x=0;x<sizeof(myclis)/sizeof(struct ast_cli_entry); x++)
1000                 ast_cli_unregister(myclis + x);
1001         close(sounddev);
1002         if (cmd[0] > 0) {
1003                 close(cmd[0]);
1004                 close(cmd[1]);
1005         }
1006         if (sndcmd[0] > 0) {
1007                 close(sndcmd[0]);
1008                 close(sndcmd[1]);
1009         }
1010         if (oss.owner)
1011                 ast_softhangup(oss.owner);
1012         if (oss.owner)
1013                 return -1;
1014         return 0;
1015 }
1016
1017 char *description()
1018 {
1019         return desc;
1020 }
1021
1022 int usecount()
1023 {
1024         int res;
1025         ast_pthread_mutex_lock(&usecnt_lock);
1026         res = usecnt;
1027         ast_pthread_mutex_unlock(&usecnt_lock);
1028         return res;
1029 }
1030
1031 char *key()
1032 {
1033         return ASTERISK_GPL_KEY;
1034 }