git migration: Refactor the ASTERISK_FILE_VERSION macro
[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 /*** MODULEINFO
32         <support_level>core</support_level>
33  ***/
34  
35 #include "asterisk.h"
36
37 ASTERISK_REGISTER_FILE()
38
39 #include "asterisk/mod_format.h"
40 #include "asterisk/module.h"
41 #include "asterisk/endian.h"
42 #include "asterisk/format_cache.h"
43
44 #define RATE_40         0
45 #define RATE_32         1
46 #define RATE_24         2
47 #define RATE_16         3
48
49 /* We can only read/write chunks of FRAME_TIME ms G.726 data */
50 #define FRAME_TIME      10      /* 10 ms size */
51
52 #define BUF_SIZE        (5*FRAME_TIME)  /* max frame size in bytes ? */
53 /* Frame sizes in bytes */
54 static int frame_size[4] = { 
55                 FRAME_TIME * 5,
56                 FRAME_TIME * 4,
57                 FRAME_TIME * 3,
58                 FRAME_TIME * 2
59 };
60
61 struct g726_desc  {
62         int rate;       /* RATE_* defines */
63 };
64
65 /*
66  * Rate dependant format functions (open, rewrite)
67  */
68 static int g726_open(struct ast_filestream *tmp, int rate)
69 {
70         struct g726_desc *s = (struct g726_desc *)tmp->_private;
71         s->rate = rate;
72         ast_debug(1, "Created filestream G.726-%dk.\n", 40 - s->rate * 8);
73         return 0;
74 }
75
76 static int g726_40_open(struct ast_filestream *s)
77 {
78         return g726_open(s, RATE_40);
79 }
80
81 static int g726_32_open(struct ast_filestream *s)
82 {
83         return g726_open(s, RATE_32);
84 }
85
86 static int g726_24_open(struct ast_filestream *s)
87 {
88         return g726_open(s, RATE_24);
89 }
90
91 static int g726_16_open(struct ast_filestream *s)
92 {
93         return g726_open(s, RATE_16);
94 }
95
96 static int g726_40_rewrite(struct ast_filestream *s, const char *comment)
97 {
98         return g726_open(s, RATE_40);
99 }
100
101 static int g726_32_rewrite(struct ast_filestream *s, const char *comment)
102 {
103         return g726_open(s, RATE_32);
104 }
105
106 static int g726_24_rewrite(struct ast_filestream *s, const char *comment)
107 {
108         return g726_open(s, RATE_24);
109 }
110
111 static int g726_16_rewrite(struct ast_filestream *s, const char *comment)
112 {
113         return g726_open(s, RATE_16);
114 }
115
116 /*
117  * Rate independent format functions (read, write)
118  */
119
120 static struct ast_frame *g726_read(struct ast_filestream *s, int *whennext)
121 {
122         int res;
123         struct g726_desc *fs = (struct g726_desc *)s->_private;
124
125         /* Send a frame from the file to the appropriate channel */
126         AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, frame_size[fs->rate]);
127         s->fr.samples = 8 * FRAME_TIME;
128         if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) {
129                 if (res)
130                         ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
131                 return NULL;
132         }
133         *whennext = s->fr.samples;
134         return &s->fr;
135 }
136
137 static int g726_write(struct ast_filestream *s, struct ast_frame *f)
138 {
139         int res;
140         struct g726_desc *fs = (struct g726_desc *)s->_private;
141
142         if (f->datalen % frame_size[fs->rate]) {
143                 ast_log(LOG_WARNING, "Invalid data length %d, should be multiple of %d\n", 
144                                                 f->datalen, frame_size[fs->rate]);
145                 return -1;
146         }
147         if ((res = fwrite(f->data.ptr, 1, f->datalen, s->f)) != f->datalen) {
148                 ast_log(LOG_WARNING, "Bad write (%d/%d): %s\n", 
149                                 res, frame_size[fs->rate], strerror(errno));
150                         return -1;
151         }
152         return 0;
153 }
154
155 static int g726_seek(struct ast_filestream *fs, off_t sample_offset, int whence)
156 {
157         return -1;
158 }
159
160 static int g726_trunc(struct ast_filestream *fs)
161 {
162         return -1;
163 }
164
165 static off_t g726_tell(struct ast_filestream *fs)
166 {
167         return -1;
168 }
169
170 static struct ast_format_def f[] = {
171         {
172                 .name = "g726-40",
173                 .exts = "g726-40",
174                 .open = g726_40_open,
175                 .rewrite = g726_40_rewrite,
176                 .write = g726_write,
177                 .seek = g726_seek,
178                 .trunc = g726_trunc,
179                 .tell = g726_tell,
180                 .read = g726_read,
181                 .buf_size = BUF_SIZE + AST_FRIENDLY_OFFSET,
182                 .desc_size = sizeof(struct g726_desc),
183         },
184         {
185                 .name = "g726-32",
186                 .exts = "g726-32",
187                 .open = g726_32_open,
188                 .rewrite = g726_32_rewrite,
189                 .write = g726_write,
190                 .seek = g726_seek,
191                 .trunc = g726_trunc,
192                 .tell = g726_tell,
193                 .read = g726_read,
194                 .buf_size = BUF_SIZE + AST_FRIENDLY_OFFSET,
195                 .desc_size = sizeof(struct g726_desc),
196         },
197         {
198                 .name = "g726-24",
199                 .exts = "g726-24",
200                 .open = g726_24_open,
201                 .rewrite = g726_24_rewrite,
202                 .write = g726_write,
203                 .seek = g726_seek,
204                 .trunc = g726_trunc,
205                 .tell = g726_tell,
206                 .read = g726_read,
207                 .buf_size = BUF_SIZE + AST_FRIENDLY_OFFSET,
208                 .desc_size = sizeof(struct g726_desc),
209         },
210         {
211                 .name = "g726-16",
212                 .exts = "g726-16",
213                 .open = g726_16_open,
214                 .rewrite = g726_16_rewrite,
215                 .write = g726_write,
216                 .seek = g726_seek,
217                 .trunc = g726_trunc,
218                 .tell = g726_tell,
219                 .read = g726_read,
220                 .buf_size = BUF_SIZE + AST_FRIENDLY_OFFSET,
221                 .desc_size = sizeof(struct g726_desc),
222         },
223         {       .desc_size = 0 }        /* terminator */
224 };
225
226 static int load_module(void)
227 {
228         int i;
229
230         for (i = 0; f[i].desc_size ; i++) {
231                 f[i].format = ast_format_g726;
232                 if (ast_format_def_register(&f[i])) {   /* errors are fatal */
233                         ast_log(LOG_WARNING, "Failed to register format %s.\n", f[i].name);
234                         return AST_MODULE_LOAD_FAILURE;
235                 }
236         }
237         return AST_MODULE_LOAD_SUCCESS;
238 }
239
240 static int unload_module(void)
241 {
242         int i;
243
244         for (i = 0; f[i].desc_size ; i++) {
245                 if (ast_format_def_unregister(f[i].name))
246                         ast_log(LOG_WARNING, "Failed to unregister format %s.\n", f[i].name);
247         }
248         return(0);
249 }
250
251 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Raw G.726 (16/24/32/40kbps) data",
252         .support_level = AST_MODULE_SUPPORT_CORE,
253         .load = load_module,
254         .unload = unload_module,
255         .load_pri = AST_MODPRI_APP_DEPEND
256 );