Asterisk - The Open Source Telephony Project GIT-master-a358458
format_g726.c
Go to the documentation of this file.
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#include "asterisk/mod_format.h"
38#include "asterisk/module.h"
39#include "asterisk/endian.h"
41
42#define RATE_40 0
43#define RATE_32 1
44#define RATE_24 2
45#define RATE_16 3
46
47/* We can only read/write chunks of FRAME_TIME ms G.726 data */
48#define FRAME_TIME 10 /* 10 ms size */
49
50#define BUF_SIZE (5*FRAME_TIME) /* max frame size in bytes ? */
51/* Frame sizes in bytes */
52static int frame_size[4] = {
53 FRAME_TIME * 5,
54 FRAME_TIME * 4,
55 FRAME_TIME * 3,
56 FRAME_TIME * 2
57};
58
59struct g726_desc {
60 int rate; /* RATE_* defines */
61};
62
63/*
64 * Rate dependant format functions (open, rewrite)
65 */
66static int g726_open(struct ast_filestream *tmp, int rate)
67{
68 struct g726_desc *s = (struct g726_desc *)tmp->_private;
69 s->rate = rate;
70 ast_debug(1, "Created filestream G.726-%dk.\n", 40 - s->rate * 8);
71 return 0;
72}
73
74static int g726_40_open(struct ast_filestream *s)
75{
76 return g726_open(s, RATE_40);
77}
78
79static int g726_32_open(struct ast_filestream *s)
80{
81 return g726_open(s, RATE_32);
82}
83
84static int g726_24_open(struct ast_filestream *s)
85{
86 return g726_open(s, RATE_24);
87}
88
89static int g726_16_open(struct ast_filestream *s)
90{
91 return g726_open(s, RATE_16);
92}
93
94static int g726_40_rewrite(struct ast_filestream *s, const char *comment)
95{
96 return g726_open(s, RATE_40);
97}
98
99static int g726_32_rewrite(struct ast_filestream *s, const char *comment)
100{
101 return g726_open(s, RATE_32);
102}
103
104static int g726_24_rewrite(struct ast_filestream *s, const char *comment)
105{
106 return g726_open(s, RATE_24);
107}
108
109static int g726_16_rewrite(struct ast_filestream *s, const char *comment)
110{
111 return g726_open(s, RATE_16);
112}
113
114/*
115 * Rate independent format functions (read, write)
116 */
117
118static struct ast_frame *g726_read(struct ast_filestream *s, int *whennext)
119{
120 size_t res;
121 struct g726_desc *fs = (struct g726_desc *)s->_private;
122
123 /* Send a frame from the file to the appropriate channel */
125 s->fr.samples = 8 * FRAME_TIME;
126 if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) {
127 if (res) {
128 ast_log(LOG_WARNING, "Short read of %s data (expected %d bytes, read %zu): %s\n",
130 strerror(errno));
131 }
132 return NULL;
133 }
134 *whennext = s->fr.samples;
135 return &s->fr;
136}
137
138static int g726_write(struct ast_filestream *s, struct ast_frame *f)
139{
140 int res;
141 struct g726_desc *fs = (struct g726_desc *)s->_private;
142
143 if (f->datalen % frame_size[fs->rate]) {
144 ast_log(LOG_WARNING, "Invalid data length %d, should be multiple of %d\n",
145 f->datalen, frame_size[fs->rate]);
146 return -1;
147 }
148 if ((res = fwrite(f->data.ptr, 1, f->datalen, s->f)) != f->datalen) {
149 ast_log(LOG_WARNING, "Bad write (%d/%d): %s\n",
150 res, frame_size[fs->rate], strerror(errno));
151 return -1;
152 }
153 return 0;
154}
155
156static int g726_seek(struct ast_filestream *fs, off_t sample_offset, int whence)
157{
158 off_t offset = 0, min = 0, cur, max, distance;
159
160 if ((cur = ftello(fs->f)) < 0) {
161 ast_log(AST_LOG_WARNING, "Unable to determine current position in g726 filestream %p: %s\n", fs, strerror(errno));
162 return -1;
163 }
164
165 if (fseeko(fs->f, 0, SEEK_END) < 0) {
166 ast_log(AST_LOG_WARNING, "Unable to seek to end of g726 filestream %p: %s\n", fs, strerror(errno));
167 return -1;
168 }
169
170 if ((max = ftello(fs->f)) < 0) {
171 ast_log(AST_LOG_WARNING, "Unable to determine max position in g726 filestream %p: %s\n", fs, strerror(errno));
172 return -1;
173 }
174
175 /* have to fudge to frame here, so not fully to sample */
176 distance = sample_offset / 2;
177 if (whence == SEEK_SET) {
178 offset = distance;
179 } else if (whence == SEEK_CUR || whence == SEEK_FORCECUR) {
180 offset = distance + cur;
181 } else if (whence == SEEK_END) {
182 offset = max - distance;
183 }
184
185 if (whence != SEEK_FORCECUR) {
186 offset = offset > max ? max : offset;
187 offset = offset < min ? min : offset;
188 }
189 return fseeko(fs->f, offset, SEEK_SET);
190}
191
192static int g726_trunc(struct ast_filestream *fs)
193{
194 return -1;
195}
196
197static off_t g726_tell(struct ast_filestream *fs)
198{
199 return ftello(fs->f) << 1;
200}
201
202static struct ast_format_def f_def[] = {
203 {
204 .name = "g726-40",
205 .exts = "g726-40",
206 .open = g726_40_open,
207 .rewrite = g726_40_rewrite,
208 .write = g726_write,
209 .seek = g726_seek,
210 .trunc = g726_trunc,
211 .tell = g726_tell,
212 .read = g726_read,
213 .buf_size = BUF_SIZE + AST_FRIENDLY_OFFSET,
214 .desc_size = sizeof(struct g726_desc),
215 },
216 {
217 .name = "g726-32",
218 .exts = "g726-32",
219 .open = g726_32_open,
220 .rewrite = g726_32_rewrite,
221 .write = g726_write,
222 .seek = g726_seek,
223 .trunc = g726_trunc,
224 .tell = g726_tell,
225 .read = g726_read,
226 .buf_size = BUF_SIZE + AST_FRIENDLY_OFFSET,
227 .desc_size = sizeof(struct g726_desc),
228 },
229 {
230 .name = "g726-24",
231 .exts = "g726-24",
232 .open = g726_24_open,
233 .rewrite = g726_24_rewrite,
234 .write = g726_write,
235 .seek = g726_seek,
236 .trunc = g726_trunc,
237 .tell = g726_tell,
238 .read = g726_read,
239 .buf_size = BUF_SIZE + AST_FRIENDLY_OFFSET,
240 .desc_size = sizeof(struct g726_desc),
241 },
242 {
243 .name = "g726-16",
244 .exts = "g726-16",
245 .open = g726_16_open,
246 .rewrite = g726_16_rewrite,
247 .write = g726_write,
248 .seek = g726_seek,
249 .trunc = g726_trunc,
250 .tell = g726_tell,
251 .read = g726_read,
252 .buf_size = BUF_SIZE + AST_FRIENDLY_OFFSET,
253 .desc_size = sizeof(struct g726_desc),
254 },
255 { .desc_size = 0 } /* terminator */
256};
257
258static int unload_module(void)
259{
260 int i;
261
262 for (i = 0; f_def[i].desc_size ; i++) {
264 ast_log(LOG_WARNING, "Failed to unregister format %s.\n", f_def[i].name);
265 }
266 return(0);
267}
268
269static int load_module(void)
270{
271 int i;
272
273 for (i = 0; f_def[i].desc_size ; i++) {
275 if (ast_format_def_register(&f_def[i])) { /* errors are fatal */
276 ast_log(LOG_WARNING, "Failed to register format %s.\n", f_def[i].name);
279 }
280 }
282}
283
284AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Raw G.726 (16/24/32/40kbps) data",
285 .support_level = AST_MODULE_SUPPORT_CORE,
286 .load = load_module,
287 .unload = unload_module,
288 .load_pri = AST_MODPRI_APP_DEPEND
#define comment
Definition: ael_lex.c:965
if(!yyg->yy_init)
Definition: ast_expr2f.c:854
Asterisk main include file. File version handling, generic pbx functions.
#define ast_log
Definition: astobj2.c:42
static int tmp()
Definition: bt_open.c:389
Asterisk architecture endianess compatibility definitions.
#define min(a, b)
Definition: f2c.h:197
#define max(a, b)
Definition: f2c.h:198
#define SEEK_FORCECUR
Definition: file.h:51
const char * ast_format_get_name(const struct ast_format *format)
Get the name associated with a format.
Definition: format.c:334
Media Format Cache API.
struct ast_format * ast_format_g726
Built-in cached g726 format.
Definition: format_cache.c:111
static struct ast_frame * g726_read(struct ast_filestream *s, int *whennext)
Definition: format_g726.c:118
#define RATE_16
Definition: format_g726.c:45
static int g726_32_open(struct ast_filestream *s)
Definition: format_g726.c:79
static int g726_write(struct ast_filestream *s, struct ast_frame *f)
Definition: format_g726.c:138
static int g726_40_rewrite(struct ast_filestream *s, const char *comment)
Definition: format_g726.c:94
static int g726_open(struct ast_filestream *tmp, int rate)
Definition: format_g726.c:66
static int g726_40_open(struct ast_filestream *s)
Definition: format_g726.c:74
#define BUF_SIZE
Definition: format_g726.c:50
#define RATE_32
Definition: format_g726.c:43
static int g726_16_open(struct ast_filestream *s)
Definition: format_g726.c:89
static int g726_24_rewrite(struct ast_filestream *s, const char *comment)
Definition: format_g726.c:104
static int g726_16_rewrite(struct ast_filestream *s, const char *comment)
Definition: format_g726.c:109
#define FRAME_TIME
Definition: format_g726.c:48
#define RATE_40
Definition: format_g726.c:42
static int frame_size[4]
Definition: format_g726.c:52
static int g726_32_rewrite(struct ast_filestream *s, const char *comment)
Definition: format_g726.c:99
#define RATE_24
Definition: format_g726.c:44
static int load_module(void)
Definition: format_g726.c:269
static int unload_module(void)
Definition: format_g726.c:258
static int g726_trunc(struct ast_filestream *fs)
Definition: format_g726.c:192
static int g726_24_open(struct ast_filestream *s)
Definition: format_g726.c:84
static off_t g726_tell(struct ast_filestream *fs)
Definition: format_g726.c:197
static struct ast_format_def f_def[]
Definition: format_g726.c:202
static int g726_seek(struct ast_filestream *fs, off_t sample_offset, int whence)
Definition: format_g726.c:156
static const char name[]
Definition: format_mp3.c:68
#define AST_FRAME_SET_BUFFER(fr, _base, _ofs, _datalen)
#define AST_FRIENDLY_OFFSET
Offset into a frame's data buffer.
#define AST_LOG_WARNING
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_WARNING
int errno
Header for providers of file and format handling routines. Clients of these routines should include "...
int ast_format_def_unregister(const char *name)
Unregisters a file format.
Definition: file.c:162
#define ast_format_def_register(f)
Definition: mod_format.h:136
Asterisk module definitions.
@ AST_MODFLAG_LOAD_ORDER
Definition: module.h:317
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:543
@ AST_MODPRI_APP_DEPEND
Definition: module.h:328
@ AST_MODULE_SUPPORT_CORE
Definition: module.h:121
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
#define NULL
Definition: resample.c:96
This structure is allocated by file.c in one chunk, together with buf_size and desc_size bytes of mem...
Definition: mod_format.h:101
struct ast_frame fr
frame produced by read, typically
Definition: mod_format.h:122
void * _private
Definition: mod_format.h:124
Each supported file format is described by the following structure.
Definition: mod_format.h:43
char name[80]
Definition: mod_format.h:44
struct ast_format * format
Definition: mod_format.h:48
struct ast_format * format
Data structure associated with a single frame of data.
struct ast_frame_subclass subclass
union ast_frame::@226 data