00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #include "asterisk.h"
00036
00037 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 328209 $")
00038
00039 #include "asterisk/mod_format.h"
00040 #include "asterisk/module.h"
00041 #include "asterisk/endian.h"
00042
00043 #define RATE_40 0
00044 #define RATE_32 1
00045 #define RATE_24 2
00046 #define RATE_16 3
00047
00048
00049 #define FRAME_TIME 10
00050
00051 #define BUF_SIZE (5*FRAME_TIME)
00052
00053 static int frame_size[4] = {
00054 FRAME_TIME * 5,
00055 FRAME_TIME * 4,
00056 FRAME_TIME * 3,
00057 FRAME_TIME * 2
00058 };
00059
00060 struct g726_desc {
00061 int rate;
00062 };
00063
00064
00065
00066
00067 static int g726_open(struct ast_filestream *tmp, int rate)
00068 {
00069 struct g726_desc *s = (struct g726_desc *)tmp->_private;
00070 s->rate = rate;
00071 ast_debug(1, "Created filestream G.726-%dk.\n", 40 - s->rate * 8);
00072 return 0;
00073 }
00074
00075 static int g726_40_open(struct ast_filestream *s)
00076 {
00077 return g726_open(s, RATE_40);
00078 }
00079
00080 static int g726_32_open(struct ast_filestream *s)
00081 {
00082 return g726_open(s, RATE_32);
00083 }
00084
00085 static int g726_24_open(struct ast_filestream *s)
00086 {
00087 return g726_open(s, RATE_24);
00088 }
00089
00090 static int g726_16_open(struct ast_filestream *s)
00091 {
00092 return g726_open(s, RATE_16);
00093 }
00094
00095 static int g726_40_rewrite(struct ast_filestream *s, const char *comment)
00096 {
00097 return g726_open(s, RATE_40);
00098 }
00099
00100 static int g726_32_rewrite(struct ast_filestream *s, const char *comment)
00101 {
00102 return g726_open(s, RATE_32);
00103 }
00104
00105 static int g726_24_rewrite(struct ast_filestream *s, const char *comment)
00106 {
00107 return g726_open(s, RATE_24);
00108 }
00109
00110 static int g726_16_rewrite(struct ast_filestream *s, const char *comment)
00111 {
00112 return g726_open(s, RATE_16);
00113 }
00114
00115
00116
00117
00118
00119 static struct ast_frame *g726_read(struct ast_filestream *s, int *whennext)
00120 {
00121 int res;
00122 struct g726_desc *fs = (struct g726_desc *)s->_private;
00123
00124
00125 s->fr.frametype = AST_FRAME_VOICE;
00126 s->fr.subclass.codec = AST_FORMAT_G726;
00127 s->fr.mallocd = 0;
00128 AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, frame_size[fs->rate]);
00129 s->fr.samples = 8 * FRAME_TIME;
00130 if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) {
00131 if (res)
00132 ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
00133 return NULL;
00134 }
00135 *whennext = s->fr.samples;
00136 return &s->fr;
00137 }
00138
00139 static int g726_write(struct ast_filestream *s, struct ast_frame *f)
00140 {
00141 int res;
00142 struct g726_desc *fs = (struct g726_desc *)s->_private;
00143
00144 if (f->frametype != AST_FRAME_VOICE) {
00145 ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
00146 return -1;
00147 }
00148 if (f->subclass.codec != AST_FORMAT_G726) {
00149 ast_log(LOG_WARNING, "Asked to write non-G726 frame (%s)!\n",
00150 ast_getformatname(f->subclass.codec));
00151 return -1;
00152 }
00153 if (f->datalen % frame_size[fs->rate]) {
00154 ast_log(LOG_WARNING, "Invalid data length %d, should be multiple of %d\n",
00155 f->datalen, frame_size[fs->rate]);
00156 return -1;
00157 }
00158 if ((res = fwrite(f->data.ptr, 1, f->datalen, s->f)) != f->datalen) {
00159 ast_log(LOG_WARNING, "Bad write (%d/%d): %s\n",
00160 res, frame_size[fs->rate], strerror(errno));
00161 return -1;
00162 }
00163 return 0;
00164 }
00165
00166 static int g726_seek(struct ast_filestream *fs, off_t sample_offset, int whence)
00167 {
00168 return -1;
00169 }
00170
00171 static int g726_trunc(struct ast_filestream *fs)
00172 {
00173 return -1;
00174 }
00175
00176 static off_t g726_tell(struct ast_filestream *fs)
00177 {
00178 return -1;
00179 }
00180
00181 static const struct ast_format f[] = {
00182 {
00183 .name = "g726-40",
00184 .exts = "g726-40",
00185 .format = AST_FORMAT_G726,
00186 .open = g726_40_open,
00187 .rewrite = g726_40_rewrite,
00188 .write = g726_write,
00189 .seek = g726_seek,
00190 .trunc = g726_trunc,
00191 .tell = g726_tell,
00192 .read = g726_read,
00193 .buf_size = BUF_SIZE + AST_FRIENDLY_OFFSET,
00194 .desc_size = sizeof(struct g726_desc),
00195 },
00196 {
00197 .name = "g726-32",
00198 .exts = "g726-32",
00199 .format = AST_FORMAT_G726,
00200 .open = g726_32_open,
00201 .rewrite = g726_32_rewrite,
00202 .write = g726_write,
00203 .seek = g726_seek,
00204 .trunc = g726_trunc,
00205 .tell = g726_tell,
00206 .read = g726_read,
00207 .buf_size = BUF_SIZE + AST_FRIENDLY_OFFSET,
00208 .desc_size = sizeof(struct g726_desc),
00209 },
00210 {
00211 .name = "g726-24",
00212 .exts = "g726-24",
00213 .format = AST_FORMAT_G726,
00214 .open = g726_24_open,
00215 .rewrite = g726_24_rewrite,
00216 .write = g726_write,
00217 .seek = g726_seek,
00218 .trunc = g726_trunc,
00219 .tell = g726_tell,
00220 .read = g726_read,
00221 .buf_size = BUF_SIZE + AST_FRIENDLY_OFFSET,
00222 .desc_size = sizeof(struct g726_desc),
00223 },
00224 {
00225 .name = "g726-16",
00226 .exts = "g726-16",
00227 .format = AST_FORMAT_G726,
00228 .open = g726_16_open,
00229 .rewrite = g726_16_rewrite,
00230 .write = g726_write,
00231 .seek = g726_seek,
00232 .trunc = g726_trunc,
00233 .tell = g726_tell,
00234 .read = g726_read,
00235 .buf_size = BUF_SIZE + AST_FRIENDLY_OFFSET,
00236 .desc_size = sizeof(struct g726_desc),
00237 },
00238 { .format = 0 }
00239 };
00240
00241 static int load_module(void)
00242 {
00243 int i;
00244
00245 for (i = 0; f[i].format ; i++) {
00246 if (ast_format_register(&f[i])) {
00247 ast_log(LOG_WARNING, "Failed to register format %s.\n", f[i].name);
00248 return AST_MODULE_LOAD_FAILURE;
00249 }
00250 }
00251 return AST_MODULE_LOAD_SUCCESS;
00252 }
00253
00254 static int unload_module(void)
00255 {
00256 int i;
00257
00258 for (i = 0; f[i].format ; i++) {
00259 if (ast_format_unregister(f[i].name))
00260 ast_log(LOG_WARNING, "Failed to unregister format %s.\n", f[i].name);
00261 }
00262 return(0);
00263 }
00264
00265 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Raw G.726 (16/24/32/40kbps) data",
00266 .load = load_module,
00267 .unload = unload_module,
00268 .load_pri = AST_MODPRI_APP_DEPEND
00269 );