Bug 4377 - Round 2 of the loader updates
[asterisk/asterisk.git] / codecs / codec_ilbc.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * The iLBC code is from The IETF code base and is copyright The Internet Society (2004)
5  *
6  * Copyright (C) 1999 - 2005, Digium, Inc.
7  *
8  * Mark Spencer <markster@digium.com>
9  *
10  * See http://www.asterisk.org for more information about
11  * the Asterisk project. Please do not directly contact
12  * any of the maintainers of this project for assistance;
13  * the project provides a web site, mailing lists and IRC
14  * channels for your use.
15  *
16  * This program is free software, distributed under the terms of
17  * the GNU General Public License Version 2. See the LICENSE file
18  * at the top of the source tree.
19  */
20
21 /*! \file
22  *
23  * \brief Translate between signed linear and Internet Low Bitrate Codec
24  * 
25  * \ingroup codecs
26  */
27
28 #include <fcntl.h>
29 #include <stdlib.h>
30 #include <unistd.h>
31 #include <netinet/in.h>
32 #include <string.h>
33 #include <stdio.h>
34
35 #include "asterisk.h"
36
37 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
38
39 #include "asterisk/lock.h"
40 #include "asterisk/translate.h"
41 #include "asterisk/module.h"
42 #include "asterisk/logger.h"
43 #include "asterisk/channel.h"
44 #include "asterisk/utils.h"
45
46 #include "ilbc/iLBC_encode.h"
47 #include "ilbc/iLBC_decode.h"
48
49 /* Sample frame data */
50 #include "slin_ilbc_ex.h"
51 #include "ilbc_slin_ex.h"
52
53 #define USE_ILBC_ENHANCER       0
54 #define ILBC_MS                         30
55 /* #define ILBC_MS                      20 */
56
57 AST_MUTEX_DEFINE_STATIC(localuser_lock);
58 static int localusecnt=0;
59
60 static char *tdesc = "iLBC/PCM16 (signed linear) Codec Translator";
61
62 struct ast_translator_pvt {
63         iLBC_Enc_Inst_t enc;
64         iLBC_Dec_Inst_t dec;
65         struct ast_frame f;
66         /* Space to build offset */
67         char offset[AST_FRIENDLY_OFFSET];
68         /* Buffer for our outgoing frame */
69         short outbuf[8000];
70         /* Enough to store a full second */
71         short buf[8000];
72         int tail;
73 };
74
75 #define ilbc_coder_pvt ast_translator_pvt
76
77 static struct ast_translator_pvt *lintoilbc_new(void)
78 {
79         struct ilbc_coder_pvt *tmp;
80         if ((tmp = ast_malloc(sizeof(*tmp)))) {
81                 /* Shut valgrind up */
82                 memset(&tmp->enc, 0, sizeof(tmp->enc));
83                 initEncode(&tmp->enc, ILBC_MS);
84                 tmp->tail = 0;
85                 localusecnt++;
86         }
87         return tmp;
88 }
89
90 static struct ast_translator_pvt *ilbctolin_new(void)
91 {
92         struct ilbc_coder_pvt *tmp;     
93         if ((tmp = ast_malloc(sizeof(*tmp)))) {
94                 /* Shut valgrind up */
95                 memset(&tmp->dec, 0, sizeof(tmp->dec));
96                 initDecode(&tmp->dec, ILBC_MS, USE_ILBC_ENHANCER);
97                 tmp->tail = 0;
98                 localusecnt++;
99         }
100         return tmp;
101 }
102
103 static struct ast_frame *lintoilbc_sample(void)
104 {
105         static struct ast_frame f;
106         f.frametype = AST_FRAME_VOICE;
107         f.subclass = AST_FORMAT_SLINEAR;
108         f.datalen = sizeof(slin_ilbc_ex);
109         /* Assume 8000 Hz */
110         f.samples = sizeof(slin_ilbc_ex)/2;
111         f.mallocd = 0;
112         f.offset = 0;
113         f.src = __PRETTY_FUNCTION__;
114         f.data = slin_ilbc_ex;
115         return &f;
116 }
117
118 static struct ast_frame *ilbctolin_sample(void)
119 {
120         static struct ast_frame f;
121         f.frametype = AST_FRAME_VOICE;
122         f.subclass = AST_FORMAT_ILBC;
123         f.datalen = sizeof(ilbc_slin_ex);
124         /* All frames are 30 ms long */
125         f.samples = 240;
126         f.mallocd = 0;
127         f.offset = 0;
128         f.src = __PRETTY_FUNCTION__;
129         f.data = ilbc_slin_ex;
130         return &f;
131 }
132
133 static struct ast_frame *ilbctolin_frameout(struct ast_translator_pvt *tmp)
134 {
135         if (!tmp->tail)
136                 return NULL;
137         /* Signed linear is no particular frame size, so just send whatever
138            we have in the buffer in one lump sum */
139         tmp->f.frametype = AST_FRAME_VOICE;
140         tmp->f.subclass = AST_FORMAT_SLINEAR;
141         tmp->f.datalen = tmp->tail * 2;
142         /* Assume 8000 Hz */
143         tmp->f.samples = tmp->tail;
144         tmp->f.mallocd = 0;
145         tmp->f.offset = AST_FRIENDLY_OFFSET;
146         tmp->f.src = __PRETTY_FUNCTION__;
147         tmp->f.data = tmp->buf;
148         /* Reset tail pointer */
149         tmp->tail = 0;
150
151         return &tmp->f; 
152 }
153
154 static int ilbctolin_framein(struct ast_translator_pvt *tmp, struct ast_frame *f)
155 {
156         /* Assuming there's space left, decode into the current buffer at
157            the tail location.  Read in as many frames as there are */
158         int x,i;
159         float tmpf[240];
160
161         if (f->datalen == 0) { /* native PLC */
162                 if (tmp->tail + 240 < sizeof(tmp->buf)/2) {     
163                         iLBC_decode(tmpf, NULL, &tmp->dec, 0);
164                         for (i=0;i<240;i++)
165                                 tmp->buf[tmp->tail + i] = tmpf[i];
166                         tmp->tail+=240;
167                 } else {
168                         ast_log(LOG_WARNING, "Out of buffer space\n");
169                         return -1;
170                 }               
171         }
172
173         if (f->datalen % 50) {
174                 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);
175                 return -1;
176         }
177         
178         for (x=0;x<f->datalen;x+=50) {
179                 if (tmp->tail + 240 < sizeof(tmp->buf)/2) {     
180                         iLBC_decode(tmpf, f->data + x, &tmp->dec, 1);
181                         for (i=0;i<240;i++)
182                                 tmp->buf[tmp->tail + i] = tmpf[i];
183                         tmp->tail+=240;
184                 } else {
185                         ast_log(LOG_WARNING, "Out of buffer space\n");
186                         return -1;
187                 }               
188         }
189         return 0;
190 }
191
192 static int lintoilbc_framein(struct ast_translator_pvt *tmp, struct ast_frame *f)
193 {
194         /* Just add the frames to our stream */
195         /* XXX We should look at how old the rest of our stream is, and if it
196            is too old, then we should overwrite it entirely, otherwise we can
197            get artifacts of earlier talk that do not belong */
198         if (tmp->tail + f->datalen/2 < sizeof(tmp->buf) / 2) {
199                 memcpy((tmp->buf + tmp->tail), f->data, f->datalen);
200                 tmp->tail += f->datalen/2;
201         } else {
202                 ast_log(LOG_WARNING, "Out of buffer space\n");
203                 return -1;
204         }
205         return 0;
206 }
207
208 static struct ast_frame *lintoilbc_frameout(struct ast_translator_pvt *tmp)
209 {
210         int x=0,i;
211         float tmpf[240];
212         /* We can't work on anything less than a frame in size */
213         if (tmp->tail < 240)
214                 return NULL;
215         tmp->f.frametype = AST_FRAME_VOICE;
216         tmp->f.subclass = AST_FORMAT_ILBC;
217         tmp->f.mallocd = 0;
218         tmp->f.offset = AST_FRIENDLY_OFFSET;
219         tmp->f.src = __PRETTY_FUNCTION__;
220         tmp->f.data = tmp->outbuf;
221         while(tmp->tail >= 240) {
222                 if ((x+1) * 50 >= sizeof(tmp->outbuf)) {
223                         ast_log(LOG_WARNING, "Out of buffer space\n");
224                         break;
225                 }
226                 for (i=0;i<240;i++)
227                         tmpf[i] = tmp->buf[i];
228                 /* Encode a frame of data */
229                 iLBC_encode(((unsigned char *)(tmp->outbuf)) + (x * 50), tmpf, &tmp->enc);
230                 /* Assume 8000 Hz -- 20 ms */
231                 tmp->tail -= 240;
232                 /* Move the data at the end of the buffer to the front */
233                 if (tmp->tail)
234                         memmove(tmp->buf, tmp->buf + 240, tmp->tail * 2);
235                 x++;
236         }
237         tmp->f.datalen = x * 50;
238         tmp->f.samples = x * 240;
239 #if 0
240         {
241                 static int fd = -1;
242                 if (fd == -1) {
243                         fd = open("ilbc.out", O_CREAT|O_TRUNC|O_WRONLY, 0666);
244                         write(fd, tmp->f.data, tmp->f.datalen);
245                         close(fd);
246                 }
247         }
248 #endif  
249         return &tmp->f; 
250 }
251
252 static void ilbc_destroy_stuff(struct ast_translator_pvt *pvt)
253 {
254         free(pvt);
255         localusecnt--;
256 }
257
258 static struct ast_translator ilbctolin =
259         { "ilbctolin", 
260            AST_FORMAT_ILBC, AST_FORMAT_SLINEAR,
261            ilbctolin_new,
262            ilbctolin_framein,
263            ilbctolin_frameout,
264            ilbc_destroy_stuff,
265            ilbctolin_sample
266            };
267
268 static struct ast_translator lintoilbc =
269         { "lintoilbc", 
270            AST_FORMAT_SLINEAR, AST_FORMAT_ILBC,
271            lintoilbc_new,
272            lintoilbc_framein,
273            lintoilbc_frameout,
274            ilbc_destroy_stuff,
275            lintoilbc_sample
276            };
277
278 int unload_module(void)
279 {
280         int res;
281         ast_mutex_lock(&localuser_lock);
282         res = ast_unregister_translator(&lintoilbc);
283         if (!res)
284                 res = ast_unregister_translator(&ilbctolin);
285         if (localusecnt)
286                 res = -1;
287         ast_mutex_unlock(&localuser_lock);
288         return res;
289 }
290
291 int load_module(void)
292 {
293         int res;
294         res=ast_register_translator(&ilbctolin);
295         if (!res) 
296                 res=ast_register_translator(&lintoilbc);
297         else
298                 ast_unregister_translator(&ilbctolin);
299         return res;
300 }
301
302 char *description(void)
303 {
304         return tdesc;
305 }
306
307 int usecount(void)
308 {
309         int res;
310         OLD_STANDARD_USECOUNT(res);
311         return res;
312 }
313
314 char *key()
315 {
316         return ASTERISK_GPL_KEY;
317 }