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