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