2 * Asterisk -- An open source telephony toolkit.
4 * The GSM code is from TOAST. Copyright information for that package is available
5 * in the GSM directory.
7 * Copyright (C) 1999 - 2005, Digium, Inc.
9 * Mark Spencer <markster@digium.com>
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.
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.
24 * \brief Translate between signed linear and Global System for Mobile Communications (GSM)
32 #include <netinet/in.h>
38 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
40 #include "asterisk/lock.h"
41 #include "asterisk/translate.h"
42 #include "asterisk/config.h"
43 #include "asterisk/options.h"
44 #include "asterisk/module.h"
45 #include "asterisk/logger.h"
46 #include "asterisk/channel.h"
48 #include "gsm/inc/gsm.h"
49 #include "../formats/msgsm.h"
51 /* Sample frame data */
52 #include "slin_gsm_ex.h"
53 #include "gsm_slin_ex.h"
55 AST_MUTEX_DEFINE_STATIC(localuser_lock);
56 static int localusecnt=0;
58 static char *tdesc = "GSM/PCM16 (signed linear) Codec Translator";
60 static int useplc = 0;
62 struct ast_translator_pvt {
65 /* Space to build offset */
66 char offset[AST_FRIENDLY_OFFSET];
67 /* Buffer for our outgoing frame */
69 /* Enough to store a full second */
75 #define gsm_coder_pvt ast_translator_pvt
77 static struct ast_translator_pvt *gsm_new(void)
79 struct gsm_coder_pvt *tmp;
80 tmp = malloc(sizeof(struct gsm_coder_pvt));
82 if (!(tmp->gsm = gsm_create())) {
93 static struct ast_frame *lintogsm_sample(void)
95 static struct ast_frame f;
96 f.frametype = AST_FRAME_VOICE;
97 f.subclass = AST_FORMAT_SLINEAR;
98 f.datalen = sizeof(slin_gsm_ex);
100 f.samples = sizeof(slin_gsm_ex)/2;
103 f.src = __PRETTY_FUNCTION__;
104 f.data = slin_gsm_ex;
108 static struct ast_frame *gsmtolin_sample(void)
110 static struct ast_frame f;
111 f.frametype = AST_FRAME_VOICE;
112 f.subclass = AST_FORMAT_GSM;
113 f.datalen = sizeof(gsm_slin_ex);
114 /* All frames are 20 ms long */
118 f.src = __PRETTY_FUNCTION__;
119 f.data = gsm_slin_ex;
123 static struct ast_frame *gsmtolin_frameout(struct ast_translator_pvt *tmp)
127 /* Signed linear is no particular frame size, so just send whatever
128 we have in the buffer in one lump sum */
129 tmp->f.frametype = AST_FRAME_VOICE;
130 tmp->f.subclass = AST_FORMAT_SLINEAR;
131 tmp->f.datalen = tmp->tail * 2;
133 tmp->f.samples = tmp->tail;
135 tmp->f.offset = AST_FRIENDLY_OFFSET;
136 tmp->f.src = __PRETTY_FUNCTION__;
137 tmp->f.data = tmp->buf;
138 /* Reset tail pointer */
144 static int gsmtolin_framein(struct ast_translator_pvt *tmp, struct ast_frame *f)
146 /* Assuming there's space left, decode into the current buffer at
147 the tail location. Read in as many frames as there are */
149 unsigned char data[66];
152 if(f->datalen == 0) { /* perform PLC with nominal framesize of 20ms/160 samples */
153 if((tmp->tail + 160) > sizeof(tmp->buf) / 2) {
154 ast_log(LOG_WARNING, "Out of buffer space\n");
158 plc_fillin(&tmp->plc, tmp->buf+tmp->tail, 160);
164 if ((f->datalen % 33) && (f->datalen % 65)) {
165 ast_log(LOG_WARNING, "Huh? A GSM frame that isn't a multiple of 33 or 65 bytes long from %s (%d)?\n", f->src, f->datalen);
169 if (f->datalen % 65 == 0)
172 for (x=0;x<f->datalen;x+=(msgsm ? 65 : 33)) {
174 /* Translate MSGSM format to Real GSM format before feeding in */
175 conv65(f->data + x, data);
176 if (tmp->tail + 320 < sizeof(tmp->buf)/2) {
177 if (gsm_decode(tmp->gsm, data, tmp->buf + tmp->tail)) {
178 ast_log(LOG_WARNING, "Invalid GSM data (1)\n");
182 if (gsm_decode(tmp->gsm, data + 33, tmp->buf + tmp->tail)) {
183 ast_log(LOG_WARNING, "Invalid GSM data (2)\n");
188 ast_log(LOG_WARNING, "Out of (MS) buffer space\n");
192 if (tmp->tail + 160 < sizeof(tmp->buf)/2) {
193 if (gsm_decode(tmp->gsm, f->data + x, tmp->buf + tmp->tail)) {
194 ast_log(LOG_WARNING, "Invalid GSM data\n");
199 ast_log(LOG_WARNING, "Out of buffer space\n");
205 /* just add the last 20ms frame; there must have been at least one */
206 if(useplc) plc_rx(&tmp->plc, tmp->buf+tmp->tail-160, 160);
211 static int lintogsm_framein(struct ast_translator_pvt *tmp, struct ast_frame *f)
213 /* Just add the frames to our stream */
214 /* XXX We should look at how old the rest of our stream is, and if it
215 is too old, then we should overwrite it entirely, otherwise we can
216 get artifacts of earlier talk that do not belong */
217 if (tmp->tail + f->datalen/2 < sizeof(tmp->buf) / 2) {
218 memcpy((tmp->buf + tmp->tail), f->data, f->datalen);
219 tmp->tail += f->datalen/2;
221 ast_log(LOG_WARNING, "Out of buffer space\n");
227 static struct ast_frame *lintogsm_frameout(struct ast_translator_pvt *tmp)
230 /* We can't work on anything less than a frame in size */
233 tmp->f.frametype = AST_FRAME_VOICE;
234 tmp->f.subclass = AST_FORMAT_GSM;
236 tmp->f.offset = AST_FRIENDLY_OFFSET;
237 tmp->f.src = __PRETTY_FUNCTION__;
238 tmp->f.data = tmp->outbuf;
239 while(tmp->tail >= 160) {
240 if ((x+1) * 33 >= sizeof(tmp->outbuf)) {
241 ast_log(LOG_WARNING, "Out of buffer space\n");
244 /* Encode a frame of data */
245 gsm_encode(tmp->gsm, tmp->buf, ((gsm_byte *) tmp->outbuf) + (x * 33));
246 /* Assume 8000 Hz -- 20 ms */
248 /* Move the data at the end of the buffer to the front */
250 memmove(tmp->buf, tmp->buf + 160, tmp->tail * 2);
253 tmp->f.datalen = x * 33;
254 tmp->f.samples = x * 160;
258 static void gsm_destroy_stuff(struct ast_translator_pvt *pvt)
261 gsm_destroy(pvt->gsm);
266 static struct ast_translator gsmtolin =
268 AST_FORMAT_GSM, AST_FORMAT_SLINEAR,
276 static struct ast_translator lintogsm =
278 AST_FORMAT_SLINEAR, AST_FORMAT_GSM,
287 static void parse_config(void)
289 struct ast_config *cfg;
290 struct ast_variable *var;
291 if ((cfg = ast_config_load("codecs.conf"))) {
292 if ((var = ast_variable_browse(cfg, "plc"))) {
294 if (!strcasecmp(var->name, "genericplc")) {
295 useplc = ast_true(var->value) ? 1 : 0;
296 if (option_verbose > 2)
297 ast_verbose(VERBOSE_PREFIX_3 "codec_gsm: %susing generic PLC\n", useplc ? "" : "not ");
302 ast_config_destroy(cfg);
312 int unload_module(void)
315 ast_mutex_lock(&localuser_lock);
316 res = ast_unregister_translator(&lintogsm);
318 res = ast_unregister_translator(&gsmtolin);
321 ast_mutex_unlock(&localuser_lock);
325 int load_module(void)
329 res=ast_register_translator(&gsmtolin);
331 res=ast_register_translator(&lintogsm);
333 ast_unregister_translator(&gsmtolin);
337 char *description(void)
345 STANDARD_USECOUNT(res);
351 return ASTERISK_GPL_KEY;