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