more file version tags
[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 int 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("$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, &vad);
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
330         if ((cfg = ast_config_load("codecs.conf"))) {
331                 if ((var = ast_variable_browse(cfg, "speex"))) {
332                         while (var) {
333                                 if (!strcasecmp(var->name, "quality")) {
334                                         res = abs(atoi(var->value));
335                                         if (res > -1 && res < 11) {
336                                                 if (option_verbose > 2)
337                                                         ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Setting Quality to %d\n",res);
338                                                 ast_mutex_lock(&localuser_lock);
339                                                 quality = res;
340                                                 ast_mutex_unlock(&localuser_lock);
341                                         } else 
342                                                 ast_log(LOG_ERROR,"Error Quality must be 0-10\n");
343                                 } else if (!strcasecmp(var->name, "complexity")) {
344                                         res = abs(atoi(var->value));
345                                         if (option_verbose > 2)
346                                                 ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Setting Complexity to %d\n",res);
347                                         if (res > -1 && res < 11) {
348                                                 ast_mutex_lock(&localuser_lock);
349                                                 complexity = res;
350                                                 ast_mutex_unlock(&localuser_lock);
351                                         } else 
352                                                 ast_log(LOG_ERROR,"Error! Complexity must be 0-10\n");
353                                 } else if (!strcasecmp(var->name, "vbr_quality")) {
354                                         res = abs(atoi(var->value));
355                                         if (option_verbose > 2)
356                                                 ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Setting VBR Quality to %d\n",res);
357                                         if (res > -1 && res < 11) {
358                                                 ast_mutex_lock(&localuser_lock);
359                                                 vbr_quality = res;
360                                                 ast_mutex_unlock(&localuser_lock);
361                                         } else 
362                                                 ast_log(LOG_ERROR,"Error! VBR Quality must be 0-10\n");
363                                 } else if (!strcasecmp(var->name, "abr_quality")) {
364                                         ast_log(LOG_ERROR,"Error! ABR Quality setting obsolete, set ABR to desired bitrate\n");
365                                 } else if (!strcasecmp(var->name, "enhancement")) {
366                                         ast_mutex_lock(&localuser_lock);
367                                         enhancement = ast_true(var->value) ? 1 : 0;
368                                         if (option_verbose > 2)
369                                                 ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Perceptual Enhancement Mode. [%s]\n",enhancement ? "on" : "off");
370                                         ast_mutex_unlock(&localuser_lock);
371                                 } else if (!strcasecmp(var->name, "vbr")) {
372                                         ast_mutex_lock(&localuser_lock);
373                                         vbr = ast_true(var->value) ? 1 : 0;
374                                         if (option_verbose > 2)
375                                                 ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: VBR Mode. [%s]\n",vbr ? "on" : "off");
376                                         ast_mutex_unlock(&localuser_lock);
377                                 } else if (!strcasecmp(var->name, "abr")) {
378                                         res = abs(atoi(var->value));
379                                         if (option_verbose > 2) {
380                                               if(res > 0)
381                                                 ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Setting ABR target bitrate to %d\n",res);
382                                               else
383                                                 ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Disabling ABR\n");
384                                         }
385                                         if (res >= 0) {
386                                                 ast_mutex_lock(&localuser_lock);
387                                                 abr = res;
388                                                 ast_mutex_unlock(&localuser_lock);
389                                         } else 
390                                                 ast_log(LOG_ERROR,"Error! ABR target bitrate must be >= 0\n");
391                                 } else if (!strcasecmp(var->name, "vad")) {
392                                         ast_mutex_lock(&localuser_lock);
393                                         vad = ast_true(var->value) ? 1 : 0;
394                                         if (option_verbose > 2)
395                                                 ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: VAD Mode. [%s]\n",vbr ? "on" : "off");
396                                         ast_mutex_unlock(&localuser_lock);
397                                 } else if (!strcasecmp(var->name, "dtx")) {
398                                         ast_mutex_lock(&localuser_lock);
399                                         dtx = ast_true(var->value) ? 1 : 0;
400                                         if (option_verbose > 2)
401                                                 ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: DTX Mode. [%s]\n",dtx ? "on" : "off");
402                                         ast_mutex_unlock(&localuser_lock);
403                                 }
404                                 var = var->next;
405                         }
406                 }
407                 ast_config_destroy(cfg);
408         }
409 }
410
411 int reload(void) 
412 {
413         parse_config();
414         return 0;
415 }
416
417 int unload_module(void)
418 {
419         int res;
420         ast_mutex_lock(&localuser_lock);
421         res = ast_unregister_translator(&lintospeex);
422         if (!res)
423                 res = ast_unregister_translator(&speextolin);
424         if (localusecnt)
425                 res = -1;
426         ast_mutex_unlock(&localuser_lock);
427         return res;
428 }
429
430 int load_module(void)
431 {
432         int res;
433         parse_config();
434         res=ast_register_translator(&speextolin);
435         if (!res) 
436                 res=ast_register_translator(&lintospeex);
437         else
438                 ast_unregister_translator(&speextolin);
439         return res;
440 }
441
442 char *description(void)
443 {
444         return tdesc;
445 }
446
447 int usecount(void)
448 {
449         int res;
450         STANDARD_USECOUNT(res);
451         return res;
452 }
453
454 char *key()
455 {
456         return ASTERISK_GPL_KEY;
457 }