42 #include <speex/speex.h>
48 #include <speex/speex_preprocess.h>
63 static int complexity = 2;
64 static int enhancement = 0;
67 static float vbr_quality = 4;
70 static int exp_rtcp_fb = 0;
72 static int preproc = 0;
73 static int pp_vad = 0;
74 static int pp_agc = 0;
75 static float pp_agc_level = 8000;
76 static int pp_denoise = 0;
77 static int pp_dereverb = 0;
78 static float pp_dereverb_decay = 0.4;
79 static float pp_dereverb_level = 0.3;
81 #define TYPE_SILENCE 0x2
86 #define BUFFER_SAMPLES 8000
87 #define SPEEX_SAMPLES 160
90 #include "asterisk/slin.h"
103 #ifdef _SPEEX_TYPES_H
104 SpeexPreprocessState *pp;
105 spx_int16_t buf[BUFFER_SAMPLES];
107 int16_t buf[BUFFER_SAMPLES];
111 static int speex_encoder_construct(
struct ast_trans_pvt *pvt,
const SpeexMode *profile,
int sampling_rate)
115 if (!(tmp->speex = speex_encoder_init(profile)))
118 speex_bits_init(&tmp->bits);
119 speex_bits_reset(&tmp->bits);
120 speex_encoder_ctl(tmp->speex, SPEEX_GET_FRAME_SIZE, &tmp->framesize);
121 speex_encoder_ctl(tmp->speex, SPEEX_SET_COMPLEXITY, &complexity);
122 #ifdef _SPEEX_TYPES_H
124 tmp->pp = speex_preprocess_state_init(tmp->framesize, sampling_rate);
125 speex_preprocess_ctl(tmp->pp, SPEEX_PREPROCESS_SET_VAD, &pp_vad);
126 speex_preprocess_ctl(tmp->pp, SPEEX_PREPROCESS_SET_AGC, &pp_agc);
127 speex_preprocess_ctl(tmp->pp, SPEEX_PREPROCESS_SET_AGC_LEVEL, &pp_agc_level);
128 speex_preprocess_ctl(tmp->pp, SPEEX_PREPROCESS_SET_DENOISE, &pp_denoise);
129 speex_preprocess_ctl(tmp->pp, SPEEX_PREPROCESS_SET_DEREVERB, &pp_dereverb);
130 speex_preprocess_ctl(tmp->pp, SPEEX_PREPROCESS_SET_DEREVERB_DECAY, &pp_dereverb_decay);
131 speex_preprocess_ctl(tmp->pp, SPEEX_PREPROCESS_SET_DEREVERB_LEVEL, &pp_dereverb_level);
135 speex_encoder_ctl(tmp->speex, SPEEX_SET_QUALITY, &quality);
137 speex_encoder_ctl(tmp->speex, SPEEX_SET_VAD, &vad);
140 speex_encoder_ctl(tmp->speex, SPEEX_SET_VBR, &vbr);
141 speex_encoder_ctl(tmp->speex, SPEEX_SET_VBR_QUALITY, &vbr_quality);
144 speex_encoder_ctl(tmp->speex, SPEEX_SET_ABR, &abr);
146 speex_encoder_ctl(tmp->speex, SPEEX_SET_DTX, &dtx);
147 tmp->silent_state = 0;
149 tmp->fraction_lost = 0;
150 tmp->default_quality = vbr ? vbr_quality : quality;
151 tmp->quality = tmp->default_quality;
152 ast_debug(3,
"Default quality (%s): %d\n", vbr ?
"vbr" :
"cbr", tmp->default_quality);
159 return speex_encoder_construct(pvt, &speex_nb_mode, 8000);
164 return speex_encoder_construct(pvt, &speex_wb_mode, 16000);
169 return speex_encoder_construct(pvt, &speex_uwb_mode, 32000);
172 static int speex_decoder_construct(
struct ast_trans_pvt *pvt,
const SpeexMode *profile)
176 if (!(tmp->speex = speex_decoder_init(profile)))
179 speex_bits_init(&tmp->bits);
180 speex_decoder_ctl(tmp->speex, SPEEX_GET_FRAME_SIZE, &tmp->framesize);
182 speex_decoder_ctl(tmp->speex, SPEEX_SET_ENH, &enhancement);
189 return speex_decoder_construct(pvt, &speex_nb_mode);
194 return speex_decoder_construct(pvt, &speex_wb_mode);
199 return speex_decoder_construct(pvt, &speex_uwb_mode);
211 int16_t *dst = pvt->outbuf.i16;
213 #ifdef _SPEEX_TYPES_H
214 spx_int16_t fout[1024];
220 if (pvt->
samples + tmp->framesize > BUFFER_SAMPLES) {
221 ast_log(LOG_WARNING,
"Out of buffer space\n");
224 #ifdef _SPEEX_TYPES_H
225 speex_decode_int(tmp->speex, NULL, dst + pvt->
samples);
227 speex_decode(tmp->speex, NULL, fout);
228 for (x=0;x<tmp->framesize;x++) {
229 dst[pvt->
samples + x] = (int16_t)fout[x];
232 pvt->
samples += tmp->framesize;
233 pvt->
datalen += 2 * tmp->framesize;
238 speex_bits_read_from(&tmp->bits, f->
data.ptr, f->
datalen);
240 #ifdef _SPEEX_TYPES_H
241 res = speex_decode_int(tmp->speex, &tmp->bits, fout);
243 res = speex_decode(tmp->speex, &tmp->bits, fout);
247 if (pvt->
samples + tmp->framesize > BUFFER_SAMPLES) {
248 ast_log(LOG_WARNING,
"Out of buffer space\n");
251 for (x = 0 ; x < tmp->framesize; x++)
252 dst[pvt->
samples + x] = (int16_t)fout[x];
253 pvt->
samples += tmp->framesize;
254 pvt->
datalen += 2 * tmp->framesize;
280 while (pvt->
samples >= tmp->framesize) {
284 speex_bits_reset(&tmp->bits);
286 #ifdef _SPEEX_TYPES_H
289 is_speech = speex_preprocess(tmp->pp, tmp->buf + samples, NULL);
293 is_speech = speex_encode_int(tmp->speex, tmp->buf + samples, &tmp->bits) || !dtx;
296 speex_bits_pack(&tmp->bits, 0, 5);
303 for (x = 0; x < tmp->framesize; x++)
304 fbuf[x] = tmp->buf[samples + x];
306 is_speech = speex_encode(tmp->speex, fbuf, &tmp->bits) || !dtx;
309 samples += tmp->framesize;
310 pvt->
samples -= tmp->framesize;
316 tmp->silent_state = 0;
318 speex_bits_pack(&tmp->bits, 15, 5);
319 datalen = speex_bits_write(&tmp->bits, pvt->outbuf.
c, pvt->t->
buf_size);
321 }
else if (tmp->silent_state) {
335 tmp->silent_state = 1;
353 memmove(tmp->buf, tmp->buf + samples, pvt->
samples * 2);
381 if (rtcp_report->reception_report_count == 0)
384 fraction_lost = report_block->lost_count.fraction;
385 if (fraction_lost == tmp->fraction_lost)
390 percent = (fraction_lost*100)/256;
393 ast_debug(3,
"Fraction lost changed: %d --> %d percent loss\n", fraction_lost, percent);
395 speex_encoder_ctl(tmp->speex, SPEEX_GET_BITRATE, &bitrate);
396 ast_debug(3,
"Current bitrate: %d\n", bitrate);
397 ast_debug(3,
"Current quality: %d/%d\n", tmp->quality, tmp->default_quality);
401 q = tmp->default_quality;
402 }
else if (percent < 20) {
404 q = tmp->default_quality-1;
405 }
else if (percent < 30) {
407 q = tmp->default_quality-2;
414 if (q != tmp->quality) {
418 speex_encoder_ctl(tmp->speex, SPEEX_SET_VBR_QUALITY, &vbr_q);
420 speex_encoder_ctl(tmp->speex, SPEEX_SET_QUALITY, &q);
424 tmp->fraction_lost = fraction_lost;
431 speex_decoder_destroy(pvt->speex);
432 speex_bits_destroy(&pvt->bits);
438 #ifdef _SPEEX_TYPES_H
440 speex_preprocess_state_destroy(pvt->pp);
442 speex_encoder_destroy(pvt->speex);
443 speex_bits_destroy(&pvt->bits);
447 .
name =
"speextolin",
450 .type = AST_MEDIA_TYPE_AUDIO,
455 .type = AST_MEDIA_TYPE_AUDIO,
459 .newpvt = speextolin_new,
461 .destroy = speextolin_destroy,
462 .sample = speex_sample,
464 .buffer_samples = BUFFER_SAMPLES,
465 .buf_size = BUFFER_SAMPLES * 2,
470 .
name =
"lintospeex",
473 .type = AST_MEDIA_TYPE_AUDIO,
478 .type = AST_MEDIA_TYPE_AUDIO,
482 .newpvt = lintospeex_new,
486 .destroy = lintospeex_destroy,
487 .sample = slin8_sample,
489 .buffer_samples = BUFFER_SAMPLES,
490 .buf_size = BUFFER_SAMPLES * 2,
494 .
name =
"speexwbtolin16",
497 .type = AST_MEDIA_TYPE_AUDIO,
498 .sample_rate = 16000,
502 .type = AST_MEDIA_TYPE_AUDIO,
503 .sample_rate = 16000,
506 .newpvt = speexwbtolin16_new,
508 .destroy = speextolin_destroy,
509 .sample = speex16_sample,
511 .buffer_samples = BUFFER_SAMPLES,
512 .buf_size = BUFFER_SAMPLES * 2,
517 .
name =
"lin16tospeexwb",
520 .type = AST_MEDIA_TYPE_AUDIO,
521 .sample_rate = 16000,
525 .type = AST_MEDIA_TYPE_AUDIO,
526 .sample_rate = 16000,
529 .newpvt = lin16tospeexwb_new,
533 .destroy = lintospeex_destroy,
534 .sample = slin16_sample,
536 .buffer_samples = BUFFER_SAMPLES,
537 .buf_size = BUFFER_SAMPLES * 2,
541 .
name =
"speexuwbtolin32",
544 .type = AST_MEDIA_TYPE_AUDIO,
545 .sample_rate = 32000,
549 .type = AST_MEDIA_TYPE_AUDIO,
550 .sample_rate = 32000,
553 .newpvt = speexuwbtolin32_new,
555 .destroy = speextolin_destroy,
557 .buffer_samples = BUFFER_SAMPLES,
558 .buf_size = BUFFER_SAMPLES * 2,
563 .
name =
"lin32tospeexuwb",
566 .type = AST_MEDIA_TYPE_AUDIO,
567 .sample_rate = 32000,
571 .type = AST_MEDIA_TYPE_AUDIO,
572 .sample_rate = 32000,
575 .newpvt = lin32tospeexuwb_new,
579 .destroy = lintospeex_destroy,
581 .buffer_samples = BUFFER_SAMPLES,
582 .buf_size = BUFFER_SAMPLES * 2,
585 static int parse_config(
int reload)
593 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID)
596 for (var = ast_variable_browse(cfg,
"speex"); var; var = var->
next) {
597 if (!strcasecmp(var->
name,
"quality")) {
598 res = abs(atoi(var->
value));
599 if (res > -1 && res < 11) {
600 ast_verb(5,
"CODEC SPEEX: Setting Quality to %d\n",res);
603 ast_log(LOG_ERROR,
"Error Quality must be 0-10\n");
604 }
else if (!strcasecmp(var->
name,
"complexity")) {
605 res = abs(atoi(var->
value));
606 if (res > -1 && res < 11) {
607 ast_verb(5,
"CODEC SPEEX: Setting Complexity to %d\n",res);
610 ast_log(LOG_ERROR,
"Error! Complexity must be 0-10\n");
611 }
else if (!strcasecmp(var->
name,
"vbr_quality")) {
612 if (sscanf(var->
value,
"%30f", &res_f) == 1 && res_f >= 0 && res_f <= 10) {
613 ast_verb(5,
"CODEC SPEEX: Setting VBR Quality to %f\n",res_f);
616 ast_log(LOG_ERROR,
"Error! VBR Quality must be 0-10\n");
617 }
else if (!strcasecmp(var->
name,
"abr_quality")) {
618 ast_log(LOG_ERROR,
"Error! ABR Quality setting obsolete, set ABR to desired bitrate\n");
619 }
else if (!strcasecmp(var->
name,
"enhancement")) {
621 ast_verb(5,
"CODEC SPEEX: Perceptual Enhancement Mode. [%s]\n",enhancement ?
"on" :
"off");
622 }
else if (!strcasecmp(var->
name,
"vbr")) {
624 ast_verb(5,
"CODEC SPEEX: VBR Mode. [%s]\n",vbr ?
"on" :
"off");
625 }
else if (!strcasecmp(var->
name,
"abr")) {
626 res = abs(atoi(var->
value));
629 ast_verb(5,
"CODEC SPEEX: Setting ABR target bitrate to %d\n",res);
631 ast_verb(5,
"CODEC SPEEX: Disabling ABR\n");
634 ast_log(LOG_ERROR,
"Error! ABR target bitrate must be >= 0\n");
635 }
else if (!strcasecmp(var->
name,
"vad")) {
637 ast_verb(5,
"CODEC SPEEX: VAD Mode. [%s]\n",vad ?
"on" :
"off");
638 }
else if (!strcasecmp(var->
name,
"dtx")) {
640 ast_verb(5,
"CODEC SPEEX: DTX Mode. [%s]\n",dtx ?
"on" :
"off");
641 }
else if (!strcasecmp(var->
name,
"preprocess")) {
643 ast_verb(5,
"CODEC SPEEX: Preprocessing. [%s]\n",preproc ?
"on" :
"off");
644 }
else if (!strcasecmp(var->
name,
"pp_vad")) {
646 ast_verb(5,
"CODEC SPEEX: Preprocessor VAD. [%s]\n",pp_vad ?
"on" :
"off");
647 }
else if (!strcasecmp(var->
name,
"pp_agc")) {
649 ast_verb(5,
"CODEC SPEEX: Preprocessor AGC. [%s]\n",pp_agc ?
"on" :
"off");
650 }
else if (!strcasecmp(var->
name,
"pp_agc_level")) {
651 if (sscanf(var->
value,
"%30f", &res_f) == 1 && res_f >= 0) {
652 ast_verb(5,
"CODEC SPEEX: Setting preprocessor AGC Level to %f\n",res_f);
653 pp_agc_level = res_f;
655 ast_log(LOG_ERROR,
"Error! Preprocessor AGC Level must be >= 0\n");
656 }
else if (!strcasecmp(var->
name,
"pp_denoise")) {
658 ast_verb(5,
"CODEC SPEEX: Preprocessor Denoise. [%s]\n",pp_denoise ?
"on" :
"off");
659 }
else if (!strcasecmp(var->
name,
"pp_dereverb")) {
661 ast_verb(5,
"CODEC SPEEX: Preprocessor Dereverb. [%s]\n",pp_dereverb ?
"on" :
"off");
662 }
else if (!strcasecmp(var->
name,
"pp_dereverb_decay")) {
663 if (sscanf(var->
value,
"%30f", &res_f) == 1 && res_f >= 0) {
664 ast_verb(5,
"CODEC SPEEX: Setting preprocessor Dereverb Decay to %f\n",res_f);
665 pp_dereverb_decay = res_f;
667 ast_log(LOG_ERROR,
"Error! Preprocessor Dereverb Decay must be >= 0\n");
668 }
else if (!strcasecmp(var->
name,
"pp_dereverb_level")) {
669 if (sscanf(var->
value,
"%30f", &res_f) == 1 && res_f >= 0) {
670 ast_verb(5,
"CODEC SPEEX: Setting preprocessor Dereverb Level to %f\n",res_f);
671 pp_dereverb_level = res_f;
673 ast_log(LOG_ERROR,
"Error! Preprocessor Dereverb Level must be >= 0\n");
674 }
else if (!strcasecmp(var->
name,
"experimental_rtcp_feedback")) {
676 ast_verb(5,
"CODEC SPEEX: Experimental RTCP Feedback. [%s]\n",exp_rtcp_fb ?
"on" :
"off");
683 static int reload(
void)
690 static int unload_module(
void)
702 static int load_module(
void)
706 if (parse_config(0)) {
725 AST_MODULE_INFO(
ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT,
"Speex Coder/Decoder",
726 .support_level = AST_MODULE_SUPPORT_CORE,
728 .unload = unload_module,
struct ast_variable * next
struct ast_frame * ast_trans_frameout(struct ast_trans_pvt *pvt, int datalen, int samples)
generic frameout function
int datalen
actual space used in outbuf
An object that represents data sent during a SR/RR RTCP report.
Asterisk main include file. File version handling, generic pbx functions.
Descriptor of a translator.
Support for translation of data formats. translate.c.
Structure for variables, used for configurations and for channel variables.
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
static struct ast_frame * lintospeex_frameout(struct ast_trans_pvt *pvt)
convert work buffer and produce output frame
struct ast_rtp_rtcp_report_block * report_block[0]
static int lintospeex_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
store input frame in work buffer
A report block within a SR/RR report.
static void lintospeex_feedback(struct ast_trans_pvt *pvt, struct ast_frame *feedback)
handle incoming RTCP feedback and possibly edit encoder settings
struct ast_frame_subclass subclass
Configuration File Parser.
#define ast_config_load(filename, flags)
Load a config file.
static int speextolin_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
convert and store into outbuf
#define ast_register_translator(t)
See __ast_register_translator()
Asterisk internal frame definitions.
int ast_unregister_translator(struct ast_translator *t)
Unregister a translator Unregisters the given translator.
unsigned int quality
Format quality, on scale from 0 to 150 (100 is ulaw, the reference). This allows better format to be ...
A set of macros to manage forward-linked lists.
#define ast_debug(level,...)
Log a DEBUG message.
int buf_size
size of outbuf, in bytes. Mandatory. The wrapper code will also allocate an AST_FRIENDLY_OFFSET space...
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
Default structure for translators, with the basic fields and buffers, all allocated as part of the sa...
union ast_frame::@224 data
Module has failed to load, may be in an inconsistent state.
#define ast_frisolate(fr)
Makes a frame independent of any static storage.
Structure used to handle boolean flags.
Data structure associated with a single frame of data.
enum ast_frame_type frametype
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
#define ASTERISK_GPL_KEY
The text the key() function should return.
Pluggable RTP Architecture.
Asterisk module definitions.