More include fixes
[asterisk/asterisk.git] / apps / app_intercom.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Use /dev/dsp as an intercom.
5  * 
6  * Copyright (C) 1999, Mark Spencer
7  *
8  * Mark Spencer <markster@linux-support.net>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13  
14 #include <asterisk/lock.h>
15 #include <asterisk/file.h>
16 #include <asterisk/frame.h>
17 #include <asterisk/logger.h>
18 #include <asterisk/channel.h>
19 #include <asterisk/pbx.h>
20 #include <asterisk/module.h>
21 #include <asterisk/translate.h>
22 #include <unistd.h>
23 #include <errno.h>
24 #include <sys/ioctl.h>
25 #include <string.h>
26 #include <stdlib.h>
27 #include <pthread.h>
28 #include <sys/time.h>
29 #ifdef __linux__
30 #include <linux/soundcard.h>
31 #else
32 #include <soundcard.h>
33 #endif
34 #include <netinet/in.h>
35
36 #define DEV_DSP "/dev/dsp"
37
38 /* Number of 32 byte buffers -- each buffer is 2 ms */
39 #define BUFFER_SIZE 32
40
41 static char *tdesc = "Intercom using /dev/dsp for output";
42
43 static char *app = "Intercom";
44
45 static char *synopsis = "(Obsolete) Send to Intercom";
46 static char *descrip = 
47 "  Intercom(): Sends the user to the intercom (i.e. /dev/dsp).  This program\n"
48 "is generally considered  obselete by the chan_oss module.  Returns 0 if the\n"
49 "user exits with a DTMF tone, or -1 if they hangup.\n";
50
51 STANDARD_LOCAL_USER;
52
53 LOCAL_USER_DECL;
54
55 static pthread_mutex_t sound_lock = AST_MUTEX_INITIALIZER;
56 static int sound = -1;
57
58 static int write_audio(short *data, int len)
59 {
60         int res;
61         struct audio_buf_info info;
62         ast_pthread_mutex_lock(&sound_lock);
63         if (sound < 0) {
64                 ast_log(LOG_WARNING, "Sound device closed?\n");
65                 ast_pthread_mutex_unlock(&sound_lock);
66                 return -1;
67         }
68     if (ioctl(sound, SNDCTL_DSP_GETOSPACE, &info)) {
69                 ast_log(LOG_WARNING, "Unable to read output space\n");
70                 ast_pthread_mutex_unlock(&sound_lock);
71         return -1;
72     }
73         res = write(sound, data, len);
74         ast_pthread_mutex_unlock(&sound_lock);
75         return res;
76 }
77
78 static int create_audio(void)
79 {
80         int fmt, desired, res, fd;
81         fd = open(DEV_DSP, O_WRONLY);
82         if (fd < 0) {
83                 ast_log(LOG_WARNING, "Unable to open %s: %s\n", DEV_DSP, strerror(errno));
84                 close(fd);
85                 return -1;
86         }
87         fmt = AFMT_S16_LE;
88         res = ioctl(fd, SNDCTL_DSP_SETFMT, &fmt);
89         if (res < 0) {
90                 ast_log(LOG_WARNING, "Unable to set format to 16-bit signed\n");
91                 close(fd);
92                 return -1;
93         }
94         fmt = 0;
95         res = ioctl(fd, SNDCTL_DSP_STEREO, &fmt);
96         if (res < 0) {
97                 ast_log(LOG_WARNING, "Failed to set audio device to mono\n");
98                 close(fd);
99                 return -1;
100         }
101         /* 8000 Hz desired */
102         desired = 8000;
103         fmt = desired;
104         res = ioctl(fd, SNDCTL_DSP_SPEED, &fmt);
105         if (res < 0) {
106                 ast_log(LOG_WARNING, "Failed to set audio device to mono\n");
107                 close(fd);
108                 return -1;
109         }
110         if (fmt != desired) {
111                 ast_log(LOG_WARNING, "Requested %d Hz, got %d Hz -- sound may be choppy\n", desired, fmt);
112         }
113 #if 1
114         /* 2 bytes * 15 units of 2^5 = 32 bytes per buffer */
115         fmt = ((BUFFER_SIZE) << 16) | (0x0005);
116         res = ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &fmt);
117         if (res < 0) {
118                 ast_log(LOG_WARNING, "Unable to set fragment size -- sound may be choppy\n");
119         }
120 #endif
121         sound = fd;
122         return 0;
123 }
124
125 static int intercom_exec(struct ast_channel *chan, void *data)
126 {
127         int res = 0;
128         struct localuser *u;
129         struct ast_frame *f;
130         int oreadformat;
131         LOCAL_USER_ADD(u);
132         /* Remember original read format */
133         oreadformat = chan->readformat;
134         /* Set mode to signed linear */
135         res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
136         if (res < 0) {
137                 ast_log(LOG_WARNING, "Unable to set format to signed linear on channel %s\n", chan->name);
138                 return -1;
139         }
140         /* Read packets from the channel */
141         while(!res) {
142                 res = ast_waitfor(chan, -1);
143                 if (res > 0) {
144                         res = 0;
145                         f = ast_read(chan);
146                         if (f) {
147                                 if (f->frametype == AST_FRAME_DTMF) {
148                                         ast_frfree(f);
149                                         break;
150                                 } else {
151                                         if (f->frametype == AST_FRAME_VOICE) {
152                                                 if (f->subclass == AST_FORMAT_SLINEAR) {
153                                                         res = write_audio(f->data, f->datalen);
154                                                         if (res > 0)
155                                                                 res = 0;
156                                                 } else
157                                                         ast_log(LOG_DEBUG, "Unable to handle non-signed linear frame (%d)\n", f->subclass);
158                                         } 
159                                 }
160                                 ast_frfree(f);
161                         } else
162                                 res = -1;
163                 }
164         }
165         LOCAL_USER_REMOVE(u);
166         if (!res)
167                 ast_set_read_format(chan, oreadformat);
168         return res;
169 }
170
171 int unload_module(void)
172 {
173         STANDARD_HANGUP_LOCALUSERS;
174         if (sound > -1)
175                 close(sound);
176         return ast_unregister_application(app);
177 }
178
179 int load_module(void)
180 {
181         if (create_audio())
182                 return -1;
183         return ast_register_application(app, intercom_exec, synopsis, descrip);
184 }
185
186 char *description(void)
187 {
188         return tdesc;
189 }
190
191 int usecount(void)
192 {
193         int res;
194         STANDARD_USECOUNT(res);
195         return res;
196 }
197
198 char *key()
199 {
200         return ASTERISK_GPL_KEY;
201 }