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