Use FILE * instead of fd for files to support buffering
[asterisk/asterisk.git] / formats / format_g726.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (c) 2004 - 2005, inAccess Networks
5  *
6  * Michael Manousos <manousos@inaccessnetworks.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 /*
20  *
21  * Headerless G.726 (16/24/32/40kbps) data format for Asterisk.
22  * 
23  */
24  
25 #include <unistd.h>
26 #include <netinet/in.h>
27 #include <arpa/inet.h>
28 #include <stdlib.h>
29 #include <sys/time.h>
30 #include <stdio.h>
31 #include <errno.h>
32 #include <string.h>
33
34 #include "asterisk.h"
35
36 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
37
38 #include "asterisk/lock.h"
39 #include "asterisk/options.h"
40 #include "asterisk/channel.h"
41 #include "asterisk/file.h"
42 #include "asterisk/logger.h"
43 #include "asterisk/sched.h"
44 #include "asterisk/module.h"
45 #include "asterisk/endian.h"
46
47 #define RATE_40         0
48 #define RATE_32         1
49 #define RATE_24         2
50 #define RATE_16         3
51
52 /* We can only read/write chunks of FRAME_TIME ms G.726 data */
53 #define FRAME_TIME      10      /* 10 ms size */
54
55 /* Frame sizes in bytes */
56 static int frame_size[4] = { 
57                 FRAME_TIME * 5,
58                 FRAME_TIME * 4,
59                 FRAME_TIME * 3,
60                 FRAME_TIME * 2
61 };
62
63 struct ast_filestream {
64         /* Do not place anything before "reserved" */
65         void *reserved[AST_RESERVED_POINTERS];
66         /* This is what a filestream means to us */
67         FILE *f;                                                        /* Open file descriptor */
68         int rate;                                                       /* RATE_* defines */
69         struct ast_frame fr;                            /* Frame information */
70         char waste[AST_FRIENDLY_OFFSET];        /* Buffer for sending frames, etc */
71         char empty;                                                     /* Empty character */
72         unsigned char g726[FRAME_TIME * 5];     /* G.726 encoded voice */
73 };
74
75 AST_MUTEX_DEFINE_STATIC(g726_lock);
76 static int glistcnt = 0;
77
78 static char *desc = "Raw G.726 (16/24/32/40kbps) data";
79 static char *name40 = "g726-40";
80 static char *name32 = "g726-32";
81 static char *name24 = "g726-24";
82 static char *name16 = "g726-16";
83 static char *exts40 = "g726-40";
84 static char *exts32 = "g726-32";
85 static char *exts24 = "g726-24";
86 static char *exts16 = "g726-16";
87
88 /*
89  * Rate dependant format functions (open, rewrite)
90  */
91 static struct ast_filestream *g726_40_open(FILE *f)
92 {
93         /* We don't have any header to read or anything really, but
94            if we did, it would go here.  We also might want to check
95            and be sure it's a valid file.  */
96         struct ast_filestream *tmp;
97         if ((tmp = malloc(sizeof(struct ast_filestream)))) {
98                 memset(tmp, 0, sizeof(struct ast_filestream));
99                 if (ast_mutex_lock(&g726_lock)) {
100                         ast_log(LOG_WARNING, "Unable to lock g726 list.\n");
101                         free(tmp);
102                         return NULL;
103                 }
104                 tmp->f = f;
105                 tmp->rate = RATE_40;
106                 tmp->fr.data = tmp->g726;
107                 tmp->fr.frametype = AST_FRAME_VOICE;
108                 tmp->fr.subclass = AST_FORMAT_G726;
109                 /* datalen will vary for each frame */
110                 tmp->fr.src = name40;
111                 tmp->fr.mallocd = 0;
112                 glistcnt++;
113                 if (option_debug)
114                         ast_log(LOG_DEBUG, "Created filestream G.726-%dk.\n", 
115                                                                         40 - tmp->rate * 8);
116                 ast_mutex_unlock(&g726_lock);
117                 ast_update_use_count();
118         }
119         return tmp;
120 }
121
122 static struct ast_filestream *g726_32_open(FILE *f)
123 {
124         /* We don't have any header to read or anything really, but
125            if we did, it would go here.  We also might want to check
126            and be sure it's a valid file.  */
127         struct ast_filestream *tmp;
128         if ((tmp = malloc(sizeof(struct ast_filestream)))) {
129                 memset(tmp, 0, sizeof(struct ast_filestream));
130                 if (ast_mutex_lock(&g726_lock)) {
131                         ast_log(LOG_WARNING, "Unable to lock g726 list.\n");
132                         free(tmp);
133                         return NULL;
134                 }
135                 tmp->f = f;
136                 tmp->rate = RATE_32;
137                 tmp->fr.data = tmp->g726;
138                 tmp->fr.frametype = AST_FRAME_VOICE;
139                 tmp->fr.subclass = AST_FORMAT_G726;
140                 /* datalen will vary for each frame */
141                 tmp->fr.src = name32;
142                 tmp->fr.mallocd = 0;
143                 glistcnt++;
144                 if (option_debug)
145                         ast_log(LOG_DEBUG, "Created filestream G.726-%dk.\n", 
146                                                                         40 - tmp->rate * 8);
147                 ast_mutex_unlock(&g726_lock);
148                 ast_update_use_count();
149         }
150         return tmp;
151 }
152
153 static struct ast_filestream *g726_24_open(FILE *f)
154 {
155         /* We don't have any header to read or anything really, but
156            if we did, it would go here.  We also might want to check
157            and be sure it's a valid file.  */
158         struct ast_filestream *tmp;
159         if ((tmp = malloc(sizeof(struct ast_filestream)))) {
160                 memset(tmp, 0, sizeof(struct ast_filestream));
161                 if (ast_mutex_lock(&g726_lock)) {
162                         ast_log(LOG_WARNING, "Unable to lock g726 list.\n");
163                         free(tmp);
164                         return NULL;
165                 }
166                 tmp->f = f;
167                 tmp->rate = RATE_24;
168                 tmp->fr.data = tmp->g726;
169                 tmp->fr.frametype = AST_FRAME_VOICE;
170                 tmp->fr.subclass = AST_FORMAT_G726;
171                 /* datalen will vary for each frame */
172                 tmp->fr.src = name24;
173                 tmp->fr.mallocd = 0;
174                 glistcnt++;
175                 if (option_debug)
176                         ast_log(LOG_DEBUG, "Created filestream G.726-%dk.\n", 
177                                                                         40 - tmp->rate * 8);
178                 ast_mutex_unlock(&g726_lock);
179                 ast_update_use_count();
180         }
181         return tmp;
182 }
183
184 static struct ast_filestream *g726_16_open(FILE *f)
185 {
186         /* We don't have any header to read or anything really, but
187            if we did, it would go here.  We also might want to check
188            and be sure it's a valid file.  */
189         struct ast_filestream *tmp;
190         if ((tmp = malloc(sizeof(struct ast_filestream)))) {
191                 memset(tmp, 0, sizeof(struct ast_filestream));
192                 if (ast_mutex_lock(&g726_lock)) {
193                         ast_log(LOG_WARNING, "Unable to lock g726 list.\n");
194                         free(tmp);
195                         return NULL;
196                 }
197                 tmp->f = f;
198                 tmp->rate = RATE_16;
199                 tmp->fr.data = tmp->g726;
200                 tmp->fr.frametype = AST_FRAME_VOICE;
201                 tmp->fr.subclass = AST_FORMAT_G726;
202                 /* datalen will vary for each frame */
203                 tmp->fr.src = name16;
204                 tmp->fr.mallocd = 0;
205                 glistcnt++;
206                 if (option_debug)
207                         ast_log(LOG_DEBUG, "Created filestream G.726-%dk.\n", 
208                                                                         40 - tmp->rate * 8);
209                 ast_mutex_unlock(&g726_lock);
210                 ast_update_use_count();
211         }
212         return tmp;
213 }
214
215 static struct ast_filestream *g726_40_rewrite(FILE *f, const char *comment)
216 {
217         /* We don't have any header to read or anything really, but
218            if we did, it would go here.  We also might want to check
219            and be sure it's a valid file.  */
220         struct ast_filestream *tmp;
221         if ((tmp = malloc(sizeof(struct ast_filestream)))) {
222                 memset(tmp, 0, sizeof(struct ast_filestream));
223                 if (ast_mutex_lock(&g726_lock)) {
224                         ast_log(LOG_WARNING, "Unable to lock g726 list.\n");
225                         free(tmp);
226                         return NULL;
227                 }
228                 tmp->f = f;
229                 tmp->rate = RATE_40;
230                 glistcnt++;
231                 if (option_debug)
232                         ast_log(LOG_DEBUG, "Created filestream G.726-%dk.\n", 
233                                                                         40 - tmp->rate * 8);
234                 ast_mutex_unlock(&g726_lock);
235                 ast_update_use_count();
236         } else
237                 ast_log(LOG_WARNING, "Out of memory\n");
238         return tmp;
239 }
240
241 static struct ast_filestream *g726_32_rewrite(FILE *f, const char *comment)
242 {
243         /* We don't have any header to read or anything really, but
244            if we did, it would go here.  We also might want to check
245            and be sure it's a valid file.  */
246         struct ast_filestream *tmp;
247         if ((tmp = malloc(sizeof(struct ast_filestream)))) {
248                 memset(tmp, 0, sizeof(struct ast_filestream));
249                 if (ast_mutex_lock(&g726_lock)) {
250                         ast_log(LOG_WARNING, "Unable to lock g726 list.\n");
251                         free(tmp);
252                         return NULL;
253                 }
254                 tmp->f = f;
255                 tmp->rate = RATE_32;
256                 glistcnt++;
257                 if (option_debug)
258                         ast_log(LOG_DEBUG, "Created filestream G.726-%dk.\n", 
259                                                                         40 - tmp->rate * 8);
260                 ast_mutex_unlock(&g726_lock);
261                 ast_update_use_count();
262         } else
263                 ast_log(LOG_WARNING, "Out of memory\n");
264         return tmp;
265 }
266
267 static struct ast_filestream *g726_24_rewrite(FILE *f, const char *comment)
268 {
269         /* We don't have any header to read or anything really, but
270            if we did, it would go here.  We also might want to check
271            and be sure it's a valid file.  */
272         struct ast_filestream *tmp;
273         if ((tmp = malloc(sizeof(struct ast_filestream)))) {
274                 memset(tmp, 0, sizeof(struct ast_filestream));
275                 if (ast_mutex_lock(&g726_lock)) {
276                         ast_log(LOG_WARNING, "Unable to lock g726 list.\n");
277                         free(tmp);
278                         return NULL;
279                 }
280                 tmp->f = f;
281                 tmp->rate = RATE_24;
282                 glistcnt++;
283                 if (option_debug)
284                         ast_log(LOG_DEBUG, "Created filestream G.726-%dk.\n", 
285                                                                         40 - tmp->rate * 8);
286                 ast_mutex_unlock(&g726_lock);
287                 ast_update_use_count();
288         } else
289                 ast_log(LOG_WARNING, "Out of memory\n");
290         return tmp;
291 }
292
293 static struct ast_filestream *g726_16_rewrite(FILE *f, const char *comment)
294 {
295         /* We don't have any header to read or anything really, but
296            if we did, it would go here.  We also might want to check
297            and be sure it's a valid file.  */
298         struct ast_filestream *tmp;
299         if ((tmp = malloc(sizeof(struct ast_filestream)))) {
300                 memset(tmp, 0, sizeof(struct ast_filestream));
301                 if (ast_mutex_lock(&g726_lock)) {
302                         ast_log(LOG_WARNING, "Unable to lock g726 list.\n");
303                         free(tmp);
304                         return NULL;
305                 }
306                 tmp->f = f;
307                 tmp->rate = RATE_16;
308                 glistcnt++;
309                 if (option_debug)
310                         ast_log(LOG_DEBUG, "Created filestream G.726-%dk.\n", 
311                                                                         40 - tmp->rate * 8);
312                 ast_mutex_unlock(&g726_lock);
313                 ast_update_use_count();
314         } else
315                 ast_log(LOG_WARNING, "Out of memory\n");
316         return tmp;
317 }
318
319 /*
320  * Rate independent format functions (close, read, write)
321  */
322 static void g726_close(struct ast_filestream *s)
323 {
324         if (ast_mutex_lock(&g726_lock)) {
325                 ast_log(LOG_WARNING, "Unable to lock g726 list.\n");
326                 return;
327         }
328         glistcnt--;
329         if (option_debug)
330                 ast_log(LOG_DEBUG, "Closed filestream G.726-%dk.\n", 40 - s->rate * 8);
331         ast_mutex_unlock(&g726_lock);
332         ast_update_use_count();
333         fclose(s->f);
334         free(s);
335         s = NULL;
336 }
337
338 static struct ast_frame *g726_read(struct ast_filestream *s, int *whennext)
339 {
340         int res;
341         /* Send a frame from the file to the appropriate channel */
342         s->fr.frametype = AST_FRAME_VOICE;
343         s->fr.subclass = AST_FORMAT_G726;
344         s->fr.offset = AST_FRIENDLY_OFFSET;
345         s->fr.samples = 8 * FRAME_TIME;
346         s->fr.datalen = frame_size[s->rate];
347         s->fr.mallocd = 0;
348         s->fr.data = s->g726;
349         if ((res = fread(s->g726, 1, s->fr.datalen, s->f)) != s->fr.datalen) {
350                 if (res)
351                         ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
352                 return NULL;
353         }
354         *whennext = s->fr.samples;
355         return &s->fr;
356 }
357
358 static int g726_write(struct ast_filestream *fs, struct ast_frame *f)
359 {
360         int res;
361         if (f->frametype != AST_FRAME_VOICE) {
362                 ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
363                 return -1;
364         }
365         if (f->subclass != AST_FORMAT_G726) {
366                 ast_log(LOG_WARNING, "Asked to write non-G726 frame (%d)!\n", 
367                                                 f->subclass);
368                 return -1;
369         }
370         if (f->datalen % frame_size[fs->rate]) {
371                 ast_log(LOG_WARNING, "Invalid data length %d, should be multiple of %d\n", 
372                                                 f->datalen, frame_size[fs->rate]);
373                 return -1;
374         }
375         if ((res = fwrite(f->data, 1, f->datalen, fs->f)) != f->datalen) {
376                         ast_log(LOG_WARNING, "Bad write (%d/%d): %s\n", 
377                                                         res, frame_size[fs->rate], strerror(errno));
378                         return -1;
379         }
380         return 0;
381 }
382
383 static char *g726_getcomment(struct ast_filestream *s)
384 {
385         return NULL;
386 }
387
388 static int g726_seek(struct ast_filestream *fs, long sample_offset, int whence)
389 {
390         return -1;
391 }
392
393 static int g726_trunc(struct ast_filestream *fs)
394 {
395         return -1;
396 }
397
398 static long g726_tell(struct ast_filestream *fs)
399 {
400         return -1;
401 }
402
403 /*
404  * Module interface (load_module, unload_module, usecount, description, key)
405  */
406 int load_module()
407 {
408         int res;
409
410         res = ast_format_register(name40, exts40, AST_FORMAT_G726,
411                                                                 g726_40_open,
412                                                                 g726_40_rewrite,
413                                                                 g726_write,
414                                                                 g726_seek,
415                                                                 g726_trunc,
416                                                                 g726_tell,
417                                                                 g726_read,
418                                                                 g726_close,
419                                                                 g726_getcomment);
420         if (res) {
421                 ast_log(LOG_WARNING, "Failed to register format %s.\n", name40);
422                 return(-1);
423         }
424         res = ast_format_register(name32, exts32, AST_FORMAT_G726,
425                                                                 g726_32_open,
426                                                                 g726_32_rewrite,
427                                                                 g726_write,
428                                                                 g726_seek,
429                                                                 g726_trunc,
430                                                                 g726_tell,
431                                                                 g726_read,
432                                                                 g726_close,
433                                                                 g726_getcomment);
434         if (res) {
435                 ast_log(LOG_WARNING, "Failed to register format %s.\n", name32);
436                 return(-1);
437         }
438         res = ast_format_register(name24, exts24, AST_FORMAT_G726,
439                                                                 g726_24_open,
440                                                                 g726_24_rewrite,
441                                                                 g726_write,
442                                                                 g726_seek,
443                                                                 g726_trunc,
444                                                                 g726_tell,
445                                                                 g726_read,
446                                                                 g726_close,
447                                                                 g726_getcomment);
448         if (res) {
449                 ast_log(LOG_WARNING, "Failed to register format %s.\n", name24);
450                 return(-1);
451         }
452         res = ast_format_register(name16, exts16, AST_FORMAT_G726,
453                                                                 g726_16_open,
454                                                                 g726_16_rewrite,
455                                                                 g726_write,
456                                                                 g726_seek,
457                                                                 g726_trunc,
458                                                                 g726_tell,
459                                                                 g726_read,
460                                                                 g726_close,
461                                                                 g726_getcomment);
462         if (res) {
463                 ast_log(LOG_WARNING, "Failed to register format %s.\n", name16);
464                 return(-1);
465         }
466         return(0);
467 }
468
469 int unload_module()
470 {
471         int res;
472
473         res = ast_format_unregister(name16);
474         if (res) {
475                 ast_log(LOG_WARNING, "Failed to unregister format %s.\n", name16);
476                 return(-1);
477         }
478         res = ast_format_unregister(name24);
479         if (res) {
480                 ast_log(LOG_WARNING, "Failed to unregister format %s.\n", name24);
481                 return(-1);
482         }
483         res = ast_format_unregister(name32);
484         if (res) {
485                 ast_log(LOG_WARNING, "Failed to unregister format %s.\n", name32);
486                 return(-1);
487         }
488         res = ast_format_unregister(name40);
489         if (res) {
490                 ast_log(LOG_WARNING, "Failed to unregister format %s.\n", name40);
491                 return(-1);
492         }
493         return(0);
494 }       
495
496 int usecount()
497 {
498         return glistcnt;
499 }
500
501 char *description()
502 {
503         return desc;
504 }
505
506 char *key()
507 {
508         return ASTERISK_GPL_KEY;
509 }
510