684d5d1328518cf721535efa56becfa721567b3b
[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  * hacked to be configurable by anthm and bkw 9/28/2004
15  */
16
17 static int quality = 8;
18 static int complexity = 2;
19 static int enhancement = 0;
20 static int vad = 0;
21 static int vbr = 0;
22 static int vbr_quality = 0;
23 static int abr = 0;
24 static int abr_quality = 0;
25 static int dtx = 0;
26
27 #define TYPE_SILENCE     0x2
28 #define TYPE_HIGH        0x0
29 #define TYPE_LOW         0x1
30 #define TYPE_MASK        0x3
31
32 #include <asterisk/lock.h>
33 #include <asterisk/translate.h>
34 #include <asterisk/module.h>
35 #include <asterisk/config.h>
36 #include <asterisk/options.h>
37 #include <asterisk/logger.h>
38 #include <asterisk/channel.h>
39 #include <fcntl.h>
40 #include <stdlib.h>
41 #include <unistd.h>
42 #include <netinet/in.h>
43 #include <string.h>
44 #include <stdio.h>
45
46 #include <speex.h>
47
48 /* Sample frame data */
49 #include "slin_speex_ex.h"
50 #include "speex_slin_ex.h"
51
52 AST_MUTEX_DEFINE_STATIC(localuser_lock);
53 static int localusecnt=0;
54
55 static char *tdesc = "Speex/PCM16 (signed linear) Codec Translator";
56
57 struct ast_translator_pvt {
58         void *speex;
59         struct ast_frame f;
60         SpeexBits bits;
61         int framesize;
62         /* Space to build offset */
63         char offset[AST_FRIENDLY_OFFSET];
64         /* Buffer for our outgoing frame */
65         short outbuf[8000];
66         /* Enough to store a full second */
67         short buf[8000];
68         int tail;
69 };
70
71 #define speex_coder_pvt ast_translator_pvt
72
73 static struct ast_translator_pvt *lintospeex_new(void)
74 {
75         struct speex_coder_pvt *tmp;
76         tmp = malloc(sizeof(struct speex_coder_pvt));
77         if (tmp) {
78                 if (!(tmp->speex = speex_encoder_init(&speex_nb_mode))) {
79                         free(tmp);
80                         tmp = NULL;
81                 } else {
82                         speex_bits_init(&tmp->bits);
83                         speex_bits_reset(&tmp->bits);
84                         speex_encoder_ctl(tmp->speex, SPEEX_GET_FRAME_SIZE, &tmp->framesize);
85                         speex_encoder_ctl(tmp->speex, SPEEX_SET_QUALITY, &quality);
86                         speex_encoder_ctl(tmp->speex, SPEEX_SET_COMPLEXITY, &complexity);
87
88                         if (vad)
89                                 speex_encoder_ctl(tmp->speex, SPEEX_SET_VAD, &vad);
90                         if (dtx)
91                                 speex_encoder_ctl(tmp->speex, SPEEX_SET_DTX, &vad);
92                         if (vbr) {
93                                 speex_encoder_ctl(tmp->speex, SPEEX_SET_VBR, &vbr);
94                                 speex_encoder_ctl(tmp->speex, SPEEX_SET_VBR_QUALITY, &vbr_quality);
95                         }
96                         if (abr) {
97                                 speex_encoder_ctl(tmp->speex, SPEEX_SET_VBR, &abr);
98                                 speex_encoder_ctl(tmp->speex, SPEEX_SET_VBR_QUALITY, &abr_quality);
99                         }
100                         tmp->tail = 0;
101                 }
102                 localusecnt++;
103         }
104         return tmp;
105 }
106
107 static struct ast_translator_pvt *speextolin_new(void)
108 {
109         struct speex_coder_pvt *tmp;
110         tmp = malloc(sizeof(struct speex_coder_pvt));
111         if (tmp) {
112                 if (!(tmp->speex = speex_decoder_init(&speex_nb_mode))) {
113                         free(tmp);
114                         tmp = NULL;
115                 } else {
116                         speex_bits_init(&tmp->bits);
117                         speex_decoder_ctl(tmp->speex, SPEEX_GET_FRAME_SIZE, &tmp->framesize);
118                         if (enhancement)
119                                 speex_decoder_ctl(tmp->speex, SPEEX_SET_ENH, &enhancement);
120                         tmp->tail = 0;
121                 }
122                 localusecnt++;
123         }
124         return tmp;
125 }
126
127 static struct ast_frame *lintospeex_sample(void)
128 {
129         static struct ast_frame f;
130         f.frametype = AST_FRAME_VOICE;
131         f.subclass = AST_FORMAT_SLINEAR;
132         f.datalen = sizeof(slin_speex_ex);
133         /* Assume 8000 Hz */
134         f.samples = sizeof(slin_speex_ex)/2;
135         f.mallocd = 0;
136         f.offset = 0;
137         f.src = __PRETTY_FUNCTION__;
138         f.data = slin_speex_ex;
139         return &f;
140 }
141
142 static struct ast_frame *speextolin_sample(void)
143 {
144         static struct ast_frame f;
145         f.frametype = AST_FRAME_VOICE;
146         f.subclass = AST_FORMAT_SPEEX;
147         f.datalen = sizeof(speex_slin_ex);
148         /* All frames are 20 ms long */
149         f.samples = 160;
150         f.mallocd = 0;
151         f.offset = 0;
152         f.src = __PRETTY_FUNCTION__;
153         f.data = speex_slin_ex;
154         return &f;
155 }
156
157 static struct ast_frame *speextolin_frameout(struct ast_translator_pvt *tmp)
158 {
159         if (!tmp->tail)
160                 return NULL;
161         /* Signed linear is no particular frame size, so just send whatever
162            we have in the buffer in one lump sum */
163         tmp->f.frametype = AST_FRAME_VOICE;
164         tmp->f.subclass = AST_FORMAT_SLINEAR;
165         tmp->f.datalen = tmp->tail * 2;
166         /* Assume 8000 Hz */
167         tmp->f.samples = tmp->tail;
168         tmp->f.mallocd = 0;
169         tmp->f.offset = AST_FRIENDLY_OFFSET;
170         tmp->f.src = __PRETTY_FUNCTION__;
171         tmp->f.data = tmp->buf;
172         /* Reset tail pointer */
173         tmp->tail = 0;
174         return &tmp->f; 
175 }
176
177 static int speextolin_framein(struct ast_translator_pvt *tmp, struct ast_frame *f)
178 {
179         /* Assuming there's space left, decode into the current buffer at
180            the tail location.  Read in as many frames as there are */
181         int x;
182         int res;
183         float fout[1024];
184         /* Read in bits */
185         speex_bits_read_from(&tmp->bits, f->data, f->datalen);
186         for(;;) {
187                 res = speex_decode(tmp->speex, &tmp->bits, fout);
188                 if (res < 0)
189                         break;
190                 if (tmp->tail + tmp->framesize < sizeof(tmp->buf) / 2) {
191                         for (x=0;x<tmp->framesize;x++) {
192                                 tmp->buf[tmp->tail + x] = fout[x];
193                         }
194                         tmp->tail += tmp->framesize;
195                 } else {
196                         ast_log(LOG_WARNING, "Out of buffer space\n");
197                         return -1;
198                 }
199                 
200         }
201         return 0;
202 }
203
204 static int lintospeex_framein(struct ast_translator_pvt *tmp, struct ast_frame *f)
205 {
206         /* Just add the frames to our stream */
207         /* XXX We should look at how old the rest of our stream is, and if it
208            is too old, then we should overwrite it entirely, otherwise we can
209            get artifacts of earlier talk that do not belong */
210         if (tmp->tail + f->datalen/2 < sizeof(tmp->buf) / 2) {
211                 memcpy((tmp->buf + tmp->tail), f->data, f->datalen);
212                 tmp->tail += f->datalen/2;
213         } else {
214                 ast_log(LOG_WARNING, "Out of buffer space\n");
215                 return -1;
216         }
217         return 0;
218 }
219
220 static struct ast_frame *lintospeex_frameout(struct ast_translator_pvt *tmp)
221 {
222         float fbuf[1024];
223         int len;
224         int y=0,x;
225         /* We can't work on anything less than a frame in size */
226         if (tmp->tail < tmp->framesize)
227                 return NULL;
228         tmp->f.frametype = AST_FRAME_VOICE;
229         tmp->f.subclass = AST_FORMAT_SPEEX;
230         tmp->f.mallocd = 0;
231         tmp->f.offset = AST_FRIENDLY_OFFSET;
232         tmp->f.src = __PRETTY_FUNCTION__;
233         tmp->f.data = tmp->outbuf;
234         speex_bits_reset(&tmp->bits);
235         while(tmp->tail >= tmp->framesize) {
236                 /* Convert to floating point */
237                 for (x=0;x<tmp->framesize;x++)
238                         fbuf[x] = tmp->buf[x];
239                 /* Encode a frame of data */
240                 speex_encode(tmp->speex, fbuf, &tmp->bits);
241                 /* Assume 8000 Hz -- 20 ms */
242                 tmp->tail -= tmp->framesize;
243                 /* Move the data at the end of the buffer to the front */
244                 if (tmp->tail)
245                         memmove(tmp->buf, tmp->buf + tmp->framesize, tmp->tail * 2);
246                 y++;
247         }
248         /* Terminate bit stream */
249         speex_bits_pack(&tmp->bits, 15, 5);
250         len = speex_bits_write(&tmp->bits, (char *)tmp->outbuf, sizeof(tmp->outbuf));
251         tmp->f.datalen = len;
252         tmp->f.samples = y * 160;
253 #if 0
254         {
255                 static int fd = -1;
256                 if (fd  < 0) {
257                         fd = open("speex.raw", O_WRONLY|O_TRUNC|O_CREAT);
258                         if (fd > -1) {
259                                 write(fd, tmp->f.data, tmp->f.datalen);
260                                 close(fd);
261                         }
262                 }
263         }
264 #endif  
265         return &tmp->f; 
266 }
267
268 static void speextolin_destroy(struct ast_translator_pvt *pvt)
269 {
270         speex_decoder_destroy(pvt->speex);
271         speex_bits_destroy(&pvt->bits);
272         free(pvt);
273         localusecnt--;
274 }
275
276 static void lintospeex_destroy(struct ast_translator_pvt *pvt)
277 {
278         speex_encoder_destroy(pvt->speex);
279         speex_bits_destroy(&pvt->bits);
280         free(pvt);
281         localusecnt--;
282 }
283
284 static struct ast_translator speextolin =
285         { "speextolin", 
286            AST_FORMAT_SPEEX, AST_FORMAT_SLINEAR,
287            speextolin_new,
288            speextolin_framein,
289            speextolin_frameout,
290            speextolin_destroy,
291            speextolin_sample
292            };
293
294 static struct ast_translator lintospeex =
295         { "lintospeex", 
296            AST_FORMAT_SLINEAR, AST_FORMAT_SPEEX,
297            lintospeex_new,
298            lintospeex_framein,
299            lintospeex_frameout,
300            lintospeex_destroy,
301            lintospeex_sample
302         };
303
304
305 static void parse_config(void) 
306 {
307         struct ast_config *cfg;
308         struct ast_variable *var;
309         int res;
310
311         if ((cfg = ast_load("codecs.conf"))) {
312                 if ((var = ast_variable_browse(cfg, "speex"))) {
313                         while (var) {
314                                 if (!strcasecmp(var->name, "quality")) {
315                                         res = abs(atoi(var->value));
316                                         if (res > -1 && res < 11) {
317                                                 if (option_verbose > 2)
318                                                         ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Setting Quality to %d\n",res);
319                                                 ast_mutex_lock(&localuser_lock);
320                                                 quality = res;
321                                                 ast_mutex_unlock(&localuser_lock);
322                                         } else 
323                                                 ast_log(LOG_ERROR,"Error Quality must be 0-10\n");
324                                 } else if (!strcasecmp(var->name, "complexity")) {
325                                         res = abs(atoi(var->value));
326                                         if (option_verbose > 2)
327                                                 ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Setting Complexity to %d\n",res);
328                                         if (res > -1 && res < 11) {
329                                                 ast_mutex_lock(&localuser_lock);
330                                                 complexity = res;
331                                                 ast_mutex_unlock(&localuser_lock);
332                                         } else 
333                                                 ast_log(LOG_ERROR,"Error! Complexity must be 0-10\n");
334                                 } else if (!strcasecmp(var->name, "vbr_quality")) {
335                                         res = abs(atoi(var->value));
336                                         if (option_verbose > 2)
337                                                 ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Setting VBR Quality to %d\n",res);
338                                         if (res > -1 && res < 11) {
339                                                 ast_mutex_lock(&localuser_lock);
340                                                 vbr_quality = res;
341                                                 ast_mutex_unlock(&localuser_lock);
342                                         } else 
343                                                 ast_log(LOG_ERROR,"Error! VBR Quality must be 0-10\n");
344                                 } else if (!strcasecmp(var->name, "abr_quality")) {
345                                         res = abs(atoi(var->value));
346                                         if (option_verbose > 2)
347                                                 ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Setting ABR Quality to %d\n",res);
348                                         if (res > -1 && res < 11) {
349                                                 ast_mutex_lock(&localuser_lock);
350                                                 abr_quality = res;
351                                                 ast_mutex_unlock(&localuser_lock);
352                                         } else 
353                                                 ast_log(LOG_ERROR,"Error! ABR Quality must be 0-10\n");
354                                 } else if (!strcasecmp(var->name, "enhancement")) {
355                                         ast_mutex_lock(&localuser_lock);
356                                         enhancement = ast_true(var->value) ? 1 : 0;
357                                         if (option_verbose > 2)
358                                                 ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Perceptual Enhancement Mode. [%s]\n",enhancement ? "on" : "off");
359                                         ast_mutex_unlock(&localuser_lock);
360                                 } else if (!strcasecmp(var->name, "vbr")) {
361                                         ast_mutex_lock(&localuser_lock);
362                                         vbr = ast_true(var->value) ? 1 : 0;
363                                         if (option_verbose > 2)
364                                                 ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: VBR Mode. [%s]\n",vbr ? "on" : "off");
365                                         ast_mutex_unlock(&localuser_lock);
366                                 } else if (!strcasecmp(var->name, "abr")) {
367                                         ast_mutex_lock(&localuser_lock);
368                                         abr = ast_true(var->value) ? 1 : 0;
369                                         if (option_verbose > 2)
370                                                 ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: ABR Mode. [%s]\n",vbr ? "on" : "off");
371                                         ast_mutex_unlock(&localuser_lock);
372                                 } else if (!strcasecmp(var->name, "vad")) {
373                                         ast_mutex_lock(&localuser_lock);
374                                         vad = ast_true(var->value) ? 1 : 0;
375                                         if (option_verbose > 2)
376                                                 ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: VAD Mode. [%s]\n",vbr ? "on" : "off");
377                                         ast_mutex_unlock(&localuser_lock);
378                                 } else if (!strcasecmp(var->name, "dtx")) {
379                                         ast_mutex_lock(&localuser_lock);
380                                         dtx = ast_true(var->value) ? 1 : 0;
381                                         if (option_verbose > 2)
382                                                 ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: DTX Mode. [%s]\n",dtx ? "on" : "off");
383                                         ast_mutex_unlock(&localuser_lock);
384                                 }
385                                 var = var->next;
386                         }
387                 }
388         }
389 }
390
391 int reload(void) 
392 {
393         parse_config();
394         return 0;
395 }
396
397 int unload_module(void)
398 {
399         int res;
400         ast_mutex_lock(&localuser_lock);
401         res = ast_unregister_translator(&lintospeex);
402         if (!res)
403                 res = ast_unregister_translator(&speextolin);
404         if (localusecnt)
405                 res = -1;
406         ast_mutex_unlock(&localuser_lock);
407         return res;
408 }
409
410 int load_module(void)
411 {
412         int res;
413         parse_config();
414         res=ast_register_translator(&speextolin);
415         if (!res) 
416                 res=ast_register_translator(&lintospeex);
417         else
418                 ast_unregister_translator(&speextolin);
419         return res;
420 }
421
422 char *description(void)
423 {
424         return tdesc;
425 }
426
427 int usecount(void)
428 {
429         int res;
430         STANDARD_USECOUNT(res);
431         return res;
432 }
433
434 char *key()
435 {
436         return ASTERISK_GPL_KEY;
437 }