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