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