ee28e852d0b26d6e9b3605dda1b9be41ed3c4e11
[asterisk/asterisk.git] / codecs / codec_gsm.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * The GSM code is from TOAST.  Copyright information for that package is available
5  * in the GSM directory.
6  *
7  * Copyright (C) 1999 - 2005, Digium, Inc.
8  *
9  * Mark Spencer <markster@digium.com>
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 Translate between signed linear and Global System for Mobile Communications (GSM)
25  *
26  * \ingroup codecs
27  */
28
29 #include <fcntl.h>
30 #include <stdlib.h>
31 #include <unistd.h>
32 #include <netinet/in.h>
33 #include <string.h>
34 #include <stdio.h>
35
36 #include "asterisk.h"
37
38 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
39
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"
47 #include "asterisk/utils.h"
48
49 #ifdef USE_EXTERNAL_GSM_LIB
50 #include <gsm/gsm.h>
51 #else
52 #include "gsm/inc/gsm.h"
53 #endif
54
55 #include "../formats/msgsm.h"
56
57 /* Sample frame data */
58 #include "slin_gsm_ex.h"
59 #include "gsm_slin_ex.h"
60
61 AST_MUTEX_DEFINE_STATIC(localuser_lock);
62 static int localusecnt=0;
63
64 static char *tdesc = "GSM/PCM16 (signed linear) Codec Translator";
65
66 static int useplc = 0;
67
68 struct ast_translator_pvt {
69         gsm gsm;
70         struct ast_frame f;
71         /* Space to build offset */
72         char offset[AST_FRIENDLY_OFFSET];
73         /* Buffer for our outgoing frame */
74         short outbuf[8000];
75         /* Enough to store a full second */
76         short buf[8000];
77         int tail;
78         plc_state_t plc;
79 };
80
81 #define gsm_coder_pvt ast_translator_pvt
82
83 static struct ast_translator_pvt *gsm_new(void)
84 {
85         struct gsm_coder_pvt *tmp;      
86         if ((tmp = ast_malloc(sizeof(*tmp)))) {
87                 if (!(tmp->gsm = gsm_create())) {
88                         free(tmp);
89                         tmp = NULL;
90                 }
91                 tmp->tail = 0;
92                 plc_init(&tmp->plc);
93                 localusecnt++;
94         }
95         return tmp;
96 }
97
98 static struct ast_frame *lintogsm_sample(void)
99 {
100         static struct ast_frame f;
101         f.frametype = AST_FRAME_VOICE;
102         f.subclass = AST_FORMAT_SLINEAR;
103         f.datalen = sizeof(slin_gsm_ex);
104         /* Assume 8000 Hz */
105         f.samples = sizeof(slin_gsm_ex)/2;
106         f.mallocd = 0;
107         f.offset = 0;
108         f.src = __PRETTY_FUNCTION__;
109         f.data = slin_gsm_ex;
110         return &f;
111 }
112
113 static struct ast_frame *gsmtolin_sample(void)
114 {
115         static struct ast_frame f;
116         f.frametype = AST_FRAME_VOICE;
117         f.subclass = AST_FORMAT_GSM;
118         f.datalen = sizeof(gsm_slin_ex);
119         /* All frames are 20 ms long */
120         f.samples = 160;
121         f.mallocd = 0;
122         f.offset = 0;
123         f.src = __PRETTY_FUNCTION__;
124         f.data = gsm_slin_ex;
125         return &f;
126 }
127
128 static struct ast_frame *gsmtolin_frameout(struct ast_translator_pvt *tmp)
129 {
130         if (!tmp->tail)
131                 return NULL;
132         /* Signed linear is no particular frame size, so just send whatever
133            we have in the buffer in one lump sum */
134         tmp->f.frametype = AST_FRAME_VOICE;
135         tmp->f.subclass = AST_FORMAT_SLINEAR;
136         tmp->f.datalen = tmp->tail * 2;
137         /* Assume 8000 Hz */
138         tmp->f.samples = tmp->tail;
139         tmp->f.mallocd = 0;
140         tmp->f.offset = AST_FRIENDLY_OFFSET;
141         tmp->f.src = __PRETTY_FUNCTION__;
142         tmp->f.data = tmp->buf;
143         /* Reset tail pointer */
144         tmp->tail = 0;
145
146         return &tmp->f; 
147 }
148
149 static int gsmtolin_framein(struct ast_translator_pvt *tmp, struct ast_frame *f)
150 {
151         /* Assuming there's space left, decode into the current buffer at
152            the tail location.  Read in as many frames as there are */
153         int x;
154         unsigned char data[66];
155         int msgsm=0;
156         
157         if(f->datalen == 0) { /* perform PLC with nominal framesize of 20ms/160 samples */
158               if((tmp->tail + 160) > sizeof(tmp->buf) / 2) {
159                   ast_log(LOG_WARNING, "Out of buffer space\n");
160                   return -1;
161               }
162               if(useplc) {
163                   plc_fillin(&tmp->plc, tmp->buf+tmp->tail, 160);
164                   tmp->tail += 160;
165               }
166               return 0;
167         }
168
169         if ((f->datalen % 33) && (f->datalen % 65)) {
170                 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);
171                 return -1;
172         }
173         
174         if (f->datalen % 65 == 0) 
175                 msgsm = 1;
176                 
177         for (x=0;x<f->datalen;x+=(msgsm ? 65 : 33)) {
178                 if (msgsm) {
179                         /* Translate MSGSM format to Real GSM format before feeding in */
180                         conv65(f->data + x, data);
181                         if (tmp->tail + 320 < sizeof(tmp->buf)/2) {     
182                                 if (gsm_decode(tmp->gsm, data, tmp->buf + tmp->tail)) {
183                                         ast_log(LOG_WARNING, "Invalid GSM data (1)\n");
184                                         return -1;
185                                 }
186                                 tmp->tail+=160;
187                                 if (gsm_decode(tmp->gsm, data + 33, tmp->buf + tmp->tail)) {
188                                         ast_log(LOG_WARNING, "Invalid GSM data (2)\n");
189                                         return -1;
190                                 }
191                                 tmp->tail+=160;
192                         } else {
193                                 ast_log(LOG_WARNING, "Out of (MS) buffer space\n");
194                                 return -1;
195                         }
196                 } else {
197                         if (tmp->tail + 160 < sizeof(tmp->buf)/2) {     
198                                 if (gsm_decode(tmp->gsm, f->data + x, tmp->buf + tmp->tail)) {
199                                         ast_log(LOG_WARNING, "Invalid GSM data\n");
200                                         return -1;
201                                 }
202                                 tmp->tail+=160;
203                         } else {
204                                 ast_log(LOG_WARNING, "Out of buffer space\n");
205                                 return -1;
206                         }
207                 }
208         }
209
210         /* just add the last 20ms frame; there must have been at least one */
211         if(useplc) plc_rx(&tmp->plc, tmp->buf+tmp->tail-160, 160);
212
213         return 0;
214 }
215
216 static int lintogsm_framein(struct ast_translator_pvt *tmp, struct ast_frame *f)
217 {
218         /* Just add the frames to our stream */
219         /* XXX We should look at how old the rest of our stream is, and if it
220            is too old, then we should overwrite it entirely, otherwise we can
221            get artifacts of earlier talk that do not belong */
222         if (tmp->tail + f->datalen/2 < sizeof(tmp->buf) / 2) {
223                 memcpy((tmp->buf + tmp->tail), f->data, f->datalen);
224                 tmp->tail += f->datalen/2;
225         } else {
226                 ast_log(LOG_WARNING, "Out of buffer space\n");
227                 return -1;
228         }
229         return 0;
230 }
231
232 static struct ast_frame *lintogsm_frameout(struct ast_translator_pvt *tmp)
233 {
234         int x=0;
235         /* We can't work on anything less than a frame in size */
236         if (tmp->tail < 160)
237                 return NULL;
238         tmp->f.frametype = AST_FRAME_VOICE;
239         tmp->f.subclass = AST_FORMAT_GSM;
240         tmp->f.mallocd = 0;
241         tmp->f.offset = AST_FRIENDLY_OFFSET;
242         tmp->f.src = __PRETTY_FUNCTION__;
243         tmp->f.data = tmp->outbuf;
244         while(tmp->tail >= 160) {
245                 if ((x+1) * 33 >= sizeof(tmp->outbuf)) {
246                         ast_log(LOG_WARNING, "Out of buffer space\n");
247                         break;
248                 }
249                 /* Encode a frame of data */
250                 gsm_encode(tmp->gsm, tmp->buf, ((gsm_byte *) tmp->outbuf) + (x * 33));
251                 /* Assume 8000 Hz -- 20 ms */
252                 tmp->tail -= 160;
253                 /* Move the data at the end of the buffer to the front */
254                 if (tmp->tail)
255                         memmove(tmp->buf, tmp->buf + 160, tmp->tail * 2);
256                 x++;
257         }
258         tmp->f.datalen = x * 33;
259         tmp->f.samples = x * 160;
260         return &tmp->f; 
261 }
262
263 static void gsm_destroy_stuff(struct ast_translator_pvt *pvt)
264 {
265         if (pvt->gsm)
266                 gsm_destroy(pvt->gsm);
267         free(pvt);
268         localusecnt--;
269 }
270
271 static struct ast_translator gsmtolin =
272         { "gsmtolin", 
273            AST_FORMAT_GSM, AST_FORMAT_SLINEAR,
274            gsm_new,
275            gsmtolin_framein,
276            gsmtolin_frameout,
277            gsm_destroy_stuff,
278            gsmtolin_sample
279            };
280
281 static struct ast_translator lintogsm =
282         { "lintogsm", 
283            AST_FORMAT_SLINEAR, AST_FORMAT_GSM,
284            gsm_new,
285            lintogsm_framein,
286            lintogsm_frameout,
287            gsm_destroy_stuff,
288            lintogsm_sample
289            };
290
291
292 static void parse_config(void)
293 {
294         struct ast_config *cfg;
295         struct ast_variable *var;
296         if ((cfg = ast_config_load("codecs.conf"))) {
297                 if ((var = ast_variable_browse(cfg, "plc"))) {
298                         while (var) {
299                                if (!strcasecmp(var->name, "genericplc")) {
300                                        useplc = ast_true(var->value) ? 1 : 0;
301                                        if (option_verbose > 2)
302                                                ast_verbose(VERBOSE_PREFIX_3 "codec_gsm: %susing generic PLC\n", useplc ? "" : "not ");
303                                }
304                                var = var->next;
305                         }
306                 }
307                 ast_config_destroy(cfg);
308         }
309 }
310
311 int reload(void)
312 {
313         parse_config();
314         return 0;
315 }
316
317 int unload_module(void)
318 {
319         int res;
320         ast_mutex_lock(&localuser_lock);
321         res = ast_unregister_translator(&lintogsm);
322         if (!res)
323                 res = ast_unregister_translator(&gsmtolin);
324         if (localusecnt)
325                 res = -1;
326         ast_mutex_unlock(&localuser_lock);
327         return res;
328 }
329
330 int load_module(void)
331 {
332         int res;
333         parse_config();
334         res=ast_register_translator(&gsmtolin);
335         if (!res) 
336                 res=ast_register_translator(&lintogsm);
337         else
338                 ast_unregister_translator(&gsmtolin);
339         return res;
340 }
341
342 char *description(void)
343 {
344         return tdesc;
345 }
346
347 int usecount(void)
348 {
349         int res;
350         STANDARD_USECOUNT(res);
351         return res;
352 }
353
354 char *key()
355 {
356         return ASTERISK_GPL_KEY;
357 }