diff options
author | Lorenzo Miniero <lminiero@gmail.com> | 2016-11-29 16:31:21 +0100 |
---|---|---|
committer | Lorenzo Miniero <lminiero@gmail.com> | 2017-01-23 13:25:31 +0100 |
commit | 1061539b75811d9115dcbc0be46967515bd9e2d1 (patch) | |
tree | 5c1996f9a2943cc130c067546960732d2d81129b /codecs/codec_speex.c | |
parent | 31268e0a280110748f33314a2c09563c576243de (diff) |
media: Add experimental support for RTCP feedback.
This change adds experimental support for providing RTCP
feedback information to codec modules so they can dynamically
change themselves based on conditions.
ASTERISK-26584
Change-Id: Ifd6aa77fb4a7ff546c6025900fc2baf332c31857
Diffstat (limited to 'codecs/codec_speex.c')
-rw-r--r-- | codecs/codec_speex.c | 83 |
1 files changed, 83 insertions, 0 deletions
diff --git a/codecs/codec_speex.c b/codecs/codec_speex.c index 49990e988..72ac22023 100644 --- a/codecs/codec_speex.c +++ b/codecs/codec_speex.c @@ -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); |