2 * Asterisk -- A telephony toolkit for Linux.
4 * Translate between signed linear and Global System for Mobile Communications (GSM)
6 * The GSM code is from TOAST. Copyright information for that package is available
7 * in the GSM directory.
9 * Copyright (C) 1999, Mark Spencer
11 * Mark Spencer <markster@linux-support.net>
13 * This program is free software, distributed under the terms of
14 * the GNU General Public License
17 #include <asterisk/lock.h>
18 #include <asterisk/translate.h>
19 #include <asterisk/config.h>
20 #include <asterisk/options.h>
21 #include <asterisk/module.h>
22 #include <asterisk/logger.h>
23 #include <asterisk/channel.h>
27 #include <netinet/in.h>
31 #include "gsm/inc/gsm.h"
32 #include "../formats/msgsm.h"
34 /* Sample frame data */
35 #include "slin_gsm_ex.h"
36 #include "gsm_slin_ex.h"
38 AST_MUTEX_DEFINE_STATIC(localuser_lock);
39 static int localusecnt=0;
41 static char *tdesc = "GSM/PCM16 (signed linear) Codec Translator";
43 static int useplc = 0;
45 struct ast_translator_pvt {
48 /* Space to build offset */
49 char offset[AST_FRIENDLY_OFFSET];
50 /* Buffer for our outgoing frame */
52 /* Enough to store a full second */
58 #define gsm_coder_pvt ast_translator_pvt
60 static struct ast_translator_pvt *gsm_new(void)
62 struct gsm_coder_pvt *tmp;
63 tmp = malloc(sizeof(struct gsm_coder_pvt));
65 if (!(tmp->gsm = gsm_create())) {
76 static struct ast_frame *lintogsm_sample(void)
78 static struct ast_frame f;
79 f.frametype = AST_FRAME_VOICE;
80 f.subclass = AST_FORMAT_SLINEAR;
81 f.datalen = sizeof(slin_gsm_ex);
83 f.samples = sizeof(slin_gsm_ex)/2;
86 f.src = __PRETTY_FUNCTION__;
91 static struct ast_frame *gsmtolin_sample(void)
93 static struct ast_frame f;
94 f.frametype = AST_FRAME_VOICE;
95 f.subclass = AST_FORMAT_GSM;
96 f.datalen = sizeof(gsm_slin_ex);
97 /* All frames are 20 ms long */
101 f.src = __PRETTY_FUNCTION__;
102 f.data = gsm_slin_ex;
106 static struct ast_frame *gsmtolin_frameout(struct ast_translator_pvt *tmp)
110 /* Signed linear is no particular frame size, so just send whatever
111 we have in the buffer in one lump sum */
112 tmp->f.frametype = AST_FRAME_VOICE;
113 tmp->f.subclass = AST_FORMAT_SLINEAR;
114 tmp->f.datalen = tmp->tail * 2;
116 tmp->f.samples = tmp->tail;
118 tmp->f.offset = AST_FRIENDLY_OFFSET;
119 tmp->f.src = __PRETTY_FUNCTION__;
120 tmp->f.data = tmp->buf;
121 /* Reset tail pointer */
127 static int gsmtolin_framein(struct ast_translator_pvt *tmp, struct ast_frame *f)
129 /* Assuming there's space left, decode into the current buffer at
130 the tail location. Read in as many frames as there are */
132 unsigned char data[66];
135 if(f->datalen == 0) { /* perform PLC with nominal framesize of 20ms/160 samples */
136 if((tmp->tail + 160) > sizeof(tmp->buf) / 2) {
137 ast_log(LOG_WARNING, "Out of buffer space\n");
141 plc_fillin(&tmp->plc, tmp->buf+tmp->tail, 160);
147 if ((f->datalen % 33) && (f->datalen % 65)) {
148 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);
152 if (f->datalen % 65 == 0)
155 for (x=0;x<f->datalen;x+=(msgsm ? 65 : 33)) {
157 /* Translate MSGSM format to Real GSM format before feeding in */
158 conv65(f->data + x, data);
159 if (tmp->tail + 320 < sizeof(tmp->buf)/2) {
160 if (gsm_decode(tmp->gsm, data, tmp->buf + tmp->tail)) {
161 ast_log(LOG_WARNING, "Invalid GSM data (1)\n");
165 if (gsm_decode(tmp->gsm, data + 33, tmp->buf + tmp->tail)) {
166 ast_log(LOG_WARNING, "Invalid GSM data (2)\n");
171 ast_log(LOG_WARNING, "Out of (MS) buffer space\n");
175 if (tmp->tail + 160 < sizeof(tmp->buf)/2) {
176 if (gsm_decode(tmp->gsm, f->data + x, tmp->buf + tmp->tail)) {
177 ast_log(LOG_WARNING, "Invalid GSM data\n");
182 ast_log(LOG_WARNING, "Out of buffer space\n");
188 /* just add the last 20ms frame; there must have been at least one */
189 if(useplc) plc_rx(&tmp->plc, tmp->buf+tmp->tail-160, 160);
194 static int lintogsm_framein(struct ast_translator_pvt *tmp, struct ast_frame *f)
196 /* Just add the frames to our stream */
197 /* XXX We should look at how old the rest of our stream is, and if it
198 is too old, then we should overwrite it entirely, otherwise we can
199 get artifacts of earlier talk that do not belong */
200 if (tmp->tail + f->datalen/2 < sizeof(tmp->buf) / 2) {
201 memcpy((tmp->buf + tmp->tail), f->data, f->datalen);
202 tmp->tail += f->datalen/2;
204 ast_log(LOG_WARNING, "Out of buffer space\n");
210 static struct ast_frame *lintogsm_frameout(struct ast_translator_pvt *tmp)
213 /* We can't work on anything less than a frame in size */
216 tmp->f.frametype = AST_FRAME_VOICE;
217 tmp->f.subclass = AST_FORMAT_GSM;
219 tmp->f.offset = AST_FRIENDLY_OFFSET;
220 tmp->f.src = __PRETTY_FUNCTION__;
221 tmp->f.data = tmp->outbuf;
222 while(tmp->tail >= 160) {
223 if ((x+1) * 33 >= sizeof(tmp->outbuf)) {
224 ast_log(LOG_WARNING, "Out of buffer space\n");
227 /* Encode a frame of data */
228 gsm_encode(tmp->gsm, tmp->buf, ((gsm_byte *) tmp->outbuf) + (x * 33));
229 /* Assume 8000 Hz -- 20 ms */
231 /* Move the data at the end of the buffer to the front */
233 memmove(tmp->buf, tmp->buf + 160, tmp->tail * 2);
236 tmp->f.datalen = x * 33;
237 tmp->f.samples = x * 160;
241 static void gsm_destroy_stuff(struct ast_translator_pvt *pvt)
244 gsm_destroy(pvt->gsm);
249 static struct ast_translator gsmtolin =
251 AST_FORMAT_GSM, AST_FORMAT_SLINEAR,
259 static struct ast_translator lintogsm =
261 AST_FORMAT_SLINEAR, AST_FORMAT_GSM,
270 static void parse_config(void)
272 struct ast_config *cfg;
273 struct ast_variable *var;
274 if ((cfg = ast_config_load("codecs.conf"))) {
275 if ((var = ast_variable_browse(cfg, "plc"))) {
277 if (!strcasecmp(var->name, "genericplc")) {
278 useplc = ast_true(var->value) ? 1 : 0;
279 if (option_verbose > 2)
280 ast_verbose(VERBOSE_PREFIX_3 "codec_gsm: %susing generic PLC\n", useplc ? "" : "not ");
294 int unload_module(void)
297 ast_mutex_lock(&localuser_lock);
298 res = ast_unregister_translator(&lintogsm);
300 res = ast_unregister_translator(&gsmtolin);
303 ast_mutex_unlock(&localuser_lock);
307 int load_module(void)
311 res=ast_register_translator(&gsmtolin);
313 res=ast_register_translator(&lintogsm);
315 ast_unregister_translator(&gsmtolin);
319 char *description(void)
327 STANDARD_USECOUNT(res);
333 return ASTERISK_GPL_KEY;