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>
45 static int quality = 3;
46 static int complexity = 2;
47 static int enhancement = 0;
50 static float vbr_quality = 4;
52 static int dtx = 0; /* set to 1 to enable silence detection */
54 static int preproc = 0;
55 static int pp_vad = 0;
56 static int pp_agc = 0;
57 static float pp_agc_level = 8000; /* XXX what is this 8000 ? */
58 static int pp_denoise = 0;
59 static int pp_dereverb = 0;
60 static float pp_dereverb_decay = 0.4;
61 static float pp_dereverb_level = 0.3;
63 #define TYPE_SILENCE 0x2
70 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
72 #include "asterisk/lock.h"
73 #include "asterisk/translate.h"
74 #include "asterisk/module.h"
75 #include "asterisk/config.h"
76 #include "asterisk/options.h"
77 #include "asterisk/logger.h"
78 #include "asterisk/channel.h"
79 #include "asterisk/utils.h"
81 /* Sample frame data */
82 #include "slin_speex_ex.h"
83 #include "speex_slin_ex.h"
85 #define BUFFER_SAMPLES 8000
86 #define SPEEX_SAMPLES 160
88 struct speex_coder_pvt {
94 SpeexPreprocessState *pp;
95 spx_int16_t buf[BUFFER_SAMPLES];
97 int16_t buf[BUFFER_SAMPLES]; /* input, waiting to be compressed */
102 static void *lintospeex_new(struct ast_trans_pvt *pvt)
104 struct speex_coder_pvt *tmp = pvt->pvt;
106 if (!(tmp->speex = speex_encoder_init(&speex_nb_mode)))
109 speex_bits_init(&tmp->bits);
110 speex_bits_reset(&tmp->bits);
111 speex_encoder_ctl(tmp->speex, SPEEX_GET_FRAME_SIZE, &tmp->framesize);
112 ast_log(LOG_WARNING, "speex framesize is %d\n", tmp->framesize);
113 speex_encoder_ctl(tmp->speex, SPEEX_SET_COMPLEXITY, &complexity);
114 #ifdef _SPEEX_TYPES_H
116 tmp->pp = speex_preprocess_state_init(tmp->framesize, 8000); /* XXX what is this 8000 ? */
117 speex_preprocess_ctl(tmp->pp, SPEEX_PREPROCESS_SET_VAD, &pp_vad);
118 speex_preprocess_ctl(tmp->pp, SPEEX_PREPROCESS_SET_AGC, &pp_agc);
119 speex_preprocess_ctl(tmp->pp, SPEEX_PREPROCESS_SET_AGC_LEVEL, &pp_agc_level);
120 speex_preprocess_ctl(tmp->pp, SPEEX_PREPROCESS_SET_DENOISE, &pp_denoise);
121 speex_preprocess_ctl(tmp->pp, SPEEX_PREPROCESS_SET_DEREVERB, &pp_dereverb);
122 speex_preprocess_ctl(tmp->pp, SPEEX_PREPROCESS_SET_DEREVERB_DECAY, &pp_dereverb_decay);
123 speex_preprocess_ctl(tmp->pp, SPEEX_PREPROCESS_SET_DEREVERB_LEVEL, &pp_dereverb_level);
127 speex_encoder_ctl(tmp->speex, SPEEX_SET_QUALITY, &quality);
129 speex_encoder_ctl(tmp->speex, SPEEX_SET_VAD, &vad);
132 speex_encoder_ctl(tmp->speex, SPEEX_SET_VBR, &vbr);
133 speex_encoder_ctl(tmp->speex, SPEEX_SET_VBR_QUALITY, &vbr_quality);
136 speex_encoder_ctl(tmp->speex, SPEEX_SET_ABR, &abr);
138 speex_encoder_ctl(tmp->speex, SPEEX_SET_DTX, &dtx);
139 tmp->silent_state = 0;
144 static void *speextolin_new(struct ast_trans_pvt *pvt)
146 struct speex_coder_pvt *tmp = pvt->pvt;
148 if (!(tmp->speex = speex_decoder_init(&speex_nb_mode)))
150 speex_bits_init(&tmp->bits);
151 speex_decoder_ctl(tmp->speex, SPEEX_GET_FRAME_SIZE, &tmp->framesize);
153 speex_decoder_ctl(tmp->speex, SPEEX_SET_ENH, &enhancement);
157 static struct ast_frame *lintospeex_sample(void)
159 static struct ast_frame f;
160 f.frametype = AST_FRAME_VOICE;
161 f.subclass = AST_FORMAT_SLINEAR;
162 f.datalen = sizeof(slin_speex_ex);
164 f.samples = sizeof(slin_speex_ex)/2;
167 f.src = __PRETTY_FUNCTION__;
168 f.data = slin_speex_ex;
172 static struct ast_frame *speextolin_sample(void)
174 static struct ast_frame f;
175 f.frametype = AST_FRAME_VOICE;
176 f.subclass = AST_FORMAT_SPEEX;
177 f.datalen = sizeof(speex_slin_ex);
178 /* All frames are 20 ms long */
179 f.samples = SPEEX_SAMPLES;
182 f.src = __PRETTY_FUNCTION__;
183 f.data = speex_slin_ex;
187 /*! \brief convert and store into outbuf */
188 static int speextolin_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
190 struct speex_coder_pvt *tmp = pvt->pvt;
192 /* Assuming there's space left, decode into the current buffer at
193 the tail location. Read in as many frames as there are */
196 int16_t *dst = (int16_t *)pvt->outbuf;
197 /* XXX fout is a temporary buffer, may have different types */
198 #ifdef _SPEEX_TYPES_H
199 spx_int16_t fout[1024];
204 if (f->datalen == 0) { /* Native PLC interpolation */
205 if (pvt->samples + tmp->framesize > BUFFER_SAMPLES) {
206 ast_log(LOG_WARNING, "Out of buffer space\n");
209 #ifdef _SPEEX_TYPES_H
210 speex_decode_int(tmp->speex, NULL, dst + pvt->samples);
212 speex_decode(tmp->speex, NULL, fout);
213 for (x=0;x<tmp->framesize;x++) {
214 dst[pvt->samples + x] = (int16_t)fout[x];
217 pvt->samples += tmp->framesize;
222 speex_bits_read_from(&tmp->bits, f->data, f->datalen);
224 #ifdef _SPEEX_TYPES_H
225 res = speex_decode_int(tmp->speex, &tmp->bits, fout);
227 res = speex_decode(tmp->speex, &tmp->bits, fout);
231 if (pvt->samples + tmp->framesize > BUFFER_SAMPLES) {
232 ast_log(LOG_WARNING, "Out of buffer space\n");
235 for (x = 0 ; x < tmp->framesize; x++)
236 dst[pvt->samples + x] = (int16_t)fout[x];
237 pvt->samples += tmp->framesize;
238 pvt->datalen += 2 * tmp->framesize; /* 2 bytes/sample */
243 /*! \brief store input frame in work buffer */
244 static int lintospeex_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
246 struct speex_coder_pvt *tmp = pvt->pvt;
248 /* XXX We should look at how old the rest of our stream is, and if it
249 is too old, then we should overwrite it entirely, otherwise we can
250 get artifacts of earlier talk that do not belong */
251 memcpy(tmp->buf + pvt->samples, f->data, f->datalen);
252 pvt->samples += f->samples;
256 /*! \brief convert work buffer and produce output frame */
257 static struct ast_frame *lintospeex_frameout(struct ast_trans_pvt *pvt)
259 struct speex_coder_pvt *tmp = pvt->pvt;
261 int datalen = 0; /* output bytes */
262 int samples = 0; /* output samples */
264 /* We can't work on anything less than a frame in size */
265 if (pvt->samples < tmp->framesize)
267 speex_bits_reset(&tmp->bits);
268 while (pvt->samples >= tmp->framesize) {
269 #ifdef _SPEEX_TYPES_H
270 /* Preprocess audio */
272 is_speech = speex_preprocess(tmp->pp, tmp->buf, NULL);
273 /* Encode a frame of data */
275 /* If DTX enabled speex_encode returns 0 during silence */
276 is_speech = speex_encode_int(tmp->speex, tmp->buf, &tmp->bits) || !dtx;
278 /* 5 zeros interpreted by Speex as silence (submode 0) */
279 speex_bits_pack(&tmp->bits, 0, 5);
285 /* Convert to floating point */
286 for (x = 0; x < tmp->framesize; x++)
287 fbuf[x] = tmp->buf[x];
288 /* Encode a frame of data */
289 is_speech = speex_encode(tmp->speex, fbuf, &tmp->bits) || !dtx;
292 samples += tmp->framesize;
293 pvt->samples -= tmp->framesize;
294 /* Move the data at the end of the buffer to the front */
296 memmove(tmp->buf, tmp->buf + tmp->framesize, pvt->samples * 2);
299 /* Use AST_FRAME_CNG to signify the start of any silence period */
301 tmp->silent_state = 0;
303 if (tmp->silent_state) {
306 tmp->silent_state = 1;
307 speex_bits_reset(&tmp->bits);
308 memset(&pvt->f, 0, sizeof(pvt->f));
309 pvt->f.frametype = AST_FRAME_CNG;
310 pvt->f.samples = samples;
311 /* XXX what now ? format etc... */
315 /* Terminate bit stream */
316 speex_bits_pack(&tmp->bits, 15, 5);
317 datalen = speex_bits_write(&tmp->bits, pvt->outbuf, pvt->t->buf_size);
318 return ast_trans_frameout(pvt, datalen, samples);
321 static void speextolin_destroy(struct ast_trans_pvt *arg)
323 struct speex_coder_pvt *pvt = arg->pvt;
325 speex_decoder_destroy(pvt->speex);
326 speex_bits_destroy(&pvt->bits);
329 static void lintospeex_destroy(struct ast_trans_pvt *arg)
331 struct speex_coder_pvt *pvt = arg->pvt;
332 #ifdef _SPEEX_TYPES_H
334 speex_preprocess_state_destroy(pvt->pp);
336 speex_encoder_destroy(pvt->speex);
337 speex_bits_destroy(&pvt->bits);
340 static struct ast_translator speextolin = {
341 .name = "speextolin",
342 .srcfmt = AST_FORMAT_SPEEX,
343 .dstfmt = AST_FORMAT_SLINEAR,
344 .newpvt = speextolin_new,
345 .framein = speextolin_framein,
346 .destroy = speextolin_destroy,
347 .sample = speextolin_sample,
348 .desc_size = sizeof(struct speex_coder_pvt),
349 .buffer_samples = BUFFER_SAMPLES,
350 .buf_size = BUFFER_SAMPLES * 2,
353 static struct ast_translator lintospeex = {
354 .name = "lintospeex",
355 .srcfmt = AST_FORMAT_SLINEAR,
356 .dstfmt = AST_FORMAT_SPEEX,
357 .newpvt = lintospeex_new,
358 .framein = lintospeex_framein,
359 .frameout = lintospeex_frameout,
360 .destroy = lintospeex_destroy,
361 .sample = lintospeex_sample,
362 .desc_size = sizeof(struct speex_coder_pvt),
363 .buffer_samples = BUFFER_SAMPLES,
364 .buf_size = BUFFER_SAMPLES * 2, /* XXX maybe a lot less ? */
367 static void parse_config(void)
369 struct ast_config *cfg = ast_config_load("codecs.conf");
370 struct ast_variable *var;
377 for (var = ast_variable_browse(cfg, "speex"); var; var = var->next) {
378 if (!strcasecmp(var->name, "quality")) {
379 res = abs(atoi(var->value));
380 if (res > -1 && res < 11) {
381 if (option_verbose > 2)
382 ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Setting Quality to %d\n",res);
385 ast_log(LOG_ERROR,"Error Quality must be 0-10\n");
386 } else if (!strcasecmp(var->name, "complexity")) {
387 res = abs(atoi(var->value));
388 if (res > -1 && res < 11) {
389 if (option_verbose > 2)
390 ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Setting Complexity to %d\n",res);
393 ast_log(LOG_ERROR,"Error! Complexity must be 0-10\n");
394 } else if (!strcasecmp(var->name, "vbr_quality")) {
395 if (sscanf(var->value, "%f", &res_f) == 1 && res_f >= 0 && res_f <= 10) {
396 if (option_verbose > 2)
397 ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Setting VBR Quality to %f\n",res_f);
400 ast_log(LOG_ERROR,"Error! VBR Quality must be 0-10\n");
401 } else if (!strcasecmp(var->name, "abr_quality")) {
402 ast_log(LOG_ERROR,"Error! ABR Quality setting obsolete, set ABR to desired bitrate\n");
403 } else if (!strcasecmp(var->name, "enhancement")) {
404 enhancement = ast_true(var->value) ? 1 : 0;
405 if (option_verbose > 2)
406 ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Perceptual Enhancement Mode. [%s]\n",enhancement ? "on" : "off");
407 } else if (!strcasecmp(var->name, "vbr")) {
408 vbr = ast_true(var->value) ? 1 : 0;
409 if (option_verbose > 2)
410 ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: VBR Mode. [%s]\n",vbr ? "on" : "off");
411 } else if (!strcasecmp(var->name, "abr")) {
412 res = abs(atoi(var->value));
414 if (option_verbose > 2) {
416 ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Setting ABR target bitrate to %d\n",res);
418 ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Disabling ABR\n");
422 ast_log(LOG_ERROR,"Error! ABR target bitrate must be >= 0\n");
423 } else if (!strcasecmp(var->name, "vad")) {
424 vad = ast_true(var->value) ? 1 : 0;
425 if (option_verbose > 2)
426 ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: VAD Mode. [%s]\n",vad ? "on" : "off");
427 } else if (!strcasecmp(var->name, "dtx")) {
428 dtx = ast_true(var->value) ? 1 : 0;
429 if (option_verbose > 2)
430 ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: DTX Mode. [%s]\n",dtx ? "on" : "off");
431 } else if (!strcasecmp(var->name, "preprocess")) {
432 preproc = ast_true(var->value) ? 1 : 0;
433 if (option_verbose > 2)
434 ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Preprocessing. [%s]\n",preproc ? "on" : "off");
435 } else if (!strcasecmp(var->name, "pp_vad")) {
436 pp_vad = ast_true(var->value) ? 1 : 0;
437 if (option_verbose > 2)
438 ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Preprocessor VAD. [%s]\n",pp_vad ? "on" : "off");
439 } else if (!strcasecmp(var->name, "pp_agc")) {
440 pp_agc = ast_true(var->value) ? 1 : 0;
441 if (option_verbose > 2)
442 ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Preprocessor AGC. [%s]\n",pp_agc ? "on" : "off");
443 } else if (!strcasecmp(var->name, "pp_agc_level")) {
444 if (sscanf(var->value, "%f", &res_f) == 1 && res_f >= 0) {
445 if (option_verbose > 2)
446 ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Setting preprocessor AGC Level to %f\n",res_f);
447 pp_agc_level = res_f;
449 ast_log(LOG_ERROR,"Error! Preprocessor AGC Level must be >= 0\n");
450 } else if (!strcasecmp(var->name, "pp_denoise")) {
451 pp_denoise = ast_true(var->value) ? 1 : 0;
452 if (option_verbose > 2)
453 ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Preprocessor Denoise. [%s]\n",pp_denoise ? "on" : "off");
454 } else if (!strcasecmp(var->name, "pp_dereverb")) {
455 pp_dereverb = ast_true(var->value) ? 1 : 0;
456 if (option_verbose > 2)
457 ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Preprocessor Dereverb. [%s]\n",pp_dereverb ? "on" : "off");
458 } else if (!strcasecmp(var->name, "pp_dereverb_decay")) {
459 if (sscanf(var->value, "%f", &res_f) == 1 && res_f >= 0) {
460 if (option_verbose > 2)
461 ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Setting preprocessor Dereverb Decay to %f\n",res_f);
462 pp_dereverb_decay = res_f;
464 ast_log(LOG_ERROR,"Error! Preprocessor Dereverb Decay must be >= 0\n");
465 } else if (!strcasecmp(var->name, "pp_dereverb_level")) {
466 if (sscanf(var->value, "%f", &res_f) == 1 && res_f >= 0) {
467 if (option_verbose > 2)
468 ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Setting preprocessor Dereverb Level to %f\n",res_f);
469 pp_dereverb_level = res_f;
471 ast_log(LOG_ERROR,"Error! Preprocessor Dereverb Level must be >= 0\n");
474 ast_config_destroy(cfg);
477 static int reload(void *mod)
480 * XXX reloading while there are active sessions is
481 * somewhat silly because the old state presumably
482 * wouldn't work anymore...
483 * maybe we shuld do a standard hangup localusers ?
485 ast_mutex_lock(&__mod_desc->lock);
487 ast_mutex_lock(&__mod_desc->lock);
491 static int unload_module(void *mod)
494 res = ast_unregister_translator(&lintospeex);
495 res |= ast_unregister_translator(&speextolin);
499 static int load_module(void *mod)
503 res=ast_register_translator(&speextolin, mod);
505 res=ast_register_translator(&lintospeex, mod);
507 ast_unregister_translator(&speextolin);
511 static const char *description(void)
513 return "Speex/PCM16 (signed linear) Codec Translator";
516 static const char *key(void)
518 return ASTERISK_GPL_KEY;
521 STD_MOD(MOD_1, reload, NULL, NULL);