9c3494402fd468ed31ebce91d2a1081f6ffb7c83
[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 /*** MODULEINFO
30         <depend>gsm</depend>
31  ***/
32
33 #include "asterisk.h"
34
35 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
36
37 #include <fcntl.h>
38
39 #include "asterisk/translate.h"
40 #include "asterisk/config.h"
41 #include "asterisk/module.h"
42 #include "asterisk/utils.h"
43
44 #ifdef HAVE_GSM_HEADER
45 #include "gsm.h"
46 #elif defined(HAVE_GSM_GSM_HEADER)
47 #include <gsm/gsm.h>
48 #endif
49
50 #include "../formats/msgsm.h"
51
52 /* Sample frame data */
53 #include "slin_gsm_ex.h"
54 #include "gsm_slin_ex.h"
55
56 #define BUFFER_SAMPLES  8000
57 #define GSM_SAMPLES     160
58 #define GSM_FRAME_LEN   33
59 #define MSGSM_FRAME_LEN 65
60
61 struct gsm_translator_pvt {     /* both gsm2lin and lin2gsm */
62         gsm gsm;
63         int16_t buf[BUFFER_SAMPLES];    /* lin2gsm, temporary storage */
64 };
65
66 static int gsm_new(struct ast_trans_pvt *pvt)
67 {
68         struct gsm_translator_pvt *tmp = pvt->pvt;
69         
70         return (tmp->gsm = gsm_create()) ? 0 : -1;
71 }
72
73 static struct ast_frame *lintogsm_sample(void)
74 {
75         static struct ast_frame f;
76         f.frametype = AST_FRAME_VOICE;
77         f.subclass = AST_FORMAT_SLINEAR;
78         f.datalen = sizeof(slin_gsm_ex);
79         /* Assume 8000 Hz */
80         f.samples = sizeof(slin_gsm_ex)/2;
81         f.mallocd = 0;
82         f.offset = 0;
83         f.src = __PRETTY_FUNCTION__;
84         f.data = slin_gsm_ex;
85         return &f;
86 }
87
88 static struct ast_frame *gsmtolin_sample(void)
89 {
90         static struct ast_frame f;
91         f.frametype = AST_FRAME_VOICE;
92         f.subclass = AST_FORMAT_GSM;
93         f.datalen = sizeof(gsm_slin_ex);
94         /* All frames are 20 ms long */
95         f.samples = GSM_SAMPLES;
96         f.mallocd = 0;
97         f.offset = 0;
98         f.src = __PRETTY_FUNCTION__;
99         f.data = gsm_slin_ex;
100         return &f;
101 }
102
103 /*! \brief decode and store in outbuf. */
104 static int gsmtolin_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
105 {
106         struct gsm_translator_pvt *tmp = pvt->pvt;
107         int x;
108         int16_t *dst = (int16_t *)pvt->outbuf;
109         /* guess format from frame len. 65 for MSGSM, 33 for regular GSM */
110         int flen = (f->datalen % MSGSM_FRAME_LEN == 0) ?
111                 MSGSM_FRAME_LEN : GSM_FRAME_LEN;
112
113         for (x=0; x < f->datalen; x += flen) {
114                 unsigned char data[2 * GSM_FRAME_LEN];
115                 unsigned char *src;
116                 int len;
117                 if (flen == MSGSM_FRAME_LEN) {
118                         len = 2*GSM_SAMPLES;
119                         src = data;
120                         /* Translate MSGSM format to Real GSM format before feeding in */
121                         /* XXX what's the point here! we should just work
122                          * on the full format.
123                          */
124                         conv65(f->data + x, data);
125                 } else {
126                         len = GSM_SAMPLES;
127                         src = f->data + x;
128                 }
129                 /* XXX maybe we don't need to check */
130                 if (pvt->samples + len > BUFFER_SAMPLES) {      
131                         ast_log(LOG_WARNING, "Out of buffer space\n");
132                         return -1;
133                 }
134                 if (gsm_decode(tmp->gsm, src, dst + pvt->samples)) {
135                         ast_log(LOG_WARNING, "Invalid GSM data (1)\n");
136                         return -1;
137                 }
138                 pvt->samples += GSM_SAMPLES;
139                 pvt->datalen += 2 * GSM_SAMPLES;
140                 if (flen == MSGSM_FRAME_LEN) {
141                         if (gsm_decode(tmp->gsm, data + GSM_FRAME_LEN, dst + pvt->samples)) {
142                                 ast_log(LOG_WARNING, "Invalid GSM data (2)\n");
143                                 return -1;
144                         }
145                         pvt->samples += GSM_SAMPLES;
146                         pvt->datalen += 2 * GSM_SAMPLES;
147                 }
148         }
149         return 0;
150 }
151
152 /*! \brief store samples into working buffer for later decode */
153 static int lintogsm_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
154 {
155         struct gsm_translator_pvt *tmp = pvt->pvt;
156
157         /* XXX We should look at how old the rest of our stream is, and if it
158            is too old, then we should overwrite it entirely, otherwise we can
159            get artifacts of earlier talk that do not belong */
160         if (pvt->samples + f->samples > BUFFER_SAMPLES) {
161                 ast_log(LOG_WARNING, "Out of buffer space\n");
162                 return -1;
163         }
164         memcpy(tmp->buf + pvt->samples, f->data, f->datalen);
165         pvt->samples += f->samples;
166         return 0;
167 }
168
169 /*! \brief encode and produce a frame */
170 static struct ast_frame *lintogsm_frameout(struct ast_trans_pvt *pvt)
171 {
172         struct gsm_translator_pvt *tmp = pvt->pvt;
173         int datalen = 0;
174         int samples = 0;
175
176         /* We can't work on anything less than a frame in size */
177         if (pvt->samples < GSM_SAMPLES)
178                 return NULL;
179         while (pvt->samples >= GSM_SAMPLES) {
180                 /* Encode a frame of data */
181                 gsm_encode(tmp->gsm, tmp->buf + samples, (gsm_byte *) pvt->outbuf + datalen);
182                 datalen += GSM_FRAME_LEN;
183                 samples += GSM_SAMPLES;
184                 pvt->samples -= GSM_SAMPLES;
185         }
186
187         /* Move the data at the end of the buffer to the front */
188         if (pvt->samples)
189                 memmove(tmp->buf, tmp->buf + samples, pvt->samples * 2);
190
191         return ast_trans_frameout(pvt, datalen, samples);
192 }
193
194 static void gsm_destroy_stuff(struct ast_trans_pvt *pvt)
195 {
196         struct gsm_translator_pvt *tmp = pvt->pvt;
197         if (tmp->gsm)
198                 gsm_destroy(tmp->gsm);
199 }
200
201 static struct ast_translator gsmtolin = {
202         .name = "gsmtolin", 
203         .srcfmt = AST_FORMAT_GSM,
204         .dstfmt = AST_FORMAT_SLINEAR,
205         .newpvt = gsm_new,
206         .framein = gsmtolin_framein,
207         .destroy = gsm_destroy_stuff,
208         .sample = gsmtolin_sample,
209         .buffer_samples = BUFFER_SAMPLES,
210         .buf_size = BUFFER_SAMPLES * 2,
211         .desc_size = sizeof (struct gsm_translator_pvt ),
212         .plc_samples = GSM_SAMPLES,
213 };
214
215 static struct ast_translator lintogsm = {
216         .name = "lintogsm", 
217         .srcfmt = AST_FORMAT_SLINEAR,
218         .dstfmt = AST_FORMAT_GSM,
219         .newpvt = gsm_new,
220         .framein = lintogsm_framein,
221         .frameout = lintogsm_frameout,
222         .destroy = gsm_destroy_stuff,
223         .sample = lintogsm_sample,
224         .desc_size = sizeof (struct gsm_translator_pvt ),
225         .buf_size = (BUFFER_SAMPLES * GSM_FRAME_LEN + GSM_SAMPLES - 1)/GSM_SAMPLES,
226 };
227
228
229 static int parse_config(int reload)
230 {
231         struct ast_variable *var;
232         struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
233         struct ast_config *cfg = ast_config_load("codecs.conf", config_flags);
234         if (!cfg)
235                 return -1;
236         if (cfg == CONFIG_STATUS_FILEUNCHANGED) 
237                 return 0;
238         for (var = ast_variable_browse(cfg, "plc"); var; var = var->next) {
239                if (!strcasecmp(var->name, "genericplc")) {
240                        gsmtolin.useplc = ast_true(var->value) ? 1 : 0;
241                            ast_verb(3, "codec_gsm: %susing generic PLC\n", gsmtolin.useplc ? "" : "not ");
242                }
243         }
244         ast_config_destroy(cfg);
245         return 0;
246 }
247
248 /*! \brief standard module glue */
249 static int reload(void)
250 {
251         if (parse_config(1)) {
252                 return AST_MODULE_LOAD_DECLINE;
253         }
254         return AST_MODULE_LOAD_SUCCESS;
255 }
256
257 static int unload_module(void)
258 {
259         int res;
260
261         res = ast_unregister_translator(&lintogsm);
262         if (!res)
263                 res = ast_unregister_translator(&gsmtolin);
264
265         return res;
266 }
267
268 static int load_module(void)
269 {
270         int res;
271
272         if (parse_config(0))
273                 return AST_MODULE_LOAD_DECLINE;
274         res = ast_register_translator(&gsmtolin);
275         if (!res) 
276                 res=ast_register_translator(&lintogsm);
277         else
278                 ast_unregister_translator(&gsmtolin);
279         if (res) 
280                 return AST_MODULE_LOAD_FAILURE;
281         return AST_MODULE_LOAD_SUCCESS;
282 }
283
284 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "GSM Coder/Decoder",
285                 .load = load_module,
286                 .unload = unload_module,
287                 .reload = reload,
288                );