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