codecs.conf really shouldn't be mandatory.. it never had been before, so let's go...
[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  * \ingroup codecs
27  */
28
29 #include "asterisk.h"
30
31 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
32
33 #include "asterisk/linkedlists.h"
34 #include "asterisk/module.h"
35 #include "asterisk/config.h"
36 #include "asterisk/translate.h"
37 #include "asterisk/utils.h"
38
39 #define BUFFER_SAMPLES   8096   /* size for the translation buffers */
40 #define BUF_SHIFT       5
41
42 /* Sample frame data */
43
44 #include "g722/g722.h"
45 #include "slin_g722_ex.h"
46 #include "g722_slin_ex.h"
47
48 struct g722_encoder_pvt {
49         g722_encode_state_t g722;
50 };
51
52 struct g722_decoder_pvt {
53         g722_decode_state_t g722;
54 };
55
56 /*! \brief init a new instance of g722_encoder_pvt. */
57 static int lintog722_new(struct ast_trans_pvt *pvt)
58 {
59         struct g722_encoder_pvt *tmp = pvt->pvt;
60
61         g722_encode_init(&tmp->g722, 64000, G722_SAMPLE_RATE_8000);
62
63         return 0;
64 }
65
66 static int lin16tog722_new(struct ast_trans_pvt *pvt)
67 {
68         struct g722_encoder_pvt *tmp = pvt->pvt;
69
70         g722_encode_init(&tmp->g722, 64000, 0);
71
72         return 0;
73 }
74
75 /*! \brief init a new instance of g722_encoder_pvt. */
76 static int g722tolin_new(struct ast_trans_pvt *pvt)
77 {
78         struct g722_decoder_pvt *tmp = pvt->pvt;
79
80         g722_decode_init(&tmp->g722, 64000, G722_SAMPLE_RATE_8000);
81
82         return 0;
83 }
84
85 static int g722tolin16_new(struct ast_trans_pvt *pvt)
86 {
87         struct g722_decoder_pvt *tmp = pvt->pvt;
88
89         g722_decode_init(&tmp->g722, 64000, 0);
90
91         return 0;
92 }
93
94 static int g722tolin_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
95 {
96         struct g722_decoder_pvt *tmp = pvt->pvt;
97         unsigned char *src = f->data;
98         int16_t *dst = (int16_t *) pvt->outbuf + pvt->samples;
99
100         g722_decode(&tmp->g722, dst, src, f->samples);
101         pvt->samples += f->samples;
102         pvt->datalen += 2 * f->samples;
103
104         return 0;
105 }
106
107 static int lintog722_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
108 {
109         struct g722_encoder_pvt *tmp = pvt->pvt;
110         int16_t *src = f->data;
111
112         g722_encode(&tmp->g722, (uint8_t*)(&pvt->outbuf[pvt->datalen]), src, f->samples);
113         /* Since G.722 64kbps per second is one bye per sample, all of these
114            calculations are easy */
115         pvt->samples += f->samples;
116         pvt->datalen += f->samples;
117
118         return 0;
119 }
120
121 static struct ast_frame *g722tolin_sample(void)
122 {
123         static struct ast_frame f = {
124                 .frametype = AST_FRAME_VOICE,
125                 .subclass = AST_FORMAT_G722,
126                 .datalen = sizeof(g722_slin_ex),
127                 .samples = sizeof(g722_slin_ex) / sizeof(g722_slin_ex[0]),
128                 .src = __PRETTY_FUNCTION__,
129                 .data = g722_slin_ex,
130         };
131
132         return &f;
133 }
134
135 static struct ast_frame *g722tolin16_sample(void)
136 {
137         static struct ast_frame f = {
138                 .frametype = AST_FRAME_VOICE,
139                 .subclass = AST_FORMAT_G722,
140                 .datalen = sizeof(slin_g722_ex),
141                 .samples = sizeof(slin_g722_ex) / sizeof(slin_g722_ex[0]),
142                 .src = __PRETTY_FUNCTION__,
143                 .data = slin_g722_ex,
144         };
145
146         return &f;
147 }
148
149 static struct ast_frame *lintog722_sample (void)
150 {
151         static struct ast_frame f = {
152                 .frametype = AST_FRAME_VOICE,
153                 .subclass = AST_FORMAT_SLINEAR,
154                 .datalen = sizeof(slin_g722_ex),
155                 .samples = sizeof(slin_g722_ex) / sizeof(slin_g722_ex[0]),
156                 .src = __PRETTY_FUNCTION__,
157                 .data = slin_g722_ex,
158         };
159
160         return &f;
161 }
162
163 static struct ast_frame *lin16tog722_sample (void)
164 {
165         static struct ast_frame f = {
166                 .frametype = AST_FRAME_VOICE,
167                 .subclass = AST_FORMAT_SLINEAR16,
168                 .datalen = sizeof(slin_g722_ex),
169                 .samples = sizeof(slin_g722_ex) / sizeof(slin_g722_ex[0]),
170                 .src = __PRETTY_FUNCTION__,
171                 .data = slin_g722_ex,
172         };
173
174         return &f;
175 }
176
177 static struct ast_translator g722tolin = {
178         .name = "g722tolin",
179         .srcfmt = AST_FORMAT_G722,
180         .dstfmt = AST_FORMAT_SLINEAR,
181         .newpvt = g722tolin_new,        /* same for both directions */
182         .framein = g722tolin_framein,
183         .sample = g722tolin_sample,
184         .desc_size = sizeof(struct g722_decoder_pvt),
185         .buffer_samples = BUFFER_SAMPLES,
186         .buf_size = BUFFER_SAMPLES,
187         .plc_samples = 160,
188 };
189
190 static struct ast_translator lintog722 = {
191         .name = "lintog722",
192         .srcfmt = AST_FORMAT_SLINEAR,
193         .dstfmt = AST_FORMAT_G722,
194         .newpvt = lintog722_new,        /* same for both directions */
195         .framein = lintog722_framein,
196         .sample = lintog722_sample,
197         .desc_size = sizeof(struct g722_encoder_pvt),
198         .buffer_samples = BUFFER_SAMPLES,
199         .buf_size = BUFFER_SAMPLES,
200 };
201
202 static struct ast_translator g722tolin16 = {
203         .name = "g722tolin16",
204         .srcfmt = AST_FORMAT_G722,
205         .dstfmt = AST_FORMAT_SLINEAR16,
206         .newpvt = g722tolin16_new,      /* same for both directions */
207         .framein = g722tolin_framein,
208         .sample = g722tolin16_sample,
209         .desc_size = sizeof(struct g722_decoder_pvt),
210         .buffer_samples = BUFFER_SAMPLES,
211         .buf_size = BUFFER_SAMPLES,
212         .plc_samples = 160,
213 };
214
215 static struct ast_translator lin16tog722 = {
216         .name = "lin16tog722",
217         .srcfmt = AST_FORMAT_SLINEAR16,
218         .dstfmt = AST_FORMAT_G722,
219         .newpvt = lin16tog722_new,      /* same for both directions */
220         .framein = lintog722_framein,
221         .sample = lin16tog722_sample,
222         .desc_size = sizeof(struct g722_encoder_pvt),
223         .buffer_samples = BUFFER_SAMPLES,
224         .buf_size = BUFFER_SAMPLES,
225 };
226
227 static int parse_config(int reload)
228 {
229         struct ast_variable *var;
230         struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
231         struct ast_config *cfg = ast_config_load("codecs.conf", config_flags);
232
233         if (cfg == NULL)
234                 return 0;
235         if (cfg == CONFIG_STATUS_FILEUNCHANGED)
236                 return 0;
237         for (var = ast_variable_browse(cfg, "plc"); var; var = var->next) {
238                 if (!strcasecmp(var->name, "genericplc")) {
239                         g722tolin.useplc = ast_true(var->value) ? 1 : 0;
240                         ast_verb(3, "codec_g722: %susing generic PLC\n",
241                                         g722tolin.useplc ? "" : "not ");
242                 }
243         }
244         ast_config_destroy(cfg);
245         return 0;
246 }
247
248 static int reload(void)
249 {
250         if (parse_config(1))
251                 return AST_MODULE_LOAD_DECLINE;
252         return AST_MODULE_LOAD_SUCCESS;
253 }
254
255 static int unload_module(void)
256 {
257         int res = 0;
258
259         res |= ast_unregister_translator(&g722tolin);
260         res |= ast_unregister_translator(&lintog722);
261         res |= ast_unregister_translator(&g722tolin16);
262         res |= ast_unregister_translator(&lin16tog722);
263
264         return res;
265 }
266
267 static int load_module(void)
268 {
269         int res = 0;
270
271         if (parse_config(0))
272                 return AST_MODULE_LOAD_DECLINE;
273
274         res |= ast_register_translator(&g722tolin);
275         res |= ast_register_translator(&lintog722);
276         res |= ast_register_translator(&g722tolin16);
277         res |= ast_register_translator(&lin16tog722);
278
279         if (res) {
280                 unload_module();
281                 return AST_MODULE_LOAD_FAILURE;
282         }       
283
284         return AST_MODULE_LOAD_SUCCESS;
285 }
286
287 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "ITU G.722-64kbps G722 Transcoder",
288                 .load = load_module,
289                 .unload = unload_module,
290                 .reload = reload,
291                );