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