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 #define TYPE_SILENCE 0x2
22 #include <asterisk/lock.h>
23 #include <asterisk/translate.h>
24 #include <asterisk/module.h>
25 #include <asterisk/logger.h>
26 #include <asterisk/channel.h>
31 #include <netinet/in.h>
35 #include "gsm/inc/gsm.h"
37 /* Sample frame data */
38 #include "slin_gsm_ex.h"
39 #include "gsm_slin_ex.h"
41 static pthread_mutex_t localuser_lock = AST_MUTEX_INITIALIZER;
42 static int localusecnt=0;
44 static char *tdesc = "GSM/PCM16 (signed linear) Codec Translator";
46 struct ast_translator_pvt {
49 /* Space to build offset */
50 char offset[AST_FRIENDLY_OFFSET];
51 /* Buffer for our outgoing frame */
53 /* Enough to store a full second */
58 #define gsm_coder_pvt ast_translator_pvt
60 static struct ast_translator_pvt *gsm_new()
62 struct gsm_coder_pvt *tmp;
63 tmp = malloc(sizeof(struct gsm_coder_pvt));
65 if (!(tmp->gsm = gsm_create())) {
75 static struct ast_frame *lintogsm_sample()
77 static struct ast_frame f;
78 f.frametype = AST_FRAME_VOICE;
79 f.subclass = AST_FORMAT_SLINEAR;
80 f.datalen = sizeof(slin_gsm_ex);
82 f.samples = sizeof(slin_gsm_ex)/2;
85 f.src = __PRETTY_FUNCTION__;
90 static struct ast_frame *gsmtolin_sample()
92 static struct ast_frame f;
93 f.frametype = AST_FRAME_VOICE;
94 f.subclass = AST_FORMAT_GSM;
95 f.datalen = sizeof(gsm_slin_ex);
96 /* All frames are 20 ms long */
100 f.src = __PRETTY_FUNCTION__;
101 f.data = gsm_slin_ex;
105 static struct ast_frame *gsmtolin_frameout(struct ast_translator_pvt *tmp)
109 /* Signed linear is no particular frame size, so just send whatever
110 we have in the buffer in one lump sum */
111 tmp->f.frametype = AST_FRAME_VOICE;
112 tmp->f.subclass = AST_FORMAT_SLINEAR;
113 tmp->f.datalen = tmp->tail * 2;
115 tmp->f.samples = tmp->tail;
117 tmp->f.offset = AST_FRIENDLY_OFFSET;
118 tmp->f.src = __PRETTY_FUNCTION__;
119 tmp->f.data = tmp->buf;
120 /* Reset tail pointer */
126 static int gsmtolin_framein(struct ast_translator_pvt *tmp, struct ast_frame *f)
128 /* Assuming there's space left, decode into the current buffer at
129 the tail location. Read in as many frames as there are */
131 if (f->datalen % 33) {
132 ast_log(LOG_WARNING, "Huh? A GSM frame that isn't a multiple of 33 bytes long from %s (%d)?\n", f->src, f->datalen);
135 for (x=0;x<f->datalen;x+=33) {
136 if (tmp->tail + 160 < sizeof(tmp->buf)/2) {
137 if (gsm_decode(tmp->gsm, f->data + x, tmp->buf + tmp->tail)) {
138 ast_log(LOG_WARNING, "Invalid GSM data\n");
143 ast_log(LOG_WARNING, "Out of buffer space\n");
150 static int lintogsm_framein(struct ast_translator_pvt *tmp, struct ast_frame *f)
152 /* Just add the frames to our stream */
153 /* XXX We should look at how old the rest of our stream is, and if it
154 is too old, then we should overwrite it entirely, otherwise we can
155 get artifacts of earlier talk that do not belong */
156 if (tmp->tail + f->datalen/2 < sizeof(tmp->buf) / 2) {
157 memcpy((tmp->buf + tmp->tail), f->data, f->datalen);
158 tmp->tail += f->datalen/2;
160 ast_log(LOG_WARNING, "Out of buffer space\n");
166 static struct ast_frame *lintogsm_frameout(struct ast_translator_pvt *tmp)
169 /* We can't work on anything less than a frame in size */
172 tmp->f.frametype = AST_FRAME_VOICE;
173 tmp->f.subclass = AST_FORMAT_GSM;
175 tmp->f.offset = AST_FRIENDLY_OFFSET;
176 tmp->f.src = __PRETTY_FUNCTION__;
177 tmp->f.data = tmp->outbuf;
178 while(tmp->tail >= 160) {
179 if ((x+1) * 33 >= sizeof(tmp->outbuf)) {
180 ast_log(LOG_WARNING, "Out of buffer space\n");
183 /* Encode a frame of data */
184 gsm_encode(tmp->gsm, tmp->buf, ((gsm_byte *) tmp->outbuf) + (x * 33));
185 /* Assume 8000 Hz -- 20 ms */
187 /* Move the data at the end of the buffer to the front */
189 memmove(tmp->buf, tmp->buf + 160, tmp->tail * 2);
192 tmp->f.datalen = x * 33;
193 tmp->f.samples = x * 160;
197 static void gsm_destroy_stuff(struct ast_translator_pvt *pvt)
203 static struct ast_translator gsmtolin =
205 AST_FORMAT_GSM, AST_FORMAT_SLINEAR,
213 static struct ast_translator lintogsm =
215 AST_FORMAT_SLINEAR, AST_FORMAT_GSM,
223 int unload_module(void)
226 ast_pthread_mutex_lock(&localuser_lock);
227 res = ast_unregister_translator(&lintogsm);
229 res = ast_unregister_translator(&gsmtolin);
232 ast_pthread_mutex_unlock(&localuser_lock);
236 int load_module(void)
239 res=ast_register_translator(&gsmtolin);
241 res=ast_register_translator(&lintogsm);
243 ast_unregister_translator(&gsmtolin);
247 char *description(void)
255 STANDARD_USECOUNT(res);
261 return ASTERISK_GPL_KEY;