As per bug 8859 (Add option to revert old ChanIsAvail() with 's' option behavior...
[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 + samples, (gsm_byte *) pvt->outbuf + datalen);
187                 datalen += GSM_FRAME_LEN;
188                 samples += GSM_SAMPLES;
189                 pvt->samples -= GSM_SAMPLES;
190         }
191
192         /* Move the data at the end of the buffer to the front */
193         if (pvt->samples)
194                 memmove(tmp->buf, tmp->buf + samples, pvt->samples * 2);
195
196         return ast_trans_frameout(pvt, datalen, samples);
197 }
198
199 static void gsm_destroy_stuff(struct ast_trans_pvt *pvt)
200 {
201         struct gsm_translator_pvt *tmp = pvt->pvt;
202         if (tmp->gsm)
203                 gsm_destroy(tmp->gsm);
204 }
205
206 static struct ast_translator gsmtolin = {
207         .name = "gsmtolin", 
208         .srcfmt = AST_FORMAT_GSM,
209         .dstfmt = AST_FORMAT_SLINEAR,
210         .newpvt = gsm_new,
211         .framein = gsmtolin_framein,
212         .destroy = gsm_destroy_stuff,
213         .sample = gsmtolin_sample,
214         .buffer_samples = BUFFER_SAMPLES,
215         .buf_size = BUFFER_SAMPLES * 2,
216         .desc_size = sizeof (struct gsm_translator_pvt ),
217         .plc_samples = GSM_SAMPLES,
218 };
219
220 static struct ast_translator lintogsm = {
221         .name = "lintogsm", 
222         .srcfmt = AST_FORMAT_SLINEAR,
223         .dstfmt = AST_FORMAT_GSM,
224         .newpvt = gsm_new,
225         .framein = lintogsm_framein,
226         .frameout = lintogsm_frameout,
227         .destroy = gsm_destroy_stuff,
228         .sample = lintogsm_sample,
229         .desc_size = sizeof (struct gsm_translator_pvt ),
230         .buf_size = (BUFFER_SAMPLES * GSM_FRAME_LEN + GSM_SAMPLES - 1)/GSM_SAMPLES,
231 };
232
233
234 static void parse_config(void)
235 {
236         struct ast_variable *var;
237         struct ast_config *cfg = ast_config_load("codecs.conf");
238         if (!cfg)
239                 return;
240         for (var = ast_variable_browse(cfg, "plc"); var; var = var->next) {
241                if (!strcasecmp(var->name, "genericplc")) {
242                        gsmtolin.useplc = ast_true(var->value) ? 1 : 0;
243                        if (option_verbose > 2)
244                                ast_verbose(VERBOSE_PREFIX_3 "codec_gsm: %susing generic PLC\n", gsmtolin.useplc ? "" : "not ");
245                }
246         }
247         ast_config_destroy(cfg);
248 }
249
250 /*! \brief standard module glue */
251 static int reload(void)
252 {
253         parse_config();
254         return 0;
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         parse_config();
273         res = ast_register_translator(&gsmtolin);
274         if (!res) 
275                 res=ast_register_translator(&lintogsm);
276         else
277                 ast_unregister_translator(&gsmtolin);
278
279         return res;
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                );