Index: include/asterisk/frame.h =================================================================== --- include/asterisk/frame.h (revision 270075) +++ include/asterisk/frame.h (working copy) @@ -294,6 +294,8 @@ /*! Maximum text mask */ #define AST_FORMAT_MAX_TEXT (1ULL << 28) #define AST_FORMAT_TEXT_MASK (((1ULL << 30)-1) & ~(AST_FORMAT_AUDIO_MASK) & ~(AST_FORMAT_VIDEO_MASK)) +/*! SpeeX Wideband (16kHz) Free Compression */ +#define AST_FORMAT_SPEEX_WB (1ULL << 32) /*! Raw mu-law data (G.711) */ #define AST_FORMAT_TESTLAW (1ULL << 47) /*! Reserved bit - do not use */ @@ -743,6 +745,7 @@ case AST_FORMAT_G722: case AST_FORMAT_SLINEAR16: case AST_FORMAT_SIREN7: + case AST_FORMAT_SPEEX_WB: return 16000; case AST_FORMAT_SIREN14: return 32000; Index: main/channel.c =================================================================== --- main/channel.c (revision 270075) +++ main/channel.c (working copy) @@ -812,6 +812,7 @@ /*! iLBC is not too bad */ AST_FORMAT_ILBC, /*! Speex is free, but computationally more expensive than GSM */ + AST_FORMAT_SPEEX_WB, AST_FORMAT_SPEEX, /*! Ick, LPC10 sounds terrible, but at least we have code for it, if you're tacky enough to use it */ Index: main/frame.c =================================================================== --- main/frame.c (revision 270075) +++ main/frame.c (working copy) @@ -119,6 +119,7 @@ { AST_FORMAT_T140, "t140", 0, "Passthrough T.140 Realtime Text" }, /*!< Passthrough support for T.140 Realtime Text */ { AST_FORMAT_SIREN7, "siren7", 16000, "ITU G.722.1 (Siren7, licensed from Polycom)", 80, 20, 80, 20, 20 }, /*!< Binary commercial distribution */ { AST_FORMAT_SIREN14, "siren14", 32000, "ITU G.722.1 Annex C, (Siren14, licensed from Polycom)", 120, 20, 80, 20, 20 }, /*!< Binary commercial distribution */ + { AST_FORMAT_SPEEX_WB, "speex_wb", 16000, "SpeeX (Wideband)", 10, 10, 60, 10, 20 }, /*!< codec_speex.c */ { AST_FORMAT_TESTLAW, "testlaw", 8000, "G.711 test-law", 80, 10, 150, 10, 20 }, /*!< codec_ulaw.c */ }; @@ -1406,12 +1407,8 @@ } bit += off; - if ((len * 8 - bit) == 0) { + if ((len * 8 - bit) < 5) break; - } else if ((len * 8 - bit) < 5) { - ast_log(LOG_WARNING, "Not enough bits remaining after wide band for speex samples.\n"); - break; - } /* get control bits */ c = get_n_bits_at(data, 5, bit); @@ -1432,6 +1429,7 @@ bit += c * 8; } else if (c > 8) { /* unknown */ + ast_log(LOG_WARNING, "Unknown speex control frame %d\n", c); break; } else { /* skip number bits for submode (less the 5 control bits) */ @@ -1451,6 +1449,9 @@ case AST_FORMAT_SPEEX: samples = speex_samples(f->data.ptr, f->datalen); break; + case AST_FORMAT_SPEEX_WB: + samples = 2 * speex_samples(f->data.ptr, f->datalen); + break; case AST_FORMAT_G723_1: samples = g723_samples(f->data.ptr, f->datalen); break; Index: main/rtp_engine.c =================================================================== --- main/rtp_engine.c (revision 270075) +++ main/rtp_engine.c (working copy) @@ -102,6 +102,7 @@ {{1, AST_FORMAT_G729A}, "audio", "G729A", 8000}, {{1, AST_FORMAT_G729A}, "audio", "G.729", 8000}, {{1, AST_FORMAT_SPEEX}, "audio", "speex", 8000}, + {{1, AST_FORMAT_SPEEX_WB}, "audio", "speex", 16000}, {{1, AST_FORMAT_ILBC}, "audio", "iLBC", 8000}, /* this is the sample rate listed in the RTP profile for the G.722 codec, *NOT* the actual sample rate of the media stream @@ -169,6 +170,7 @@ [111] = {1, AST_FORMAT_G726}, [112] = {1, AST_FORMAT_G726_AAL2}, [115] = {1, AST_FORMAT_SIREN14}, + [116] = {1, AST_FORMAT_SPEEX_WB}, [121] = {0, AST_RTP_CISCO_DTMF}, /* Must be type 121 */ }; Index: res/res_rtp_asterisk.c =================================================================== --- res/res_rtp_asterisk.c (revision 270075) +++ res/res_rtp_asterisk.c (working copy) @@ -1228,6 +1228,7 @@ switch (subclass) { case AST_FORMAT_SPEEX: + case AST_FORMAT_SPEEX_WB: case AST_FORMAT_G723_1: case AST_FORMAT_SIREN7: case AST_FORMAT_SIREN14: Index: codecs/codec_speex.c =================================================================== --- codecs/codec_speex.c (revision 270075) +++ codecs/codec_speex.c (working copy) @@ -97,12 +97,11 @@ #endif }; - -static int lintospeex_new(struct ast_trans_pvt *pvt) +static int speex_encoder_construct(struct ast_trans_pvt *pvt, const SpeexMode *profile, int sampling_rate) { struct speex_coder_pvt *tmp = pvt->pvt; - if (!(tmp->speex = speex_encoder_init(&speex_nb_mode))) + if (!(tmp->speex = speex_encoder_init(profile))) return -1; speex_bits_init(&tmp->bits); @@ -111,7 +110,7 @@ speex_encoder_ctl(tmp->speex, SPEEX_SET_COMPLEXITY, &complexity); #ifdef _SPEEX_TYPES_H if (preproc) { - tmp->pp = speex_preprocess_state_init(tmp->framesize, 8000); /* XXX what is this 8000 ? */ + tmp->pp = speex_preprocess_state_init(tmp->framesize, sampling_rate); speex_preprocess_ctl(tmp->pp, SPEEX_PREPROCESS_SET_VAD, &pp_vad); speex_preprocess_ctl(tmp->pp, SPEEX_PREPROCESS_SET_AGC, &pp_agc); speex_preprocess_ctl(tmp->pp, SPEEX_PREPROCESS_SET_AGC_LEVEL, &pp_agc_level); @@ -139,11 +138,21 @@ return 0; } -static int speextolin_new(struct ast_trans_pvt *pvt) +static int lintospeex_new(struct ast_trans_pvt *pvt) { + return speex_encoder_construct(pvt, &speex_nb_mode, 8000); +} + +static int lin16tospeexwb_new(struct ast_trans_pvt *pvt) +{ + return speex_encoder_construct(pvt, &speex_wb_mode, 16000); +} + +static int speex_decoder_construct(struct ast_trans_pvt *pvt, const SpeexMode *profile) +{ struct speex_coder_pvt *tmp = pvt->pvt; - if (!(tmp->speex = speex_decoder_init(&speex_nb_mode))) + if (!(tmp->speex = speex_decoder_init(profile))) return -1; speex_bits_init(&tmp->bits); @@ -154,6 +163,16 @@ return 0; } +static int speextolin_new(struct ast_trans_pvt *pvt) +{ + return speex_decoder_construct(pvt, &speex_nb_mode); +} + +static int speexwbtolin16_new(struct ast_trans_pvt *pvt) +{ + return speex_decoder_construct(pvt, &speex_wb_mode); +} + /*! \brief convert and store into outbuf */ static int speextolin_framein(struct ast_trans_pvt *pvt, struct ast_frame *f) { @@ -337,6 +356,34 @@ .buf_size = BUFFER_SAMPLES * 2, /* XXX maybe a lot less ? */ }; +static struct ast_translator speexwbtolin16 = { + .name = "speexwbtolin16", + .srcfmt = AST_FORMAT_SPEEX_WB, + .dstfmt = AST_FORMAT_SLINEAR16, + .newpvt = speexwbtolin16_new, + .framein = speextolin_framein, + .destroy = speextolin_destroy, + .sample = speex_sample, + .desc_size = sizeof(struct speex_coder_pvt), + .buffer_samples = BUFFER_SAMPLES, + .buf_size = BUFFER_SAMPLES * 2, + .native_plc = 1, +}; + +static struct ast_translator lin16tospeexwb = { + .name = "lin16tospeexwb", + .srcfmt = AST_FORMAT_SLINEAR16, + .dstfmt = AST_FORMAT_SPEEX_WB, + .newpvt = lin16tospeexwb_new, + .framein = lintospeex_framein, + .frameout = lintospeex_frameout, + .destroy = lintospeex_destroy, + .sample = slin8_sample, + .desc_size = sizeof(struct speex_coder_pvt), + .buffer_samples = BUFFER_SAMPLES, + .buf_size = BUFFER_SAMPLES * 2, /* XXX maybe a lot less ? */ +}; + static int parse_config(int reload) { struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; @@ -441,28 +488,29 @@ static int unload_module(void) { - int res; + int res = 0; - res = ast_unregister_translator(&lintospeex); res |= ast_unregister_translator(&speextolin); + res |= ast_unregister_translator(&lintospeex); + res |= ast_unregister_translator(&speexwbtolin16); + res |= ast_unregister_translator(&lin16tospeexwb); return res; } static int load_module(void) { - int res; + int res = 0; if (parse_config(0)) return AST_MODULE_LOAD_DECLINE; - res=ast_register_translator(&speextolin); - if (!res) - res=ast_register_translator(&lintospeex); - else - ast_unregister_translator(&speextolin); - if (res) - return AST_MODULE_LOAD_FAILURE; - return AST_MODULE_LOAD_SUCCESS; + + res |= ast_register_translator(&speextolin); + res |= ast_register_translator(&lintospeex); + res |= ast_register_translator(&speexwbtolin16); + res |= ast_register_translator(&lin16tospeexwb); + + return res; } AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Speex Coder/Decoder",