Add codec G.722 support.
[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  * 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 codec_g722.c - translate between signed linear and ITU G.722-64kbps
22  *
23  * \ingroup codecs
24  */
25
26 #include "asterisk.h"
27
28 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
29
30 #include <fcntl.h>
31 #include <netinet/in.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <unistd.h>
36
37 #include "asterisk/lock.h"
38 #include "asterisk/logger.h"
39 #include "asterisk/linkedlists.h"
40 #include "asterisk/module.h"
41 #include "asterisk/config.h"
42 #include "asterisk/options.h"
43 #include "asterisk/translate.h"
44 #include "asterisk/channel.h"
45 #include "asterisk/utils.h"
46
47 #define BUFFER_SAMPLES   8096   /* size for the translation buffers */
48 #define BUF_SHIFT       5
49
50 /* Sample frame data */
51
52 #include "g722/g722.h"
53 #include "slin_g722_ex.h"
54 #include "g722_slin_ex.h"
55
56 struct g722_encoder_pvt {
57         g722_encode_state_t g722;
58 };
59
60 struct g722_decoder_pvt {
61         g722_decode_state_t g722;
62 };
63
64 /*! \brief init a new instance of g722_encoder_pvt. */
65 static int lintog722_new(struct ast_trans_pvt *pvt)
66 {
67         struct g722_encoder_pvt *tmp = pvt->pvt;
68
69         g722_encode_init(&tmp->g722, 64000, G722_SAMPLE_RATE_8000);
70
71         return 0;
72 }
73
74 /*! \brief init a new instance of g722_encoder_pvt. */
75 static int g722tolin_new(struct ast_trans_pvt *pvt)
76 {
77         struct g722_decoder_pvt *tmp = pvt->pvt;
78
79         g722_decode_init(&tmp->g722, 64000, G722_SAMPLE_RATE_8000);
80
81         return 0;
82 }
83
84 static int g722tolin_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
85 {
86         struct g722_decoder_pvt *tmp = pvt->pvt;
87         unsigned char *src = f->data;
88         int16_t *dst = (int16_t *) pvt->outbuf + pvt->samples;
89
90         g722_decode(&tmp->g722, dst, src, f->samples);
91         pvt->samples += f->samples;
92         pvt->datalen += 2 * f->samples;
93
94         return 0;
95 }
96
97 static int lintog722_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
98 {
99         struct g722_encoder_pvt *tmp = pvt->pvt;
100         int16_t *src = f->data;
101
102         g722_encode(&tmp->g722, &pvt->outbuf[pvt->datalen], src, f->samples);
103         /* Since G.722 64kbps per second is one bye per sample, all of these
104            calculations are easy */
105         pvt->samples += f->samples;
106         pvt->datalen += f->samples;
107
108         return 0;
109 }
110
111 static struct ast_frame *g722tolin_sample(void)
112 {
113         static struct ast_frame f = {
114                 .frametype = AST_FRAME_VOICE,
115                 .subclass = AST_FORMAT_G722,
116                 .datalen = sizeof(g722_slin_ex),
117                 .samples = sizeof(g722_slin_ex),
118                 .src = __PRETTY_FUNCTION__,
119                 .data = g722_slin_ex,
120         };
121
122         return &f;
123 }
124
125 static struct ast_frame *lintog722_sample (void)
126 {
127         static struct ast_frame f = {
128                 .frametype = AST_FRAME_VOICE,
129                 .subclass = AST_FORMAT_SLINEAR,
130                 .datalen = sizeof(slin_g722_ex),
131                 .samples = sizeof(slin_g722_ex),
132                 .src = __PRETTY_FUNCTION__,
133                 .data = slin_g722_ex,
134         };
135
136         return &f;
137 }
138
139 static struct ast_translator g722tolin = {
140         .name = "g722tolin",
141         .srcfmt = AST_FORMAT_G722,
142         .dstfmt = AST_FORMAT_SLINEAR,
143         .newpvt = g722tolin_new,        /* same for both directions */
144         .framein = g722tolin_framein,
145         .sample = g722tolin_sample,
146         .desc_size = sizeof(struct g722_decoder_pvt),
147         .buffer_samples = BUFFER_SAMPLES,
148         .buf_size = BUFFER_SAMPLES,
149         .plc_samples = 160,
150 };
151
152 static struct ast_translator lintog722 = {
153         .name = "lintog722",
154         .srcfmt = AST_FORMAT_SLINEAR,
155         .dstfmt = AST_FORMAT_G722,
156         .newpvt = lintog722_new,        /* same for both directions */
157         .framein = lintog722_framein,
158         .sample = lintog722_sample,
159         .desc_size = sizeof(struct g722_encoder_pvt),
160         .buffer_samples = BUFFER_SAMPLES,
161         .buf_size = BUFFER_SAMPLES,
162 };
163
164 static void parse_config(void)
165 {
166         struct ast_variable *var;
167         struct ast_config *cfg = ast_config_load("codecs.conf");
168
169         if (!cfg)
170                 return;
171         for (var = ast_variable_browse(cfg, "plc"); var; var = var->next) {
172                 if (!strcasecmp(var->name, "genericplc")) {
173                         g722tolin.useplc = ast_true(var->value) ? 1 : 0;
174                         if (option_verbose > 2)
175                                 ast_verbose(VERBOSE_PREFIX_3 "codec_g722: %susing generic PLC\n",
176                                         g722tolin.useplc ? "" : "not ");
177                 }
178         }
179         ast_config_destroy(cfg);
180 }
181
182 static int reload(void)
183 {
184         parse_config();
185
186         return 0;
187 }
188
189 static int unload_module(void)
190 {
191         int res = 0;
192
193         res |= ast_unregister_translator(&g722tolin);
194         res |= ast_unregister_translator(&lintog722);
195
196         return res;
197 }
198
199 static int load_module(void)
200 {
201         int res = 0;
202
203
204         parse_config();
205
206         res |= ast_register_translator(&g722tolin);
207         res |= ast_register_translator(&lintog722);
208
209         if (res)
210                 unload_module();
211
212         return res;
213 }
214
215 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "ITU G.722-64kbps G722 Transcoder",
216                 .load = load_module,
217                 .unload = unload_module,
218                 .reload = reload,
219                );