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