@ -55,6 +55,9 @@
# include "asterisk/frame.h"
# include "asterisk/linkedlists.h"
/* For struct ast_rtp_rtcp_report and struct ast_rtp_rtcp_report_block */
# include "asterisk/rtp_engine.h"
/* codec variables */
static int quality = 3 ;
static int complexity = 2 ;
@ -64,6 +67,7 @@ static int vbr = 0;
static float vbr_quality = 4 ;
static int abr = 0 ;
static int dtx = 0 ; /* set to 1 to enable silence detection */
static int exp_rtcp_fb = 0 ; /* set to 1 to use experimental RTCP feedback for changing bitrate */
static int preproc = 0 ;
static int pp_vad = 0 ;
@ -91,6 +95,11 @@ struct speex_coder_pvt {
SpeexBits bits ;
int framesize ;
int silent_state ;
int fraction_lost ;
int quality ;
int default_quality ;
# ifdef _SPEEX_TYPES_H
SpeexPreprocessState * pp ;
spx_int16_t buf [ BUFFER_SAMPLES ] ;
@ -137,6 +146,11 @@ static int speex_encoder_construct(struct ast_trans_pvt *pvt, const SpeexMode *p
speex_encoder_ctl ( tmp - > speex , SPEEX_SET_DTX , & dtx ) ;
tmp - > silent_state = 0 ;
tmp - > fraction_lost = 0 ;
tmp - > default_quality = vbr ? vbr_quality : quality ;
tmp - > quality = tmp - > default_quality ;
ast_debug ( 3 , " Default quality (%s): %d \n " , vbr ? " vbr " : " cbr " , tmp - > default_quality ) ;
return 0 ;
}
@ -342,6 +356,69 @@ static struct ast_frame *lintospeex_frameout(struct ast_trans_pvt *pvt)
return result ;
}
/*! \brief handle incoming RTCP feedback and possibly edit encoder settings */
static void lintospeex_feedback ( struct ast_trans_pvt * pvt , struct ast_frame * feedback )
{
struct speex_coder_pvt * tmp = pvt - > pvt ;
struct ast_rtp_rtcp_report * rtcp_report ;
struct ast_rtp_rtcp_report_block * report_block ;
int fraction_lost ;
int percent ;
int bitrate ;
int q ;
if ( ! exp_rtcp_fb )
return ;
rtcp_report = ( struct ast_rtp_rtcp_report * ) feedback - > data . ptr ;
if ( rtcp_report - > reception_report_count = = 0 )
return ;
report_block = rtcp_report - > report_block [ 0 ] ;
fraction_lost = report_block - > lost_count . fraction ;
if ( fraction_lost = = tmp - > fraction_lost )
return ;
/* Per RFC3550, fraction lost is defined to be the number of packets lost
* divided by the number of packets expected . Since it ' s a 8 - bit value ,
* and we want a percentage value , we multiply by 100 and divide by 256. */
percent = ( fraction_lost * 100 ) / 256 ;
bitrate = 0 ;
q = - 1 ;
ast_debug ( 3 , " Fraction lost changed: %d --> %d percent loss \n " , fraction_lost , percent ) ;
/* Handle change */
speex_encoder_ctl ( tmp - > speex , SPEEX_GET_BITRATE , & bitrate ) ;
ast_debug ( 3 , " Current bitrate: %d \n " , bitrate ) ;
ast_debug ( 3 , " Current quality: %d/%d \n " , tmp - > quality , tmp - > default_quality ) ;
/* FIXME BADLY Very ugly example of how this could be handled: probably sucks */
if ( percent < 10 ) {
/* Not that bad, default quality is fine */
q = tmp - > default_quality ;
} else if ( percent < 20 ) {
/* Quite bad, let's go down a bit */
q = tmp - > default_quality - 1 ;
} else if ( percent < 30 ) {
/* Very bad, let's go down even more */
q = tmp - > default_quality - 2 ;
} else {
/* Really bad, use the lowest quality possible */
q = 0 ;
}
if ( q < 0 )
q = 0 ;
if ( q ! = tmp - > quality ) {
ast_debug ( 3 , " -- Setting to %d \n " , q ) ;
if ( vbr ) {
float vbr_q = q ;
speex_encoder_ctl ( tmp - > speex , SPEEX_SET_VBR_QUALITY , & vbr_q ) ;
} else {
speex_encoder_ctl ( tmp - > speex , SPEEX_SET_QUALITY , & q ) ;
}
tmp - > quality = q ;
}
tmp - > fraction_lost = fraction_lost ;
}
static void speextolin_destroy ( struct ast_trans_pvt * arg )
{
struct speex_coder_pvt * pvt = arg - > pvt ;
@ -400,6 +477,7 @@ static struct ast_translator lintospeex = {
. newpvt = lintospeex_new ,
. framein = lintospeex_framein ,
. frameout = lintospeex_frameout ,
. feedback = lintospeex_feedback ,
. destroy = lintospeex_destroy ,
. sample = slin8_sample ,
. desc_size = sizeof ( struct speex_coder_pvt ) ,
@ -446,6 +524,7 @@ static struct ast_translator lin16tospeexwb = {
. newpvt = lin16tospeexwb_new ,
. framein = lintospeex_framein ,
. frameout = lintospeex_frameout ,
. feedback = lintospeex_feedback ,
. destroy = lintospeex_destroy ,
. sample = slin16_sample ,
. desc_size = sizeof ( struct speex_coder_pvt ) ,
@ -491,6 +570,7 @@ static struct ast_translator lin32tospeexuwb = {
. newpvt = lin32tospeexuwb_new ,
. framein = lintospeex_framein ,
. frameout = lintospeex_frameout ,
. feedback = lintospeex_feedback ,
. destroy = lintospeex_destroy ,
. desc_size = sizeof ( struct speex_coder_pvt ) ,
. buffer_samples = BUFFER_SAMPLES ,
@ -586,6 +666,9 @@ static int parse_config(int reload)
pp_dereverb_level = res_f ;
} else
ast_log ( LOG_ERROR , " Error! Preprocessor Dereverb Level must be >= 0 \n " ) ;
} else if ( ! strcasecmp ( var - > name , " experimental_rtcp_feedback " ) ) {
exp_rtcp_fb = ast_true ( var - > value ) ? 1 : 0 ;
ast_verb ( 3 , " CODEC SPEEX: Experimental RTCP Feedback. [%s] \n " , exp_rtcp_fb ? " on " : " off " ) ;
}
}
ast_config_destroy ( cfg ) ;