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