2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2005, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
9 * See http://www.asterisk.org for more information about
10 * the Asterisk project. Please do not directly contact
11 * any of the maintainers of this project for assistance;
12 * the project provides a web site, mailing lists and IRC
13 * channels for your use.
15 * This program is free software, distributed under the terms of
16 * the GNU General Public License Version 2. See the LICENSE file
17 * at the top of the source tree.
22 * \brief Translate between signed linear and Speex (Open Codec)
24 * http://www.speex.org
25 * \note This work was motivated by Jeremy McNamara
26 * hacked to be configurable by anthm and bkw 9/28/2004
33 #include <netinet/in.h>
38 /* We require a post 1.1.8 version of Speex to enable preprocessing
39 and better type handling */
41 #include <speex/speex_preprocess.h>
44 static int quality = 3;
45 static int complexity = 2;
46 static int enhancement = 0;
49 static float vbr_quality = 4;
53 static int preproc = 0;
54 static int pp_vad = 0;
55 static int pp_agc = 0;
56 static float pp_agc_level = 8000;
57 static int pp_denoise = 0;
58 static int pp_dereverb = 0;
59 static float pp_dereverb_decay = 0.4;
60 static float pp_dereverb_level = 0.3;
62 #define TYPE_SILENCE 0x2
69 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
71 #include "asterisk/lock.h"
72 #include "asterisk/translate.h"
73 #include "asterisk/module.h"
74 #include "asterisk/config.h"
75 #include "asterisk/options.h"
76 #include "asterisk/logger.h"
77 #include "asterisk/channel.h"
79 /* Sample frame data */
80 #include "slin_speex_ex.h"
81 #include "speex_slin_ex.h"
83 AST_MUTEX_DEFINE_STATIC(localuser_lock);
84 static int localusecnt=0;
86 static char *tdesc = "Speex/PCM16 (signed linear) Codec Translator";
88 struct ast_translator_pvt {
93 /* Space to build offset */
94 char offset[AST_FRIENDLY_OFFSET];
96 SpeexPreprocessState *pp;
97 /* Buffer for our outgoing frame */
98 spx_int16_t outbuf[8000];
99 /* Enough to store a full second */
100 spx_int16_t buf[8000];
110 #define speex_coder_pvt ast_translator_pvt
112 static struct ast_translator_pvt *lintospeex_new(void)
114 struct speex_coder_pvt *tmp;
115 tmp = malloc(sizeof(struct speex_coder_pvt));
117 if (!(tmp->speex = speex_encoder_init(&speex_nb_mode))) {
121 speex_bits_init(&tmp->bits);
122 speex_bits_reset(&tmp->bits);
123 speex_encoder_ctl(tmp->speex, SPEEX_GET_FRAME_SIZE, &tmp->framesize);
124 speex_encoder_ctl(tmp->speex, SPEEX_SET_COMPLEXITY, &complexity);
125 #ifdef _SPEEX_TYPES_H
127 tmp->pp = speex_preprocess_state_init(tmp->framesize, 8000);
128 speex_preprocess_ctl(tmp->pp, SPEEX_PREPROCESS_SET_VAD, &pp_vad);
129 speex_preprocess_ctl(tmp->pp, SPEEX_PREPROCESS_SET_AGC, &pp_agc);
130 speex_preprocess_ctl(tmp->pp, SPEEX_PREPROCESS_SET_AGC_LEVEL, &pp_agc_level);
131 speex_preprocess_ctl(tmp->pp, SPEEX_PREPROCESS_SET_DENOISE, &pp_denoise);
132 speex_preprocess_ctl(tmp->pp, SPEEX_PREPROCESS_SET_DEREVERB, &pp_dereverb);
133 speex_preprocess_ctl(tmp->pp, SPEEX_PREPROCESS_SET_DEREVERB_DECAY, &pp_dereverb_decay);
134 speex_preprocess_ctl(tmp->pp, SPEEX_PREPROCESS_SET_DEREVERB_LEVEL, &pp_dereverb_level);
138 speex_encoder_ctl(tmp->speex, SPEEX_SET_QUALITY, &quality);
140 speex_encoder_ctl(tmp->speex, SPEEX_SET_VAD, &vad);
143 speex_encoder_ctl(tmp->speex, SPEEX_SET_VBR, &vbr);
144 speex_encoder_ctl(tmp->speex, SPEEX_SET_VBR_QUALITY, &vbr_quality);
147 speex_encoder_ctl(tmp->speex, SPEEX_SET_ABR, &abr);
150 speex_encoder_ctl(tmp->speex, SPEEX_SET_DTX, &dtx);
152 tmp->silent_state = 0;
159 static struct ast_translator_pvt *speextolin_new(void)
161 struct speex_coder_pvt *tmp;
162 tmp = malloc(sizeof(struct speex_coder_pvt));
164 if (!(tmp->speex = speex_decoder_init(&speex_nb_mode))) {
168 speex_bits_init(&tmp->bits);
169 speex_decoder_ctl(tmp->speex, SPEEX_GET_FRAME_SIZE, &tmp->framesize);
171 speex_decoder_ctl(tmp->speex, SPEEX_SET_ENH, &enhancement);
179 static struct ast_frame *lintospeex_sample(void)
181 static struct ast_frame f;
182 f.frametype = AST_FRAME_VOICE;
183 f.subclass = AST_FORMAT_SLINEAR;
184 f.datalen = sizeof(slin_speex_ex);
186 f.samples = sizeof(slin_speex_ex)/2;
189 f.src = __PRETTY_FUNCTION__;
190 f.data = slin_speex_ex;
194 static struct ast_frame *speextolin_sample(void)
196 static struct ast_frame f;
197 f.frametype = AST_FRAME_VOICE;
198 f.subclass = AST_FORMAT_SPEEX;
199 f.datalen = sizeof(speex_slin_ex);
200 /* All frames are 20 ms long */
204 f.src = __PRETTY_FUNCTION__;
205 f.data = speex_slin_ex;
209 static struct ast_frame *speextolin_frameout(struct ast_translator_pvt *tmp)
213 /* Signed linear is no particular frame size, so just send whatever
214 we have in the buffer in one lump sum */
215 tmp->f.frametype = AST_FRAME_VOICE;
216 tmp->f.subclass = AST_FORMAT_SLINEAR;
217 tmp->f.datalen = tmp->tail * 2;
219 tmp->f.samples = tmp->tail;
221 tmp->f.offset = AST_FRIENDLY_OFFSET;
222 tmp->f.src = __PRETTY_FUNCTION__;
223 tmp->f.data = tmp->buf;
224 /* Reset tail pointer */
229 static int speextolin_framein(struct ast_translator_pvt *tmp, struct ast_frame *f)
231 /* Assuming there's space left, decode into the current buffer at
232 the tail location. Read in as many frames as there are */
235 #ifdef _SPEEX_TYPES_H
236 spx_int16_t out[1024];
241 if (f->datalen == 0) { /* Native PLC interpolation */
242 if (tmp->tail + tmp->framesize > sizeof(tmp->buf) / 2) {
243 ast_log(LOG_WARNING, "Out of buffer space\n");
246 #ifdef _SPEEX_TYPES_H
247 speex_decode_int(tmp->speex, NULL, tmp->buf + tmp->tail);
249 speex_decode(tmp->speex, NULL, fout);
250 for (x=0;x<tmp->framesize;x++) {
251 tmp->buf[tmp->tail + x] = fout[x];
254 tmp->tail += tmp->framesize;
259 speex_bits_read_from(&tmp->bits, f->data, f->datalen);
261 #ifdef _SPEEX_TYPES_H
262 res = speex_decode_int(tmp->speex, &tmp->bits, out);
264 res = speex_decode(tmp->speex, &tmp->bits, fout);
268 if (tmp->tail + tmp->framesize < sizeof(tmp->buf) / 2) {
269 for (x=0;x<tmp->framesize;x++) {
270 #ifdef _SPEEX_TYPES_H
271 tmp->buf[tmp->tail + x] = out[x];
273 tmp->buf[tmp->tail + x] = fout[x];
276 tmp->tail += tmp->framesize;
278 ast_log(LOG_WARNING, "Out of buffer space\n");
286 static int lintospeex_framein(struct ast_translator_pvt *tmp, struct ast_frame *f)
288 /* Just add the frames to our stream */
289 /* XXX We should look at how old the rest of our stream is, and if it
290 is too old, then we should overwrite it entirely, otherwise we can
291 get artifacts of earlier talk that do not belong */
292 if (tmp->tail + f->datalen/2 < sizeof(tmp->buf) / 2) {
293 memcpy((tmp->buf + tmp->tail), f->data, f->datalen);
294 tmp->tail += f->datalen/2;
296 ast_log(LOG_WARNING, "Out of buffer space\n");
302 static struct ast_frame *lintospeex_frameout(struct ast_translator_pvt *tmp)
304 #ifndef _SPEEX_TYPES_H
311 /* We can't work on anything less than a frame in size */
312 if (tmp->tail < tmp->framesize)
314 tmp->f.frametype = AST_FRAME_VOICE;
315 tmp->f.subclass = AST_FORMAT_SPEEX;
317 tmp->f.offset = AST_FRIENDLY_OFFSET;
318 tmp->f.src = __PRETTY_FUNCTION__;
319 tmp->f.data = tmp->outbuf;
320 speex_bits_reset(&tmp->bits);
321 while(tmp->tail >= tmp->framesize) {
322 #ifdef _SPEEX_TYPES_H
323 /* Preprocess audio */
325 is_speech = speex_preprocess(tmp->pp, tmp->buf, NULL);
326 /* Encode a frame of data */
328 /* If DTX enabled speex_encode returns 0 during silence */
329 is_speech = speex_encode_int(tmp->speex, tmp->buf, &tmp->bits) || !dtx;
331 /* 5 zeros interpreted by Speex as silence (submode 0) */
332 speex_bits_pack(&tmp->bits, 0, 5);
335 /* Convert to floating point */
336 for (x=0;x<tmp->framesize;x++)
337 fbuf[x] = tmp->buf[x];
338 /* Encode a frame of data */
339 is_speech = speex_encode(tmp->speex, fbuf, &tmp->bits) || !dtx;
341 /* Assume 8000 Hz -- 20 ms */
342 tmp->tail -= tmp->framesize;
343 /* Move the data at the end of the buffer to the front */
345 memmove(tmp->buf, tmp->buf + tmp->framesize, tmp->tail * 2);
349 /* Use AST_FRAME_CNG to signify the start of any silence period */
351 if (tmp->silent_state) {
354 tmp->silent_state = 1;
355 speex_bits_reset(&tmp->bits);
356 tmp->f.frametype = AST_FRAME_CNG;
359 tmp->silent_state = 0;
362 /* Terminate bit stream */
363 speex_bits_pack(&tmp->bits, 15, 5);
364 len = speex_bits_write(&tmp->bits, (char *)tmp->outbuf, sizeof(tmp->outbuf));
365 tmp->f.datalen = len;
366 tmp->f.samples = y * 160;
371 fd = open("speex.raw", O_WRONLY|O_TRUNC|O_CREAT);
373 write(fd, tmp->f.data, tmp->f.datalen);
382 static void speextolin_destroy(struct ast_translator_pvt *pvt)
384 speex_decoder_destroy(pvt->speex);
385 speex_bits_destroy(&pvt->bits);
390 static void lintospeex_destroy(struct ast_translator_pvt *pvt)
392 #ifdef _SPEEX_TYPES_H
394 speex_preprocess_state_destroy(pvt->pp);
396 speex_encoder_destroy(pvt->speex);
397 speex_bits_destroy(&pvt->bits);
402 static struct ast_translator speextolin =
404 AST_FORMAT_SPEEX, AST_FORMAT_SLINEAR,
412 static struct ast_translator lintospeex =
414 AST_FORMAT_SLINEAR, AST_FORMAT_SPEEX,
423 static void parse_config(void)
425 struct ast_config *cfg;
426 struct ast_variable *var;
430 if ((cfg = ast_config_load("codecs.conf"))) {
431 if ((var = ast_variable_browse(cfg, "speex"))) {
433 if (!strcasecmp(var->name, "quality")) {
434 res = abs(atoi(var->value));
435 if (res > -1 && res < 11) {
436 if (option_verbose > 2)
437 ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Setting Quality to %d\n",res);
438 ast_mutex_lock(&localuser_lock);
440 ast_mutex_unlock(&localuser_lock);
442 ast_log(LOG_ERROR,"Error Quality must be 0-10\n");
443 } else if (!strcasecmp(var->name, "complexity")) {
444 res = abs(atoi(var->value));
445 if (res > -1 && res < 11) {
446 if (option_verbose > 2)
447 ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Setting Complexity to %d\n",res);
448 ast_mutex_lock(&localuser_lock);
450 ast_mutex_unlock(&localuser_lock);
452 ast_log(LOG_ERROR,"Error! Complexity must be 0-10\n");
453 } else if (!strcasecmp(var->name, "vbr_quality")) {
454 if (sscanf(var->value, "%f", &res_f) == 1 && res_f >= 0 && res_f <= 10) {
455 if (option_verbose > 2)
456 ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Setting VBR Quality to %f\n",res_f);
457 ast_mutex_lock(&localuser_lock);
459 ast_mutex_unlock(&localuser_lock);
461 ast_log(LOG_ERROR,"Error! VBR Quality must be 0-10\n");
462 } else if (!strcasecmp(var->name, "abr_quality")) {
463 ast_log(LOG_ERROR,"Error! ABR Quality setting obsolete, set ABR to desired bitrate\n");
464 } else if (!strcasecmp(var->name, "enhancement")) {
465 ast_mutex_lock(&localuser_lock);
466 enhancement = ast_true(var->value) ? 1 : 0;
467 if (option_verbose > 2)
468 ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Perceptual Enhancement Mode. [%s]\n",enhancement ? "on" : "off");
469 ast_mutex_unlock(&localuser_lock);
470 } else if (!strcasecmp(var->name, "vbr")) {
471 ast_mutex_lock(&localuser_lock);
472 vbr = ast_true(var->value) ? 1 : 0;
473 if (option_verbose > 2)
474 ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: VBR Mode. [%s]\n",vbr ? "on" : "off");
475 ast_mutex_unlock(&localuser_lock);
476 } else if (!strcasecmp(var->name, "abr")) {
477 res = abs(atoi(var->value));
479 if (option_verbose > 2) {
481 ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Setting ABR target bitrate to %d\n",res);
483 ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Disabling ABR\n");
485 ast_mutex_lock(&localuser_lock);
487 ast_mutex_unlock(&localuser_lock);
489 ast_log(LOG_ERROR,"Error! ABR target bitrate must be >= 0\n");
490 } else if (!strcasecmp(var->name, "vad")) {
491 ast_mutex_lock(&localuser_lock);
492 vad = ast_true(var->value) ? 1 : 0;
493 if (option_verbose > 2)
494 ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: VAD Mode. [%s]\n",vad ? "on" : "off");
495 ast_mutex_unlock(&localuser_lock);
496 } else if (!strcasecmp(var->name, "dtx")) {
497 ast_mutex_lock(&localuser_lock);
498 dtx = ast_true(var->value) ? 1 : 0;
499 if (option_verbose > 2)
500 ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: DTX Mode. [%s]\n",dtx ? "on" : "off");
501 ast_mutex_unlock(&localuser_lock);
502 } else if (!strcasecmp(var->name, "preprocess")) {
503 ast_mutex_lock(&localuser_lock);
504 preproc = ast_true(var->value) ? 1 : 0;
505 if (option_verbose > 2)
506 ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Preprocessing. [%s]\n",preproc ? "on" : "off");
507 ast_mutex_unlock(&localuser_lock);
508 } else if (!strcasecmp(var->name, "pp_vad")) {
509 ast_mutex_lock(&localuser_lock);
510 pp_vad = ast_true(var->value) ? 1 : 0;
511 if (option_verbose > 2)
512 ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Preprocessor VAD. [%s]\n",pp_vad ? "on" : "off");
513 ast_mutex_unlock(&localuser_lock);
514 } else if (!strcasecmp(var->name, "pp_agc")) {
515 ast_mutex_lock(&localuser_lock);
516 pp_agc = ast_true(var->value) ? 1 : 0;
517 if (option_verbose > 2)
518 ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Preprocessor AGC. [%s]\n",pp_agc ? "on" : "off");
519 ast_mutex_unlock(&localuser_lock);
520 } else if (!strcasecmp(var->name, "pp_agc_level")) {
521 if (sscanf(var->value, "%f", &res_f) == 1 && res_f >= 0) {
522 if (option_verbose > 2)
523 ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Setting preprocessor AGC Level to %f\n",res_f);
524 ast_mutex_lock(&localuser_lock);
525 pp_agc_level = res_f;
526 ast_mutex_unlock(&localuser_lock);
528 ast_log(LOG_ERROR,"Error! Preprocessor AGC Level must be >= 0\n");
529 } else if (!strcasecmp(var->name, "pp_denoise")) {
530 ast_mutex_lock(&localuser_lock);
531 pp_denoise = ast_true(var->value) ? 1 : 0;
532 if (option_verbose > 2)
533 ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Preprocessor Denoise. [%s]\n",pp_denoise ? "on" : "off");
534 ast_mutex_unlock(&localuser_lock);
535 } else if (!strcasecmp(var->name, "pp_dereverb")) {
536 ast_mutex_lock(&localuser_lock);
537 pp_dereverb = ast_true(var->value) ? 1 : 0;
538 if (option_verbose > 2)
539 ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Preprocessor Dereverb. [%s]\n",pp_dereverb ? "on" : "off");
540 ast_mutex_unlock(&localuser_lock);
541 } else if (!strcasecmp(var->name, "pp_dereverb_decay")) {
542 if (sscanf(var->value, "%f", &res_f) == 1 && res_f >= 0) {
543 if (option_verbose > 2)
544 ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Setting preprocessor Dereverb Decay to %f\n",res_f);
545 ast_mutex_lock(&localuser_lock);
546 pp_dereverb_decay = res_f;
547 ast_mutex_unlock(&localuser_lock);
549 ast_log(LOG_ERROR,"Error! Preprocessor Dereverb Decay must be >= 0\n");
550 } else if (!strcasecmp(var->name, "pp_dereverb_level")) {
551 if (sscanf(var->value, "%f", &res_f) == 1 && res_f >= 0) {
552 if (option_verbose > 2)
553 ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Setting preprocessor Dereverb Level to %f\n",res_f);
554 ast_mutex_lock(&localuser_lock);
555 pp_dereverb_level = res_f;
556 ast_mutex_unlock(&localuser_lock);
558 ast_log(LOG_ERROR,"Error! Preprocessor Dereverb Level must be >= 0\n");
563 ast_config_destroy(cfg);
573 int unload_module(void)
576 ast_mutex_lock(&localuser_lock);
577 res = ast_unregister_translator(&lintospeex);
579 res = ast_unregister_translator(&speextolin);
582 ast_mutex_unlock(&localuser_lock);
586 int load_module(void)
590 res=ast_register_translator(&speextolin);
592 res=ast_register_translator(&lintospeex);
594 ast_unregister_translator(&speextolin);
598 char *description(void)
606 STANDARD_USECOUNT(res);
612 return ASTERISK_GPL_KEY;