Remove pthread.h from source. We should be using asterisk/lock.h everywhere instead...
[asterisk/asterisk.git] / codecs / codec_speex.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Translate between signed linear and Speex (Open Codec)
5  *
6  * Copyright (C) 2002, Digium
7  *
8  * Mark Spencer <markster@digium.com>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  *
13  * This work was motivated by Jeremy McNamara 
14  */
15
16 #define TYPE_SILENCE     0x2
17 #define TYPE_HIGH        0x0
18 #define TYPE_LOW         0x1
19 #define TYPE_MASK        0x3
20
21 #include <asterisk/lock.h>
22 #include <asterisk/translate.h>
23 #include <asterisk/module.h>
24 #include <asterisk/logger.h>
25 #include <asterisk/channel.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 <speex.h>
34
35 /* Sample frame data */
36 #include "slin_speex_ex.h"
37 #include "speex_slin_ex.h"
38
39 AST_MUTEX_DEFINE_STATIC(localuser_lock);
40 static int localusecnt=0;
41
42 static char *tdesc = "Speex/PCM16 (signed linear) Codec Translator";
43
44 struct ast_translator_pvt {
45         void *speex;
46         struct ast_frame f;
47         SpeexBits bits;
48         int framesize;
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 speex_coder_pvt ast_translator_pvt
59
60 static struct ast_translator_pvt *lintospeex_new(void)
61 {
62         struct speex_coder_pvt *tmp;
63         tmp = malloc(sizeof(struct speex_coder_pvt));
64         if (tmp) {
65                 if (!(tmp->speex = speex_encoder_init(&speex_nb_mode))) {
66                         free(tmp);
67                         tmp = NULL;
68                 } else {
69                         speex_bits_init(&tmp->bits);
70                         speex_bits_reset(&tmp->bits);
71                         speex_encoder_ctl(tmp->speex, SPEEX_GET_FRAME_SIZE, &tmp->framesize);
72                         tmp->tail = 0;
73                 }
74                 localusecnt++;
75         }
76         return tmp;
77 }
78
79 static struct ast_translator_pvt *speextolin_new(void)
80 {
81         struct speex_coder_pvt *tmp;
82         tmp = malloc(sizeof(struct speex_coder_pvt));
83         if (tmp) {
84                 if (!(tmp->speex = speex_decoder_init(&speex_nb_mode))) {
85                         free(tmp);
86                         tmp = NULL;
87                 } else {
88                         speex_bits_init(&tmp->bits);
89                         speex_decoder_ctl(tmp->speex, SPEEX_GET_FRAME_SIZE, &tmp->framesize);
90                         tmp->tail = 0;
91                 }
92                 localusecnt++;
93         }
94         return tmp;
95 }
96
97 static struct ast_frame *lintospeex_sample(void)
98 {
99         static struct ast_frame f;
100         f.frametype = AST_FRAME_VOICE;
101         f.subclass = AST_FORMAT_SLINEAR;
102         f.datalen = sizeof(slin_speex_ex);
103         /* Assume 8000 Hz */
104         f.samples = sizeof(slin_speex_ex)/2;
105         f.mallocd = 0;
106         f.offset = 0;
107         f.src = __PRETTY_FUNCTION__;
108         f.data = slin_speex_ex;
109         return &f;
110 }
111
112 static struct ast_frame *speextolin_sample(void)
113 {
114         static struct ast_frame f;
115         f.frametype = AST_FRAME_VOICE;
116         f.subclass = AST_FORMAT_SPEEX;
117         f.datalen = sizeof(speex_slin_ex);
118         /* All frames are 20 ms long */
119         f.samples = 160;
120         f.mallocd = 0;
121         f.offset = 0;
122         f.src = __PRETTY_FUNCTION__;
123         f.data = speex_slin_ex;
124         return &f;
125 }
126
127 static struct ast_frame *speextolin_frameout(struct ast_translator_pvt *tmp)
128 {
129         if (!tmp->tail)
130                 return NULL;
131         /* Signed linear is no particular frame size, so just send whatever
132            we have in the buffer in one lump sum */
133         tmp->f.frametype = AST_FRAME_VOICE;
134         tmp->f.subclass = AST_FORMAT_SLINEAR;
135         tmp->f.datalen = tmp->tail * 2;
136         /* Assume 8000 Hz */
137         tmp->f.samples = tmp->tail;
138         tmp->f.mallocd = 0;
139         tmp->f.offset = AST_FRIENDLY_OFFSET;
140         tmp->f.src = __PRETTY_FUNCTION__;
141         tmp->f.data = tmp->buf;
142         /* Reset tail pointer */
143         tmp->tail = 0;
144         return &tmp->f; 
145 }
146
147 static int speextolin_framein(struct ast_translator_pvt *tmp, struct ast_frame *f)
148 {
149         /* Assuming there's space left, decode into the current buffer at
150            the tail location.  Read in as many frames as there are */
151         int x;
152         int res;
153         float fout[1024];
154         /* Read in bits */
155         speex_bits_read_from(&tmp->bits, f->data, f->datalen);
156         for(;;) {
157                 res = speex_decode(tmp->speex, &tmp->bits, fout);
158                 if (res < 0)
159                         break;
160                 if (tmp->tail + tmp->framesize < sizeof(tmp->buf) / 2) {
161                         for (x=0;x<tmp->framesize;x++) {
162                                 tmp->buf[tmp->tail + x] = fout[x];
163                         }
164                         tmp->tail += tmp->framesize;
165                 } else {
166                         ast_log(LOG_WARNING, "Out of buffer space\n");
167                         return -1;
168                 }
169                 
170         }
171         return 0;
172 }
173
174 static int lintospeex_framein(struct ast_translator_pvt *tmp, struct ast_frame *f)
175 {
176         /* Just add the frames to our stream */
177         /* XXX We should look at how old the rest of our stream is, and if it
178            is too old, then we should overwrite it entirely, otherwise we can
179            get artifacts of earlier talk that do not belong */
180         if (tmp->tail + f->datalen/2 < sizeof(tmp->buf) / 2) {
181                 memcpy((tmp->buf + tmp->tail), f->data, f->datalen);
182                 tmp->tail += f->datalen/2;
183         } else {
184                 ast_log(LOG_WARNING, "Out of buffer space\n");
185                 return -1;
186         }
187         return 0;
188 }
189
190 static struct ast_frame *lintospeex_frameout(struct ast_translator_pvt *tmp)
191 {
192         float fbuf[1024];
193         int len;
194         int y=0,x;
195         /* We can't work on anything less than a frame in size */
196         if (tmp->tail < tmp->framesize)
197                 return NULL;
198         tmp->f.frametype = AST_FRAME_VOICE;
199         tmp->f.subclass = AST_FORMAT_SPEEX;
200         tmp->f.mallocd = 0;
201         tmp->f.offset = AST_FRIENDLY_OFFSET;
202         tmp->f.src = __PRETTY_FUNCTION__;
203         tmp->f.data = tmp->outbuf;
204         speex_bits_reset(&tmp->bits);
205         while(tmp->tail >= tmp->framesize) {
206                 /* Convert to floating point */
207                 for (x=0;x<tmp->framesize;x++)
208                         fbuf[x] = tmp->buf[x];
209                 /* Encode a frame of data */
210                 speex_encode(tmp->speex, fbuf, &tmp->bits);
211                 /* Assume 8000 Hz -- 20 ms */
212                 tmp->tail -= tmp->framesize;
213                 /* Move the data at the end of the buffer to the front */
214                 if (tmp->tail)
215                         memmove(tmp->buf, tmp->buf + tmp->framesize, tmp->tail * 2);
216                 y++;
217         }
218         /* Terminate bit stream */
219         speex_bits_pack(&tmp->bits, 15, 5);
220         len = speex_bits_write(&tmp->bits, (char *)tmp->outbuf, sizeof(tmp->outbuf));
221         tmp->f.datalen = len;
222         tmp->f.samples = y * 160;
223 #if 0
224         {
225                 static int fd = -1;
226                 if (fd  < 0) {
227                         fd = open("speex.raw", O_WRONLY|O_TRUNC|O_CREAT);
228                         if (fd > -1) {
229                                 write(fd, tmp->f.data, tmp->f.datalen);
230                                 close(fd);
231                         }
232                 }
233         }
234 #endif  
235         return &tmp->f; 
236 }
237
238 static void speextolin_destroy(struct ast_translator_pvt *pvt)
239 {
240         speex_decoder_destroy(pvt->speex);
241         speex_bits_destroy(&pvt->bits);
242         free(pvt);
243         localusecnt--;
244 }
245
246 static void lintospeex_destroy(struct ast_translator_pvt *pvt)
247 {
248         speex_encoder_destroy(pvt->speex);
249         speex_bits_destroy(&pvt->bits);
250         free(pvt);
251         localusecnt--;
252 }
253
254 static struct ast_translator speextolin =
255         { "speextolin", 
256            AST_FORMAT_SPEEX, AST_FORMAT_SLINEAR,
257            speextolin_new,
258            speextolin_framein,
259            speextolin_frameout,
260            speextolin_destroy,
261            speextolin_sample
262            };
263
264 static struct ast_translator lintospeex =
265         { "lintospeex", 
266            AST_FORMAT_SLINEAR, AST_FORMAT_SPEEX,
267            lintospeex_new,
268            lintospeex_framein,
269            lintospeex_frameout,
270            lintospeex_destroy,
271            lintospeex_sample
272            };
273
274 int unload_module(void)
275 {
276         int res;
277         ast_mutex_lock(&localuser_lock);
278         res = ast_unregister_translator(&lintospeex);
279         if (!res)
280                 res = ast_unregister_translator(&speextolin);
281         if (localusecnt)
282                 res = -1;
283         ast_mutex_unlock(&localuser_lock);
284         return res;
285 }
286
287 int load_module(void)
288 {
289         int res;
290         res=ast_register_translator(&speextolin);
291         if (!res) 
292                 res=ast_register_translator(&lintospeex);
293         else
294                 ast_unregister_translator(&speextolin);
295         return res;
296 }
297
298 char *description(void)
299 {
300         return tdesc;
301 }
302
303 int usecount(void)
304 {
305         int res;
306         STANDARD_USECOUNT(res);
307         return res;
308 }
309
310 char *key()
311 {
312         return ASTERISK_GPL_KEY;
313 }