b3fdfbf9361dc1eab752f044b7ceb993c32030e3
[asterisk/asterisk.git] / channels / chan_nbs.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Generic Linux Telephony Interface driver
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 <stdio.h>
15 #include <string.h>
16 #include <asterisk/lock.h>
17 #include <asterisk/channel.h>
18 #include <asterisk/channel_pvt.h>
19 #include <asterisk/config.h>
20 #include <asterisk/logger.h>
21 #include <asterisk/module.h>
22 #include <asterisk/pbx.h>
23 #include <asterisk/options.h>
24 #include <sys/socket.h>
25 #include <sys/time.h>
26 #include <errno.h>
27 #include <unistd.h>
28 #include <stdlib.h>
29 #include <arpa/inet.h>
30 #include <fcntl.h>
31 #include <sys/ioctl.h>
32 #include <nbs.h>
33
34 static char *desc = "Network Broadcast Sound Support";
35 static char *type = "NBS";
36 static char *tdesc = "Network Broadcast Sound Driver";
37
38 static int usecnt =0;
39
40 /* Only linear is allowed */
41 static int prefformat = AST_FORMAT_SLINEAR;
42
43 AST_MUTEX_DEFINE_STATIC(usecnt_lock);
44
45 static char context[AST_MAX_EXTENSION] = "default";
46
47 /* NBS creates private structures on demand */
48    
49 struct nbs_pvt {
50         NBS *nbs;
51         struct ast_channel *owner;              /* Channel we belong to, possibly NULL */
52         char app[16];                                   /* Our app */
53         char stream[80];                                /* Our stream */
54         struct ast_frame fr;                    /* "null" frame */
55 };
56
57 static int nbs_call(struct ast_channel *ast, char *dest, int timeout)
58 {
59         struct nbs_pvt *p;
60
61         p = ast->pvt->pvt;
62
63         if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
64                 ast_log(LOG_WARNING, "nbs_call called on %s, neither down nor reserved\n", ast->name);
65                 return -1;
66         }
67         /* When we call, it just works, really, there's no destination...  Just
68            ring the phone and wait for someone to answer */
69         if (option_debug)
70                 ast_log(LOG_DEBUG, "Calling %s on %s\n", dest, ast->name);
71
72         /* If we can't connect, return congestion */
73         if (nbs_connect(p->nbs)) {
74                 ast_log(LOG_WARNING, "NBS Connection failed on %s\n", ast->name);
75                 ast_queue_control(ast, AST_CONTROL_CONGESTION);
76         } else {
77                 ast_setstate(ast, AST_STATE_RINGING);
78                 ast_queue_control(ast, AST_CONTROL_ANSWER);
79         }
80
81         return 0;
82 }
83
84 static void nbs_destroy(struct nbs_pvt *p)
85 {
86         if (p->nbs)
87                 nbs_delstream(p->nbs);
88         free(p);
89 }
90
91 static struct nbs_pvt *nbs_alloc(void *data)
92 {
93         struct nbs_pvt *p;
94         int flags = 0;
95         char stream[256] = "";
96         char *opts;
97         strncpy(stream, data, sizeof(stream) - 1);
98         if ((opts = strchr(stream, ':'))) {
99                 *opts = '\0';
100                 opts++;
101         } else
102                 opts = "";
103         p = malloc(sizeof(struct nbs_pvt));
104         if (p) {
105                 memset(p, 0, sizeof(struct nbs_pvt));
106                 if (strlen(opts)) {
107                         if (strchr(opts, 'm'))
108                                 flags |= NBS_FLAG_MUTE;
109                         if (strchr(opts, 'o'))
110                                 flags |= NBS_FLAG_OVERSPEAK;
111                         if (strchr(opts, 'e'))
112                                 flags |= NBS_FLAG_EMERGENCY;
113                         if (strchr(opts, 'O'))
114                                 flags |= NBS_FLAG_OVERRIDE;
115                 } else
116                         flags = NBS_FLAG_OVERSPEAK;
117                 
118                 strncpy(p->stream, stream, sizeof(p->stream) - 1);
119                 p->nbs = nbs_newstream("asterisk", stream, flags);
120                 if (!p->nbs) {
121                         ast_log(LOG_WARNING, "Unable to allocate new NBS stream '%s' with flags %d\n", stream, flags);
122                         free(p);
123                         p = NULL;
124                 } else {
125                         /* Set for 8000 hz mono, 640 samples */
126                         nbs_setbitrate(p->nbs, 8000);
127                         nbs_setchannels(p->nbs, 1);
128                         nbs_setblocksize(p->nbs, 640);
129                         nbs_setblocking(p->nbs, 0);
130                 }
131         }
132         return p;
133 }
134
135 static int nbs_hangup(struct ast_channel *ast)
136 {
137         struct nbs_pvt *p;
138         p = ast->pvt->pvt;
139         if (option_debug)
140                 ast_log(LOG_DEBUG, "nbs_hangup(%s)\n", ast->name);
141         if (!ast->pvt->pvt) {
142                 ast_log(LOG_WARNING, "Asked to hangup channel not connected\n");
143                 return 0;
144         }
145         nbs_destroy(p);
146         ast->pvt->pvt = NULL;
147         ast_setstate(ast, AST_STATE_DOWN);
148         return 0;
149 }
150
151 static struct ast_frame  *nbs_xread(struct ast_channel *ast)
152 {
153         struct nbs_pvt *p = ast->pvt->pvt;
154         
155
156         /* Some nice norms */
157         p->fr.datalen = 0;
158         p->fr.samples = 0;
159         p->fr.data =  NULL;
160         p->fr.src = type;
161         p->fr.offset = 0;
162         p->fr.mallocd=0;
163         p->fr.delivery.tv_sec = 0;
164         p->fr.delivery.tv_usec = 0;
165
166         ast_log(LOG_DEBUG, "Returning null frame on %s\n", ast->name);
167
168         return &p->fr;
169 }
170
171 static int nbs_xwrite(struct ast_channel *ast, struct ast_frame *frame)
172 {
173         struct nbs_pvt *p = ast->pvt->pvt;
174         /* Write a frame of (presumably voice) data */
175         if (frame->frametype != AST_FRAME_VOICE) {
176                 if (frame->frametype != AST_FRAME_IMAGE)
177                         ast_log(LOG_WARNING, "Don't know what to do with  frame type '%d'\n", frame->frametype);
178                 return 0;
179         }
180         if (!(frame->subclass &
181                 (AST_FORMAT_SLINEAR))) {
182                 ast_log(LOG_WARNING, "Cannot handle frames in %d format\n", frame->subclass);
183                 return 0;
184         }
185         if (ast->_state != AST_STATE_UP) {
186                 /* Don't try tos end audio on-hook */
187                 return 0;
188         }
189         if (nbs_write(p->nbs, frame->data, frame->datalen / 2) < 0) 
190                 return -1;
191         return 0;
192 }
193
194 static struct ast_channel *nbs_new(struct nbs_pvt *i, int state)
195 {
196         struct ast_channel *tmp;
197         tmp = ast_channel_alloc(1);
198         if (tmp) {
199                 snprintf(tmp->name, sizeof(tmp->name), "NBS/%s", i->stream);
200                 tmp->type = type;
201                 tmp->fds[0] = nbs_fd(i->nbs);
202                 tmp->nativeformats = prefformat;
203                 tmp->pvt->rawreadformat = prefformat;
204                 tmp->pvt->rawwriteformat = prefformat;
205                 tmp->writeformat = prefformat;
206                 tmp->readformat = prefformat;
207                 ast_setstate(tmp, state);
208                 if (state == AST_STATE_RING)
209                         tmp->rings = 1;
210                 tmp->pvt->pvt = i;
211                 tmp->pvt->call = nbs_call;
212                 tmp->pvt->hangup = nbs_hangup;
213                 tmp->pvt->read = nbs_xread;
214                 tmp->pvt->write = nbs_xwrite;
215                 strncpy(tmp->context, context, sizeof(tmp->context)-1);
216                 strncpy(tmp->exten, "s",  sizeof(tmp->exten) - 1);
217                 tmp->language[0] = '\0';
218                 i->owner = tmp;
219                 ast_mutex_lock(&usecnt_lock);
220                 usecnt++;
221                 ast_mutex_unlock(&usecnt_lock);
222                 ast_update_use_count();
223                 if (state != AST_STATE_DOWN) {
224                         if (ast_pbx_start(tmp)) {
225                                 ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
226                                 ast_hangup(tmp);
227                         }
228                 }
229         } else
230                 ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
231         return tmp;
232 }
233
234
235 static struct ast_channel *nbs_request(const char *type, int format, void *data, int *cause)
236 {
237         int oldformat;
238         struct nbs_pvt *p;
239         struct ast_channel *tmp = NULL;
240         
241         oldformat = format;
242         format &= (AST_FORMAT_SLINEAR);
243         if (!format) {
244                 ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%d'\n", oldformat);
245                 return NULL;
246         }
247         p = nbs_alloc(data);
248         if (p) {
249                 tmp = nbs_new(p, AST_STATE_DOWN);
250                 if (!tmp)
251                         nbs_destroy(p);
252         }
253         return tmp;
254 }
255
256 static int __unload_module(void)
257 {
258         /* First, take us out of the channel loop */
259         ast_channel_unregister(type);
260         return 0;
261 }
262
263 int unload_module(void)
264 {
265         return __unload_module();
266 }
267
268 int load_module()
269 {
270         /* Make sure we can register our Adtranphone channel type */
271         if (ast_channel_register(type, tdesc, 
272                          AST_FORMAT_SLINEAR, nbs_request)) {
273                 ast_log(LOG_ERROR, "Unable to register channel class %s\n", type);
274                 __unload_module();
275                 return -1;
276         }
277         return 0;
278 }
279
280 int usecount()
281 {
282         int res;
283         ast_mutex_lock(&usecnt_lock);
284         res = usecnt;
285         ast_mutex_unlock(&usecnt_lock);
286         return res;
287 }
288
289 char *description()
290 {
291         return desc;
292 }
293
294 char *key()
295 {
296         return ASTERISK_GPL_KEY;
297 }