Asterisk - The Open Source Telephony Project  GIT-master-0190e70
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"
40 #include "asterisk/format_cache.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 */
52 static int frame_size[4] = {
53  FRAME_TIME * 5,
54  FRAME_TIME * 4,
55  FRAME_TIME * 3,
56  FRAME_TIME * 2
57 };
58 
59 struct g726_desc {
60  int rate; /* RATE_* defines */
61 };
62 
63 /*
64  * Rate dependant format functions (open, rewrite)
65  */
66 static 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 
74 static int g726_40_open(struct ast_filestream *s)
75 {
76  return g726_open(s, RATE_40);
77 }
78 
79 static int g726_32_open(struct ast_filestream *s)
80 {
81  return g726_open(s, RATE_32);
82 }
83 
84 static int g726_24_open(struct ast_filestream *s)
85 {
86  return g726_open(s, RATE_24);
87 }
88 
89 static int g726_16_open(struct ast_filestream *s)
90 {
91  return g726_open(s, RATE_16);
92 }
93 
94 static int g726_40_rewrite(struct ast_filestream *s, const char *comment)
95 {
96  return g726_open(s, RATE_40);
97 }
98 
99 static int g726_32_rewrite(struct ast_filestream *s, const char *comment)
100 {
101  return g726_open(s, RATE_32);
102 }
103 
104 static int g726_24_rewrite(struct ast_filestream *s, const char *comment)
105 {
106  return g726_open(s, RATE_24);
107 }
108 
109 static 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 
118 static 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 
138 static 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 
156 static 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 
192 static int g726_trunc(struct ast_filestream *fs)
193 {
194  return -1;
195 }
196 
197 static off_t g726_tell(struct ast_filestream *fs)
198 {
199  return ftello(fs->f) << 1;
200 }
201 
202 static 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 
258 static int unload_module(void)
259 {
260  int i;
261 
262  for (i = 0; f_def[i].desc_size ; i++) {
263  if (ast_format_def_unregister(f_def[i].name))
264  ast_log(LOG_WARNING, "Failed to unregister format %s.\n", f_def[i].name);
265  }
266  return(0);
267 }
268 
269 static int load_module(void)
270 {
271  int i;
272 
273  for (i = 0; f_def[i].desc_size ; i++) {
274  f_def[i].format = ast_format_g726;
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);
277  unload_module();
279  }
280  }
282 }
283 
284 AST_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
289 );
struct ast_format * ast_format_g726
Built-in cached g726 format.
Definition: format_cache.c:116
Asterisk main include file. File version handling, generic pbx functions.
static int load_module(void)
Definition: format_g726.c:269
#define RATE_24
Definition: format_g726.c:44
static int g726_16_rewrite(struct ast_filestream *s, const char *comment)
Definition: format_g726.c:109
#define LOG_WARNING
Definition: logger.h:274
union ast_frame::@257 data
static int g726_open(struct ast_filestream *tmp, int rate)
Definition: format_g726.c:66
static int tmp()
Definition: bt_open.c:389
#define AST_LOG_WARNING
Definition: logger.h:279
static int g726_16_open(struct ast_filestream *s)
Definition: format_g726.c:89
if(!yyg->yy_init)
Definition: ast_expr2f.c:868
const char * ast_format_get_name(const struct ast_format *format)
Get the name associated with a format.
Definition: format.c:334
#define NULL
Definition: resample.c:96
Each supported file format is described by the following structure.
Definition: mod_format.h:43
struct ast_frame_subclass subclass
Header for providers of file and format handling routines. Clients of these routines should include "...
static int g726_seek(struct ast_filestream *fs, off_t sample_offset, int whence)
Definition: format_g726.c:156
int ast_format_def_unregister(const char *name)
Unregisters a file format.
Definition: file.c:162
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:444
#define ast_log
Definition: astobj2.c:42
static int g726_trunc(struct ast_filestream *fs)
Definition: format_g726.c:192
static int g726_write(struct ast_filestream *s, struct ast_frame *f)
Definition: format_g726.c:138
#define AST_FRIENDLY_OFFSET
Offset into a frame&#39;s data buffer.
Asterisk architecture endianess compatibility definitions.
#define ast_format_def_register(f)
Definition: mod_format.h:136
struct ast_frame fr
frame produced by read, typically
Definition: mod_format.h:122
#define BUF_SIZE
Definition: format_g726.c:50
static int g726_32_rewrite(struct ast_filestream *s, const char *comment)
Definition: format_g726.c:99
struct ast_format * format
Definition: mod_format.h:48
static int g726_32_open(struct ast_filestream *s)
Definition: format_g726.c:79
void * _private
Definition: mod_format.h:124
#define AST_FRAME_SET_BUFFER(fr, _base, _ofs, _datalen)
static int g726_40_open(struct ast_filestream *s)
Definition: format_g726.c:74
static int g726_24_rewrite(struct ast_filestream *s, const char *comment)
Definition: format_g726.c:104
static struct ast_frame * g726_read(struct ast_filestream *s, int *whennext)
Definition: format_g726.c:118
#define RATE_40
Definition: format_g726.c:42
int errno
#define comment
Definition: ael_lex.c:976
char name[80]
Definition: mod_format.h:44
#define SEEK_FORCECUR
Definition: file.h:51
static const char name[]
Definition: cdr_mysql.c:74
static int g726_40_rewrite(struct ast_filestream *s, const char *comment)
Definition: format_g726.c:94
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
#define RATE_32
Definition: format_g726.c:43
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS|AST_MODFLAG_LOAD_ORDER, "HTTP Phone Provisioning",.support_level=AST_MODULE_SUPPORT_EXTENDED,.load=load_module,.unload=unload_module,.reload=reload,.load_pri=AST_MODPRI_CHANNEL_DEPEND,.requires="http",)
static struct ast_format_def f_def[]
Definition: format_g726.c:202
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
static off_t g726_tell(struct ast_filestream *fs)
Definition: format_g726.c:197
Data structure associated with a single frame of data.
static int g726_24_open(struct ast_filestream *s)
Definition: format_g726.c:84
static int unload_module(void)
Definition: format_g726.c:258
struct ast_format * format
#define FRAME_TIME
Definition: format_g726.c:48
#define RATE_16
Definition: format_g726.c:45
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
Asterisk module definitions.
#define min(a, b)
Definition: f2c.h:197
Media Format Cache API.
static int frame_size[4]
Definition: format_g726.c:52
#define max(a, b)
Definition: f2c.h:198