another few errno.h removals
[asterisk/asterisk.git] / channels / chan_nbs.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2006, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief Network broadcast sound support channel driver
22  * 
23  * \author Mark Spencer <markster@digium.com>
24  *
25  * \ingroup channel_drivers
26  */
27
28 /*** MODULEINFO
29         <depend>nbs</depend>
30  ***/
31
32 #include "asterisk.h"
33
34 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
35
36 #include <sys/socket.h>
37 #include <sys/time.h>
38 #include <arpa/inet.h>
39 #include <fcntl.h>
40 #include <sys/ioctl.h>
41 #include <nbs.h>
42
43 #include "asterisk/lock.h"
44 #include "asterisk/channel.h"
45 #include "asterisk/config.h"
46 #include "asterisk/module.h"
47 #include "asterisk/pbx.h"
48 #include "asterisk/options.h"
49 #include "asterisk/utils.h"
50
51 static const char tdesc[] = "Network Broadcast Sound Driver";
52
53 /* Only linear is allowed */
54 static int prefformat = AST_FORMAT_SLINEAR;
55
56 static char context[AST_MAX_EXTENSION] = "default";
57 static char type[] = "NBS";
58
59 /* NBS creates private structures on demand */
60    
61 struct nbs_pvt {
62         NBS *nbs;
63         struct ast_channel *owner;              /* Channel we belong to, possibly NULL */
64         char app[16];                                   /* Our app */
65         char stream[80];                                /* Our stream */
66         struct ast_frame fr;                    /* "null" frame */
67         struct ast_module_user *u;              /*! for holding a reference to this module */
68 };
69
70 static struct ast_channel *nbs_request(const char *type, int format, void *data, int *cause);
71 static int nbs_call(struct ast_channel *ast, char *dest, int timeout);
72 static int nbs_hangup(struct ast_channel *ast);
73 static struct ast_frame *nbs_xread(struct ast_channel *ast);
74 static int nbs_xwrite(struct ast_channel *ast, struct ast_frame *frame);
75
76 static const struct ast_channel_tech nbs_tech = {
77         .type = type,
78         .description = tdesc,
79         .capabilities = AST_FORMAT_SLINEAR,
80         .requester = nbs_request,
81         .call = nbs_call,
82         .hangup = nbs_hangup,
83         .read = nbs_xread,
84         .write = nbs_xwrite,
85 };
86
87 static int nbs_call(struct ast_channel *ast, char *dest, int timeout)
88 {
89         struct nbs_pvt *p;
90
91         p = ast->tech_pvt;
92
93         if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
94                 ast_log(LOG_WARNING, "nbs_call called on %s, neither down nor reserved\n", ast->name);
95                 return -1;
96         }
97         /* When we call, it just works, really, there's no destination...  Just
98            ring the phone and wait for someone to answer */
99         ast_debug(1, "Calling %s on %s\n", dest, ast->name);
100
101         /* If we can't connect, return congestion */
102         if (nbs_connect(p->nbs)) {
103                 ast_log(LOG_WARNING, "NBS Connection failed on %s\n", ast->name);
104                 ast_queue_control(ast, AST_CONTROL_CONGESTION);
105         } else {
106                 ast_setstate(ast, AST_STATE_RINGING);
107                 ast_queue_control(ast, AST_CONTROL_ANSWER);
108         }
109
110         return 0;
111 }
112
113 static void nbs_destroy(struct nbs_pvt *p)
114 {
115         if (p->nbs)
116                 nbs_delstream(p->nbs);
117         ast_module_user_remove(p->u);
118         ast_free(p);
119 }
120
121 static struct nbs_pvt *nbs_alloc(void *data)
122 {
123         struct nbs_pvt *p;
124         int flags = 0;
125         char stream[256];
126         char *opts;
127
128         ast_copy_string(stream, data, sizeof(stream));
129         if ((opts = strchr(stream, ':'))) {
130                 *opts = '\0';
131                 opts++;
132         } else
133                 opts = "";
134         p = ast_calloc(1, sizeof(*p));
135         if (p) {
136                 if (!ast_strlen_zero(opts)) {
137                         if (strchr(opts, 'm'))
138                                 flags |= NBS_FLAG_MUTE;
139                         if (strchr(opts, 'o'))
140                                 flags |= NBS_FLAG_OVERSPEAK;
141                         if (strchr(opts, 'e'))
142                                 flags |= NBS_FLAG_EMERGENCY;
143                         if (strchr(opts, 'O'))
144                                 flags |= NBS_FLAG_OVERRIDE;
145                 } else
146                         flags = NBS_FLAG_OVERSPEAK;
147                 
148                 ast_copy_string(p->stream, stream, sizeof(p->stream));
149                 p->nbs = nbs_newstream("asterisk", stream, flags);
150                 if (!p->nbs) {
151                         ast_log(LOG_WARNING, "Unable to allocate new NBS stream '%s' with flags %d\n", stream, flags);
152                         ast_free(p);
153                         p = NULL;
154                 } else {
155                         /* Set for 8000 hz mono, 640 samples */
156                         nbs_setbitrate(p->nbs, 8000);
157                         nbs_setchannels(p->nbs, 1);
158                         nbs_setblocksize(p->nbs, 640);
159                         nbs_setblocking(p->nbs, 0);
160                 }
161         }
162         return p;
163 }
164
165 static int nbs_hangup(struct ast_channel *ast)
166 {
167         struct nbs_pvt *p;
168         p = ast->tech_pvt;
169         ast_debug(1, "nbs_hangup(%s)\n", ast->name);
170         if (!ast->tech_pvt) {
171                 ast_log(LOG_WARNING, "Asked to hangup channel not connected\n");
172                 return 0;
173         }
174         nbs_destroy(p);
175         ast->tech_pvt = NULL;
176         ast_setstate(ast, AST_STATE_DOWN);
177         return 0;
178 }
179
180 static struct ast_frame  *nbs_xread(struct ast_channel *ast)
181 {
182         struct nbs_pvt *p = ast->tech_pvt;
183         
184
185         /* Some nice norms */
186         p->fr.datalen = 0;
187         p->fr.samples = 0;
188         p->fr.data =  NULL;
189         p->fr.src = type;
190         p->fr.offset = 0;
191         p->fr.mallocd=0;
192         p->fr.delivery.tv_sec = 0;
193         p->fr.delivery.tv_usec = 0;
194
195         ast_debug(1, "Returning null frame on %s\n", ast->name);
196
197         return &p->fr;
198 }
199
200 static int nbs_xwrite(struct ast_channel *ast, struct ast_frame *frame)
201 {
202         struct nbs_pvt *p = ast->tech_pvt;
203         /* Write a frame of (presumably voice) data */
204         if (frame->frametype != AST_FRAME_VOICE) {
205                 if (frame->frametype != AST_FRAME_IMAGE)
206                         ast_log(LOG_WARNING, "Don't know what to do with  frame type '%d'\n", frame->frametype);
207                 return 0;
208         }
209         if (!(frame->subclass &
210                 (AST_FORMAT_SLINEAR))) {
211                 ast_log(LOG_WARNING, "Cannot handle frames in %d format\n", frame->subclass);
212                 return 0;
213         }
214         if (ast->_state != AST_STATE_UP) {
215                 /* Don't try tos end audio on-hook */
216                 return 0;
217         }
218         if (nbs_write(p->nbs, frame->data, frame->datalen / 2) < 0) 
219                 return -1;
220         return 0;
221 }
222
223 static struct ast_channel *nbs_new(struct nbs_pvt *i, int state)
224 {
225         struct ast_channel *tmp;
226         tmp = ast_channel_alloc(1, state, 0, 0, "", "s", context, 0, "NBS/%s", i->stream);
227         if (tmp) {
228                 tmp->tech = &nbs_tech;
229                 ast_channel_set_fd(tmp, 0, nbs_fd(i->nbs));
230                 tmp->nativeformats = prefformat;
231                 tmp->rawreadformat = prefformat;
232                 tmp->rawwriteformat = prefformat;
233                 tmp->writeformat = prefformat;
234                 tmp->readformat = prefformat;
235                 if (state == AST_STATE_RING)
236                         tmp->rings = 1;
237                 tmp->tech_pvt = i;
238                 ast_copy_string(tmp->context, context, sizeof(tmp->context));
239                 ast_copy_string(tmp->exten, "s",  sizeof(tmp->exten));
240                 ast_string_field_set(tmp, language, "");
241                 i->owner = tmp;
242                 i->u = ast_module_user_add(tmp);
243                 if (state != AST_STATE_DOWN) {
244                         if (ast_pbx_start(tmp)) {
245                                 ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
246                                 ast_hangup(tmp);
247                         }
248                 }
249         } else
250                 ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
251         return tmp;
252 }
253
254
255 static struct ast_channel *nbs_request(const char *type, int format, void *data, int *cause)
256 {
257         int oldformat;
258         struct nbs_pvt *p;
259         struct ast_channel *tmp = NULL;
260         
261         oldformat = format;
262         format &= (AST_FORMAT_SLINEAR);
263         if (!format) {
264                 ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%d'\n", oldformat);
265                 return NULL;
266         }
267         p = nbs_alloc(data);
268         if (p) {
269                 tmp = nbs_new(p, AST_STATE_DOWN);
270                 if (!tmp)
271                         nbs_destroy(p);
272         }
273         return tmp;
274 }
275
276 static int unload_module(void)
277 {
278         /* First, take us out of the channel loop */
279         ast_channel_unregister(&nbs_tech);
280         return 0;
281 }
282
283 static int load_module(void)
284 {
285         /* Make sure we can register our channel type */
286         if (ast_channel_register(&nbs_tech)) {
287                 ast_log(LOG_ERROR, "Unable to register channel class %s\n", type);
288                 return -1;
289         }
290         return 0;
291 }
292
293 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Network Broadcast Sound Support");