Use 50 bytes instead of 52 bytes on ilbc
[asterisk/asterisk.git] / codecs / codec_ilbc.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Translate between signed linear and Internet Low Bitrate Codec
5  *
6  * The iLBC code is from The IETF code base and is copyright GlobalSound, AB
7  * 
8  * Copyright (C) 1999, Mark Spencer
9  *
10  * Mark Spencer <markster@linux-support.net>
11  *
12  * This program is free software, distributed under the terms of
13  * the GNU General Public License
14  */
15
16 #include <asterisk/lock.h>
17 #include <asterisk/translate.h>
18 #include <asterisk/module.h>
19 #include <asterisk/logger.h>
20 #include <asterisk/channel.h>
21 #include <pthread.h>
22 #include <fcntl.h>
23 #include <stdlib.h>
24 #include <unistd.h>
25 #include <netinet/in.h>
26 #include <string.h>
27 #include <stdio.h>
28
29 #include "ilbc/iLBC_encode.h"
30 #include "ilbc/iLBC_decode.h"
31
32 /* Sample frame data */
33 #include "slin_ilbc_ex.h"
34 #include "ilbc_slin_ex.h"
35
36 #define USE_ILBC_ENHANCER       0
37
38 static pthread_mutex_t localuser_lock = AST_MUTEX_INITIALIZER;
39 static int localusecnt=0;
40
41 static char *tdesc = "iLBC/PCM16 (signed linear) Codec Translator";
42
43 struct ast_translator_pvt {
44         iLBC_Enc_Inst_t enc;
45         iLBC_Dec_Inst_t dec;
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 ilbc_coder_pvt ast_translator_pvt
57
58 static struct ast_translator_pvt *lintoilbc_new(void)
59 {
60         struct ilbc_coder_pvt *tmp;
61         tmp = malloc(sizeof(struct ilbc_coder_pvt));
62         if (tmp) {
63                 initEncode(&tmp->enc);
64                 tmp->tail = 0;
65                 localusecnt++;
66         }
67         return tmp;
68 }
69
70 static struct ast_translator_pvt *ilbctolin_new(void)
71 {
72         struct ilbc_coder_pvt *tmp;
73         tmp = malloc(sizeof(struct ilbc_coder_pvt));
74         if (tmp) {
75                 initDecode(&tmp->dec, USE_ILBC_ENHANCER);
76                 tmp->tail = 0;
77                 localusecnt++;
78         }
79         return tmp;
80 }
81
82 static struct ast_frame *lintoilbc_sample(void)
83 {
84         static struct ast_frame f;
85         f.frametype = AST_FRAME_VOICE;
86         f.subclass = AST_FORMAT_SLINEAR;
87         f.datalen = sizeof(slin_ilbc_ex);
88         /* Assume 8000 Hz */
89         f.samples = sizeof(slin_ilbc_ex)/2;
90         f.mallocd = 0;
91         f.offset = 0;
92         f.src = __PRETTY_FUNCTION__;
93         f.data = slin_ilbc_ex;
94         return &f;
95 }
96
97 static struct ast_frame *ilbctolin_sample(void)
98 {
99         static struct ast_frame f;
100         f.frametype = AST_FRAME_VOICE;
101         f.subclass = AST_FORMAT_ILBC;
102         f.datalen = sizeof(ilbc_slin_ex);
103         /* All frames are 30 ms long */
104         f.samples = 240;
105         f.mallocd = 0;
106         f.offset = 0;
107         f.src = __PRETTY_FUNCTION__;
108         f.data = ilbc_slin_ex;
109         return &f;
110 }
111
112 static struct ast_frame *ilbctolin_frameout(struct ast_translator_pvt *tmp)
113 {
114         if (!tmp->tail)
115                 return NULL;
116         /* Signed linear is no particular frame size, so just send whatever
117            we have in the buffer in one lump sum */
118         tmp->f.frametype = AST_FRAME_VOICE;
119         tmp->f.subclass = AST_FORMAT_SLINEAR;
120         tmp->f.datalen = tmp->tail * 2;
121         /* Assume 8000 Hz */
122         tmp->f.samples = tmp->tail;
123         tmp->f.mallocd = 0;
124         tmp->f.offset = AST_FRIENDLY_OFFSET;
125         tmp->f.src = __PRETTY_FUNCTION__;
126         tmp->f.data = tmp->buf;
127         /* Reset tail pointer */
128         tmp->tail = 0;
129
130         return &tmp->f; 
131 }
132
133 static int ilbctolin_framein(struct ast_translator_pvt *tmp, struct ast_frame *f)
134 {
135         /* Assuming there's space left, decode into the current buffer at
136            the tail location.  Read in as many frames as there are */
137         int x,i;
138         float tmpf[240];
139         
140         if (f->datalen % 50) {
141                 ast_log(LOG_WARNING, "Huh?  An ilbc frame that isn't a multiple of 50 bytes long from %s (%d)?\n", f->src, f->datalen);
142                 return -1;
143         }
144         
145         for (x=0;x<f->datalen;x+=50) {
146                 if (tmp->tail + 240 < sizeof(tmp->buf)/2) {     
147                         iLBC_decode(tmpf, f->data + x, &tmp->dec, 1);
148                         for (i=0;i<240;i++)
149                                 tmp->buf[tmp->tail + i] = tmpf[i];
150                         tmp->tail+=240;
151                 } else {
152                         ast_log(LOG_WARNING, "Out of buffer space\n");
153                         return -1;
154                 }               
155         }
156         return 0;
157 }
158
159 static int lintoilbc_framein(struct ast_translator_pvt *tmp, struct ast_frame *f)
160 {
161         /* Just add the frames to our stream */
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 (tmp->tail + f->datalen/2 < sizeof(tmp->buf) / 2) {
166                 memcpy((tmp->buf + tmp->tail), f->data, f->datalen);
167                 tmp->tail += f->datalen/2;
168         } else {
169                 ast_log(LOG_WARNING, "Out of buffer space\n");
170                 return -1;
171         }
172         return 0;
173 }
174
175 static struct ast_frame *lintoilbc_frameout(struct ast_translator_pvt *tmp)
176 {
177         int x=0,i;
178         float tmpf[240];
179         /* We can't work on anything less than a frame in size */
180         if (tmp->tail < 240)
181                 return NULL;
182         tmp->f.frametype = AST_FRAME_VOICE;
183         tmp->f.subclass = AST_FORMAT_ILBC;
184         tmp->f.mallocd = 0;
185         tmp->f.offset = AST_FRIENDLY_OFFSET;
186         tmp->f.src = __PRETTY_FUNCTION__;
187         tmp->f.data = tmp->outbuf;
188         while(tmp->tail >= 240) {
189                 if ((x+1) * 50 >= sizeof(tmp->outbuf)) {
190                         ast_log(LOG_WARNING, "Out of buffer space\n");
191                         break;
192                 }
193                 for (i=0;i<240;i++)
194                         tmpf[i] = tmp->buf[i];
195                 /* Encode a frame of data */
196                 iLBC_encode(((unsigned char *)(tmp->outbuf)) + (x * 50), tmpf, &tmp->enc);
197                 /* Assume 8000 Hz -- 20 ms */
198                 tmp->tail -= 240;
199                 /* Move the data at the end of the buffer to the front */
200                 if (tmp->tail)
201                         memmove(tmp->buf, tmp->buf + 240, tmp->tail * 2);
202                 x++;
203         }
204         tmp->f.datalen = x * 50;
205         tmp->f.samples = x * 240;
206 #if 0
207         {
208                 static int fd = -1;
209                 if (fd == -1) {
210                         fd = open("ilbc.out", O_CREAT|O_TRUNC|O_WRONLY, 0666);
211                         write(fd, tmp->f.data, tmp->f.datalen);
212                         close(fd);
213                 }
214         }
215 #endif  
216         return &tmp->f; 
217 }
218
219 static void ilbc_destroy_stuff(struct ast_translator_pvt *pvt)
220 {
221         free(pvt);
222         localusecnt--;
223 }
224
225 static struct ast_translator ilbctolin =
226         { "ilbctolin", 
227            AST_FORMAT_ILBC, AST_FORMAT_SLINEAR,
228            ilbctolin_new,
229            ilbctolin_framein,
230            ilbctolin_frameout,
231            ilbc_destroy_stuff,
232            ilbctolin_sample
233            };
234
235 static struct ast_translator lintoilbc =
236         { "lintoilbc", 
237            AST_FORMAT_SLINEAR, AST_FORMAT_ILBC,
238            lintoilbc_new,
239            lintoilbc_framein,
240            lintoilbc_frameout,
241            ilbc_destroy_stuff,
242            lintoilbc_sample
243            };
244
245 int unload_module(void)
246 {
247         int res;
248         ast_pthread_mutex_lock(&localuser_lock);
249         res = ast_unregister_translator(&lintoilbc);
250         if (!res)
251                 res = ast_unregister_translator(&ilbctolin);
252         if (localusecnt)
253                 res = -1;
254         ast_pthread_mutex_unlock(&localuser_lock);
255         return res;
256 }
257
258 int load_module(void)
259 {
260         int res;
261         res=ast_register_translator(&ilbctolin);
262         if (!res) 
263                 res=ast_register_translator(&lintoilbc);
264         else
265                 ast_unregister_translator(&ilbctolin);
266         return res;
267 }
268
269 char *description(void)
270 {
271         return tdesc;
272 }
273
274 int usecount(void)
275 {
276         int res;
277         STANDARD_USECOUNT(res);
278         return res;
279 }
280
281 char *key()
282 {
283         return ASTERISK_GPL_KEY;
284 }