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