Remove pthread.h from source. We should be using asterisk/lock.h everywhere instead...
[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/module.h>
25 #include <asterisk/logger.h>
26 #include <asterisk/channel.h>
27 #include <fcntl.h>
28 #include <stdlib.h>
29 #include <unistd.h>
30 #include <netinet/in.h>
31 #include <string.h>
32 #include <stdio.h>
33
34 #include "gsm/inc/gsm.h"
35 #include "../formats/msgsm.h"
36
37 /* Sample frame data */
38 #include "slin_gsm_ex.h"
39 #include "gsm_slin_ex.h"
40
41 AST_MUTEX_DEFINE_STATIC(localuser_lock);
42 static int localusecnt=0;
43
44 static char *tdesc = "GSM/PCM16 (signed linear) Codec Translator";
45
46 struct ast_translator_pvt {
47         gsm gsm;
48         struct ast_frame f;
49         /* Space to build offset */
50         char offset[AST_FRIENDLY_OFFSET];
51         /* Buffer for our outgoing frame */
52         short outbuf[8000];
53         /* Enough to store a full second */
54         short buf[8000];
55         int tail;
56 };
57
58 #define gsm_coder_pvt ast_translator_pvt
59
60 static struct ast_translator_pvt *gsm_new(void)
61 {
62         struct gsm_coder_pvt *tmp;
63         tmp = malloc(sizeof(struct gsm_coder_pvt));
64         if (tmp) {
65                 if (!(tmp->gsm = gsm_create())) {
66                         free(tmp);
67                         tmp = NULL;
68                 }
69                 tmp->tail = 0;
70                 localusecnt++;
71         }
72         return tmp;
73 }
74
75 static struct ast_frame *lintogsm_sample(void)
76 {
77         static struct ast_frame f;
78         f.frametype = AST_FRAME_VOICE;
79         f.subclass = AST_FORMAT_SLINEAR;
80         f.datalen = sizeof(slin_gsm_ex);
81         /* Assume 8000 Hz */
82         f.samples = sizeof(slin_gsm_ex)/2;
83         f.mallocd = 0;
84         f.offset = 0;
85         f.src = __PRETTY_FUNCTION__;
86         f.data = slin_gsm_ex;
87         return &f;
88 }
89
90 static struct ast_frame *gsmtolin_sample(void)
91 {
92         static struct ast_frame f;
93         f.frametype = AST_FRAME_VOICE;
94         f.subclass = AST_FORMAT_GSM;
95         f.datalen = sizeof(gsm_slin_ex);
96         /* All frames are 20 ms long */
97         f.samples = 160;
98         f.mallocd = 0;
99         f.offset = 0;
100         f.src = __PRETTY_FUNCTION__;
101         f.data = gsm_slin_ex;
102         return &f;
103 }
104
105 static struct ast_frame *gsmtolin_frameout(struct ast_translator_pvt *tmp)
106 {
107         if (!tmp->tail)
108                 return NULL;
109         /* Signed linear is no particular frame size, so just send whatever
110            we have in the buffer in one lump sum */
111         tmp->f.frametype = AST_FRAME_VOICE;
112         tmp->f.subclass = AST_FORMAT_SLINEAR;
113         tmp->f.datalen = tmp->tail * 2;
114         /* Assume 8000 Hz */
115         tmp->f.samples = tmp->tail;
116         tmp->f.mallocd = 0;
117         tmp->f.offset = AST_FRIENDLY_OFFSET;
118         tmp->f.src = __PRETTY_FUNCTION__;
119         tmp->f.data = tmp->buf;
120         /* Reset tail pointer */
121         tmp->tail = 0;
122
123         return &tmp->f; 
124 }
125
126 static int gsmtolin_framein(struct ast_translator_pvt *tmp, struct ast_frame *f)
127 {
128         /* Assuming there's space left, decode into the current buffer at
129            the tail location.  Read in as many frames as there are */
130         int x;
131         unsigned char data[66];
132         int msgsm=0;
133         
134         if ((f->datalen % 33) && (f->datalen % 65)) {
135                 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);
136                 return -1;
137         }
138         
139         if (f->datalen % 65 == 0) 
140                 msgsm = 1;
141                 
142         for (x=0;x<f->datalen;x+=(msgsm ? 65 : 33)) {
143                 if (msgsm) {
144                         /* Translate MSGSM format to Real GSM format before feeding in */
145                         conv65(f->data + x, data);
146                         if (tmp->tail + 320 < sizeof(tmp->buf)/2) {     
147                                 if (gsm_decode(tmp->gsm, data, tmp->buf + tmp->tail)) {
148                                         ast_log(LOG_WARNING, "Invalid GSM data (1)\n");
149                                         return -1;
150                                 }
151                                 tmp->tail+=160;
152                                 if (gsm_decode(tmp->gsm, data + 33, tmp->buf + tmp->tail)) {
153                                         ast_log(LOG_WARNING, "Invalid GSM data (2)\n");
154                                         return -1;
155                                 }
156                                 tmp->tail+=160;
157                         } else {
158                                 ast_log(LOG_WARNING, "Out of (MS) buffer space\n");
159                                 return -1;
160                         }
161                 } else {
162                         if (tmp->tail + 160 < sizeof(tmp->buf)/2) {     
163                                 if (gsm_decode(tmp->gsm, f->data + x, tmp->buf + tmp->tail)) {
164                                         ast_log(LOG_WARNING, "Invalid GSM data\n");
165                                         return -1;
166                                 }
167                                 tmp->tail+=160;
168                         } else {
169                                 ast_log(LOG_WARNING, "Out of buffer space\n");
170                                 return -1;
171                         }
172                 }
173         }
174         return 0;
175 }
176
177 static int lintogsm_framein(struct ast_translator_pvt *tmp, struct ast_frame *f)
178 {
179         /* Just add the frames to our stream */
180         /* XXX We should look at how old the rest of our stream is, and if it
181            is too old, then we should overwrite it entirely, otherwise we can
182            get artifacts of earlier talk that do not belong */
183         if (tmp->tail + f->datalen/2 < sizeof(tmp->buf) / 2) {
184                 memcpy((tmp->buf + tmp->tail), f->data, f->datalen);
185                 tmp->tail += f->datalen/2;
186         } else {
187                 ast_log(LOG_WARNING, "Out of buffer space\n");
188                 return -1;
189         }
190         return 0;
191 }
192
193 static struct ast_frame *lintogsm_frameout(struct ast_translator_pvt *tmp)
194 {
195         int x=0;
196         /* We can't work on anything less than a frame in size */
197         if (tmp->tail < 160)
198                 return NULL;
199         tmp->f.frametype = AST_FRAME_VOICE;
200         tmp->f.subclass = AST_FORMAT_GSM;
201         tmp->f.mallocd = 0;
202         tmp->f.offset = AST_FRIENDLY_OFFSET;
203         tmp->f.src = __PRETTY_FUNCTION__;
204         tmp->f.data = tmp->outbuf;
205         while(tmp->tail >= 160) {
206                 if ((x+1) * 33 >= sizeof(tmp->outbuf)) {
207                         ast_log(LOG_WARNING, "Out of buffer space\n");
208                         break;
209                 }
210                 /* Encode a frame of data */
211                 gsm_encode(tmp->gsm, tmp->buf, ((gsm_byte *) tmp->outbuf) + (x * 33));
212                 /* Assume 8000 Hz -- 20 ms */
213                 tmp->tail -= 160;
214                 /* Move the data at the end of the buffer to the front */
215                 if (tmp->tail)
216                         memmove(tmp->buf, tmp->buf + 160, tmp->tail * 2);
217                 x++;
218         }
219         tmp->f.datalen = x * 33;
220         tmp->f.samples = x * 160;
221         return &tmp->f; 
222 }
223
224 static void gsm_destroy_stuff(struct ast_translator_pvt *pvt)
225 {
226         if (pvt->gsm)
227                 gsm_destroy(pvt->gsm);
228         free(pvt);
229         localusecnt--;
230 }
231
232 static struct ast_translator gsmtolin =
233         { "gsmtolin", 
234            AST_FORMAT_GSM, AST_FORMAT_SLINEAR,
235            gsm_new,
236            gsmtolin_framein,
237            gsmtolin_frameout,
238            gsm_destroy_stuff,
239            gsmtolin_sample
240            };
241
242 static struct ast_translator lintogsm =
243         { "lintogsm", 
244            AST_FORMAT_SLINEAR, AST_FORMAT_GSM,
245            gsm_new,
246            lintogsm_framein,
247            lintogsm_frameout,
248            gsm_destroy_stuff,
249            lintogsm_sample
250            };
251
252 int unload_module(void)
253 {
254         int res;
255         ast_mutex_lock(&localuser_lock);
256         res = ast_unregister_translator(&lintogsm);
257         if (!res)
258                 res = ast_unregister_translator(&gsmtolin);
259         if (localusecnt)
260                 res = -1;
261         ast_mutex_unlock(&localuser_lock);
262         return res;
263 }
264
265 int load_module(void)
266 {
267         int res;
268         res=ast_register_translator(&gsmtolin);
269         if (!res) 
270                 res=ast_register_translator(&lintogsm);
271         else
272                 ast_unregister_translator(&gsmtolin);
273         return res;
274 }
275
276 char *description(void)
277 {
278         return tdesc;
279 }
280
281 int usecount(void)
282 {
283         int res;
284         STANDARD_USECOUNT(res);
285         return res;
286 }
287
288 char *key()
289 {
290         return ASTERISK_GPL_KEY;
291 }