- Fix the last set of places where incorrect assumptions were made about the
[asterisk/asterisk.git] / codecs / codec_g722.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2008, Digium, Inc.
5  *
6  * Matthew Fredrickson <creslin@digium.com>
7  * Russell Bryant <russell@digium.com>
8  *
9  * Special thanks to Steve Underwood for the implementation
10  * and for doing the 8khz<->g.722 direct translation code.
11  *
12  * See http://www.asterisk.org for more information about
13  * the Asterisk project. Please do not directly contact
14  * any of the maintainers of this project for assistance;
15  * the project provides a web site, mailing lists and IRC
16  * channels for your use.
17  *
18  * This program is free software, distributed under the terms of
19  * the GNU General Public License Version 2. See the LICENSE file
20  * at the top of the source tree.
21  */
22
23 /*! \file
24  *
25  * \brief codec_g722.c - translate between signed linear and ITU G.722-64kbps
26  *
27  * \author Matthew Fredrickson <creslin@digium.com>
28  * \author Russell Bryant <russell@digium.com>
29  *
30  * \arg http://soft-switch.org/downloads/non-gpl-bits.tgz
31  * \arg http://lists.digium.com/pipermail/asterisk-dev/2006-September/022866.html
32  *
33  * \ingroup codecs
34  */
35
36 #include "asterisk.h"
37
38 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
39
40 #include "asterisk/linkedlists.h"
41 #include "asterisk/module.h"
42 #include "asterisk/config.h"
43 #include "asterisk/translate.h"
44 #include "asterisk/utils.h"
45
46 #define BUFFER_SAMPLES   8096   /* size for the translation buffers */
47 #define BUF_SHIFT       5
48
49 /* Sample frame data */
50
51 #include "g722/g722.h"
52 #include "slin_g722_ex.h"
53 #include "g722_slin_ex.h"
54
55 struct g722_encoder_pvt {
56         g722_encode_state_t g722;
57 };
58
59 struct g722_decoder_pvt {
60         g722_decode_state_t g722;
61 };
62
63 /*! \brief init a new instance of g722_encoder_pvt. */
64 static int lintog722_new(struct ast_trans_pvt *pvt)
65 {
66         struct g722_encoder_pvt *tmp = pvt->pvt;
67
68         g722_encode_init(&tmp->g722, 64000, G722_SAMPLE_RATE_8000);
69
70         return 0;
71 }
72
73 static int lin16tog722_new(struct ast_trans_pvt *pvt)
74 {
75         struct g722_encoder_pvt *tmp = pvt->pvt;
76
77         g722_encode_init(&tmp->g722, 64000, 0);
78
79         return 0;
80 }
81
82 /*! \brief init a new instance of g722_encoder_pvt. */
83 static int g722tolin_new(struct ast_trans_pvt *pvt)
84 {
85         struct g722_decoder_pvt *tmp = pvt->pvt;
86
87         g722_decode_init(&tmp->g722, 64000, G722_SAMPLE_RATE_8000);
88
89         return 0;
90 }
91
92 static int g722tolin16_new(struct ast_trans_pvt *pvt)
93 {
94         struct g722_decoder_pvt *tmp = pvt->pvt;
95
96         g722_decode_init(&tmp->g722, 64000, 0);
97
98         return 0;
99 }
100
101 static int g722tolin_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
102 {
103         struct g722_decoder_pvt *tmp = pvt->pvt;
104         unsigned char *src = f->data;
105         int out_samples;
106
107         out_samples = g722_decode(&tmp->g722, (int16_t *) &pvt->outbuf[pvt->samples * sizeof(int16_t)], 
108                 src, f->samples);
109
110         pvt->samples += out_samples;
111
112         pvt->datalen += (out_samples * sizeof(int16_t));
113
114         return 0;
115 }
116
117 static int g722tolin16_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
118 {
119         struct g722_decoder_pvt *tmp = pvt->pvt;
120         int out_samples;
121
122         out_samples = g722_decode(&tmp->g722, (int16_t *) &pvt->outbuf[pvt->samples * sizeof(int16_t)], 
123                 (uint8_t *) f->data, f->samples);
124
125         /* sample rate the same between formats, but don't assume that it won't output more ... */
126         pvt->samples += out_samples;
127
128         pvt->datalen += (out_samples * sizeof(int16_t));
129
130         return 0;
131 }
132
133 static int lintog722_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
134 {
135         struct g722_encoder_pvt *tmp = pvt->pvt;
136         int outlen;
137
138         outlen = g722_encode(&tmp->g722, (uint8_t *) (&pvt->outbuf[pvt->datalen]), 
139                 (int16_t *) f->data, f->samples);
140
141         pvt->samples += outlen;
142
143         pvt->datalen += outlen;
144
145         return 0;
146 }
147
148 static int lin16tog722_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
149 {
150         struct g722_encoder_pvt *tmp = pvt->pvt;
151         int16_t *src = f->data;
152         int outlen;
153
154         outlen = g722_encode(&tmp->g722, (uint8_t*)(&pvt->outbuf[pvt->datalen]), src, f->samples);
155
156         pvt->samples += outlen;
157
158         pvt->datalen += outlen;
159
160         return 0;
161 }
162
163 static struct ast_frame *g722tolin_sample(void)
164 {
165         static struct ast_frame f = {
166                 .frametype = AST_FRAME_VOICE,
167                 .subclass = AST_FORMAT_G722,
168                 .datalen = sizeof(g722_slin_ex),
169                 .samples = sizeof(g722_slin_ex) * 2,
170                 .src = __PRETTY_FUNCTION__,
171                 .data = g722_slin_ex,
172         };
173
174         return &f;
175 }
176
177 static struct ast_frame *g722tolin16_sample(void)
178 {
179         static struct ast_frame f = {
180                 .frametype = AST_FRAME_VOICE,
181                 .subclass = AST_FORMAT_G722,
182                 .datalen = sizeof(slin_g722_ex),
183                 .samples = sizeof(slin_g722_ex) * 2,
184                 .src = __PRETTY_FUNCTION__,
185                 .data = slin_g722_ex,
186         };
187
188         return &f;
189 }
190
191 static struct ast_frame *lintog722_sample (void)
192 {
193         static struct ast_frame f = {
194                 .frametype = AST_FRAME_VOICE,
195                 .subclass = AST_FORMAT_SLINEAR,
196                 .datalen = sizeof(slin_g722_ex),
197                 .samples = sizeof(slin_g722_ex) / sizeof(slin_g722_ex[0]),
198                 .src = __PRETTY_FUNCTION__,
199                 .data = slin_g722_ex,
200         };
201
202         return &f;
203 }
204
205 static struct ast_frame *lin16tog722_sample (void)
206 {
207         static struct ast_frame f = {
208                 .frametype = AST_FRAME_VOICE,
209                 .subclass = AST_FORMAT_SLINEAR16,
210                 .datalen = sizeof(slin_g722_ex),
211                 .samples = sizeof(slin_g722_ex) / sizeof(slin_g722_ex[0]),
212                 .src = __PRETTY_FUNCTION__,
213                 .data = slin_g722_ex,
214         };
215
216         return &f;
217 }
218
219 static struct ast_translator g722tolin = {
220         .name = "g722tolin",
221         .srcfmt = AST_FORMAT_G722,
222         .dstfmt = AST_FORMAT_SLINEAR,
223         .newpvt = g722tolin_new,        /* same for both directions */
224         .framein = g722tolin_framein,
225         .sample = g722tolin_sample,
226         .desc_size = sizeof(struct g722_decoder_pvt),
227         .buffer_samples = BUFFER_SAMPLES / sizeof(int16_t),
228         .buf_size = BUFFER_SAMPLES,
229         .plc_samples = 160,
230 };
231
232 static struct ast_translator lintog722 = {
233         .name = "lintog722",
234         .srcfmt = AST_FORMAT_SLINEAR,
235         .dstfmt = AST_FORMAT_G722,
236         .newpvt = lintog722_new,        /* same for both directions */
237         .framein = lintog722_framein,
238         .sample = lintog722_sample,
239         .desc_size = sizeof(struct g722_encoder_pvt),
240         .buffer_samples = BUFFER_SAMPLES * 2,
241         .buf_size = BUFFER_SAMPLES,
242 };
243
244 static struct ast_translator g722tolin16 = {
245         .name = "g722tolin16",
246         .srcfmt = AST_FORMAT_G722,
247         .dstfmt = AST_FORMAT_SLINEAR16,
248         .newpvt = g722tolin16_new,      /* same for both directions */
249         .framein = g722tolin16_framein,
250         .sample = g722tolin16_sample,
251         .desc_size = sizeof(struct g722_decoder_pvt),
252         .buffer_samples = BUFFER_SAMPLES / sizeof(int16_t),
253         .buf_size = BUFFER_SAMPLES,
254         .plc_samples = 160,
255 };
256
257 static struct ast_translator lin16tog722 = {
258         .name = "lin16tog722",
259         .srcfmt = AST_FORMAT_SLINEAR16,
260         .dstfmt = AST_FORMAT_G722,
261         .newpvt = lin16tog722_new,      /* same for both directions */
262         .framein = lin16tog722_framein,
263         .sample = lin16tog722_sample,
264         .desc_size = sizeof(struct g722_encoder_pvt),
265         .buffer_samples = BUFFER_SAMPLES * 2,
266         .buf_size = BUFFER_SAMPLES,
267 };
268
269 static int parse_config(int reload)
270 {
271         struct ast_variable *var;
272         struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
273         struct ast_config *cfg = ast_config_load("codecs.conf", config_flags);
274
275         if (cfg == NULL)
276                 return 0;
277         if (cfg == CONFIG_STATUS_FILEUNCHANGED)
278                 return 0;
279         for (var = ast_variable_browse(cfg, "plc"); var; var = var->next) {
280                 if (!strcasecmp(var->name, "genericplc")) {
281                         g722tolin.useplc = ast_true(var->value) ? 1 : 0;
282                         ast_verb(3, "codec_g722: %susing generic PLC\n",
283                                         g722tolin.useplc ? "" : "not ");
284                 }
285         }
286         ast_config_destroy(cfg);
287         return 0;
288 }
289
290 static int reload(void)
291 {
292         if (parse_config(1))
293                 return AST_MODULE_LOAD_DECLINE;
294         return AST_MODULE_LOAD_SUCCESS;
295 }
296
297 static int unload_module(void)
298 {
299         int res = 0;
300
301         res |= ast_unregister_translator(&g722tolin);
302         res |= ast_unregister_translator(&lintog722);
303         res |= ast_unregister_translator(&g722tolin16);
304         res |= ast_unregister_translator(&lin16tog722);
305
306         return res;
307 }
308
309 static int load_module(void)
310 {
311         int res = 0;
312
313         if (parse_config(0))
314                 return AST_MODULE_LOAD_DECLINE;
315
316         res |= ast_register_translator(&g722tolin);
317         res |= ast_register_translator(&lintog722);
318         res |= ast_register_translator(&g722tolin16);
319         res |= ast_register_translator(&lin16tog722);
320
321         if (res) {
322                 unload_module();
323                 return AST_MODULE_LOAD_FAILURE;
324         }       
325
326         return AST_MODULE_LOAD_SUCCESS;
327 }
328
329 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "ITU G.722-64kbps G722 Transcoder",
330                 .load = load_module,
331                 .unload = unload_module,
332                 .reload = reload,
333                );