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