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