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