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