blob: c2c166cee95d4ba609248f12f260bfe8edbafa9b [file] [log] [blame]
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
/*
* BwEstimator.c
*
* This file contains the code for the Bandwidth Estimator designed
* for iSAC.
*
*/
#include "bandwidth_estimator.h"
#include "settings.h"
#include "isac.h"
#include "webrtc/rtc_base/checks.h"
#include <math.h>
#include <string.h>
/* array of quantization levels for bottle neck info; Matlab code: */
/* sprintf('%4.1ff, ', logspace(log10(5000), log10(40000), 12)) */
static const float kQRateTableWb[12] =
{
10000.0f, 11115.3f, 12355.1f, 13733.1f, 15264.8f, 16967.3f,
18859.8f, 20963.3f, 23301.4f, 25900.3f, 28789.0f, 32000.0f};
static const float kQRateTableSwb[24] =
{
10000.0f, 11115.3f, 12355.1f, 13733.1f, 15264.8f, 16967.3f,
18859.8f, 20963.3f, 23153.1f, 25342.9f, 27532.7f, 29722.5f,
31912.3f, 34102.1f, 36291.9f, 38481.7f, 40671.4f, 42861.2f,
45051.0f, 47240.8f, 49430.6f, 51620.4f, 53810.2f, 56000.0f,
};
int32_t WebRtcIsac_InitBandwidthEstimator(
BwEstimatorstr* bwest_str,
enum IsacSamplingRate encoderSampRate,
enum IsacSamplingRate decoderSampRate)
{
switch(encoderSampRate)
{
case kIsacWideband:
{
bwest_str->send_bw_avg = INIT_BN_EST_WB;
break;
}
case kIsacSuperWideband:
{
bwest_str->send_bw_avg = INIT_BN_EST_SWB;
break;
}
}
switch(decoderSampRate)
{
case kIsacWideband:
{
bwest_str->prev_frame_length = INIT_FRAME_LEN_WB;
bwest_str->rec_bw_inv = 1.0f /
(INIT_BN_EST_WB + INIT_HDR_RATE_WB);
bwest_str->rec_bw = (int32_t)INIT_BN_EST_WB;
bwest_str->rec_bw_avg_Q = INIT_BN_EST_WB;
bwest_str->rec_bw_avg = INIT_BN_EST_WB + INIT_HDR_RATE_WB;
bwest_str->rec_header_rate = INIT_HDR_RATE_WB;
break;
}
case kIsacSuperWideband:
{
bwest_str->prev_frame_length = INIT_FRAME_LEN_SWB;
bwest_str->rec_bw_inv = 1.0f /
(INIT_BN_EST_SWB + INIT_HDR_RATE_SWB);
bwest_str->rec_bw = (int32_t)INIT_BN_EST_SWB;
bwest_str->rec_bw_avg_Q = INIT_BN_EST_SWB;
bwest_str->rec_bw_avg = INIT_BN_EST_SWB + INIT_HDR_RATE_SWB;
bwest_str->rec_header_rate = INIT_HDR_RATE_SWB;
break;
}
}
bwest_str->prev_rec_rtp_number = 0;
bwest_str->prev_rec_arr_ts = 0;
bwest_str->prev_rec_send_ts = 0;
bwest_str->prev_rec_rtp_rate = 1.0f;
bwest_str->last_update_ts = 0;
bwest_str->last_reduction_ts = 0;
bwest_str->count_tot_updates_rec = -9;
bwest_str->rec_jitter = 10.0f;
bwest_str->rec_jitter_short_term = 0.0f;
bwest_str->rec_jitter_short_term_abs = 5.0f;
bwest_str->rec_max_delay = 10.0f;
bwest_str->rec_max_delay_avg_Q = 10.0f;
bwest_str->num_pkts_rec = 0;
bwest_str->send_max_delay_avg = 10.0f;
bwest_str->hsn_detect_rec = 0;
bwest_str->num_consec_rec_pkts_over_30k = 0;
bwest_str->hsn_detect_snd = 0;
bwest_str->num_consec_snt_pkts_over_30k = 0;
bwest_str->in_wait_period = 0;
bwest_str->change_to_WB = 0;
bwest_str->numConsecLatePkts = 0;
bwest_str->consecLatency = 0;
bwest_str->inWaitLatePkts = 0;
bwest_str->senderTimestamp = 0;
bwest_str->receiverTimestamp = 0;
bwest_str->external_bw_info.in_use = 0;
return 0;
}
/* This function updates both bottle neck rates */
/* Parameters: */
/* rtp_number - value from RTP packet, from NetEq */
/* frame length - length of signal frame in ms, from iSAC decoder */
/* send_ts - value in RTP header giving send time in samples */
/* arr_ts - value given by timeGetTime() time of arrival in samples of packet from NetEq */
/* pksize - size of packet in bytes, from NetEq */
/* Index - integer (range 0...23) indicating bottle neck & jitter as estimated by other side */
/* returns 0 if everything went fine, -1 otherwise */
int16_t WebRtcIsac_UpdateBandwidthEstimator(
BwEstimatorstr* bwest_str,
const uint16_t rtp_number,
const int32_t frame_length,
const uint32_t send_ts,
const uint32_t arr_ts,
const size_t pksize
/*, const uint16_t Index*/)
{
float weight = 0.0f;
float curr_bw_inv = 0.0f;
float rec_rtp_rate;
float t_diff_proj;
float arr_ts_diff;
float send_ts_diff;
float arr_time_noise;
float arr_time_noise_abs;
float delay_correction_factor = 1;
float late_diff = 0.0f;
int immediate_set = 0;
int num_pkts_expected;
RTC_DCHECK(!bwest_str->external_bw_info.in_use);
// We have to adjust the header-rate if the first packet has a
// frame-size different than the initialized value.
if ( frame_length != bwest_str->prev_frame_length )
{
bwest_str->rec_header_rate = (float)HEADER_SIZE * 8.0f *
1000.0f / (float)frame_length; /* bits/s */
}
/* UPDATE ESTIMATES ON THIS SIDE */
/* compute far-side transmission rate */
rec_rtp_rate = ((float)pksize * 8.0f * 1000.0f / (float)frame_length) +
bwest_str->rec_header_rate;
// rec_rtp_rate packet bits/s + header bits/s
/* check for timer wrap-around */
if (arr_ts < bwest_str->prev_rec_arr_ts)
{
bwest_str->prev_rec_arr_ts = arr_ts;
bwest_str->last_update_ts = arr_ts;
bwest_str->last_reduction_ts = arr_ts + 3*FS;
bwest_str->num_pkts_rec = 0;
/* store frame length */
bwest_str->prev_frame_length = frame_length;
/* store far-side transmission rate */
bwest_str->prev_rec_rtp_rate = rec_rtp_rate;
/* store far-side RTP time stamp */
bwest_str->prev_rec_rtp_number = rtp_number;
return 0;
}
bwest_str->num_pkts_rec++;
/* check that it's not one of the first 9 packets */
if ( bwest_str->count_tot_updates_rec > 0 )
{
if(bwest_str->in_wait_period > 0 )
{
bwest_str->in_wait_period--;
}
bwest_str->inWaitLatePkts -= ((bwest_str->inWaitLatePkts > 0)? 1:0);
send_ts_diff = (float)(send_ts - bwest_str->prev_rec_send_ts);
if (send_ts_diff <= (16 * frame_length)*2)
//doesn't allow for a dropped packet, not sure necessary to be
// that strict -DH
{
/* if not been updated for a long time, reduce the BN estimate */
if((uint32_t)(arr_ts - bwest_str->last_update_ts) *
1000.0f / FS > 3000)
{
//how many frames should have been received since the last
// update if too many have been dropped or there have been
// big delays won't allow this reduction may no longer need
// the send_ts_diff here
num_pkts_expected = (int)(((float)(arr_ts -
bwest_str->last_update_ts) * 1000.0f /(float) FS) /
(float)frame_length);
if(((float)bwest_str->num_pkts_rec/(float)num_pkts_expected) >
0.9)
{
float inv_bitrate = (float) pow( 0.99995,
(double)((uint32_t)(arr_ts -
bwest_str->last_reduction_ts)*1000.0f/FS) );
if ( inv_bitrate )
{
bwest_str->rec_bw_inv /= inv_bitrate;
//precautionary, likely never necessary
if (bwest_str->hsn_detect_snd &&
bwest_str->hsn_detect_rec)
{
if (bwest_str->rec_bw_inv > 0.000066f)
{
bwest_str->rec_bw_inv = 0.000066f;
}
}
}
else
{
bwest_str->rec_bw_inv = 1.0f /
(INIT_BN_EST_WB + INIT_HDR_RATE_WB);
}
/* reset time-since-update counter */
bwest_str->last_reduction_ts = arr_ts;
}
else
//reset here?
{
bwest_str->last_reduction_ts = arr_ts + 3*FS;
bwest_str->last_update_ts = arr_ts;
bwest_str->num_pkts_rec = 0;
}
}
}
else
{
bwest_str->last_reduction_ts = arr_ts + 3*FS;
bwest_str->last_update_ts = arr_ts;
bwest_str->num_pkts_rec = 0;
}
/* temporarily speed up adaptation if frame length has changed */
if ( frame_length != bwest_str->prev_frame_length )
{
bwest_str->count_tot_updates_rec = 10;
bwest_str->rec_header_rate = (float)HEADER_SIZE * 8.0f *
1000.0f / (float)frame_length; /* bits/s */
bwest_str->rec_bw_inv = 1.0f /((float)bwest_str->rec_bw +
bwest_str->rec_header_rate);
}
////////////////////////
arr_ts_diff = (float)(arr_ts - bwest_str->prev_rec_arr_ts);
if (send_ts_diff > 0 )
{
late_diff = arr_ts_diff - send_ts_diff;
}
else
{
late_diff = arr_ts_diff - (float)(16 * frame_length);
}
if((late_diff > 0) && !bwest_str->inWaitLatePkts)
{
bwest_str->numConsecLatePkts++;
bwest_str->consecLatency += late_diff;
}
else
{
bwest_str->numConsecLatePkts = 0;
bwest_str->consecLatency = 0;
}
if(bwest_str->numConsecLatePkts > 50)
{
float latencyMs = bwest_str->consecLatency/(FS/1000);
float averageLatencyMs = latencyMs / bwest_str->numConsecLatePkts;
delay_correction_factor = frame_length / (frame_length + averageLatencyMs);
immediate_set = 1;
bwest_str->inWaitLatePkts = (int16_t)((bwest_str->consecLatency/(FS/1000)) / 30);// + 150;
bwest_str->start_wait_period = arr_ts;
}
///////////////////////////////////////////////
/* update only if previous packet was not lost */
if ( rtp_number == bwest_str->prev_rec_rtp_number + 1 )
{
if (!(bwest_str->hsn_detect_snd && bwest_str->hsn_detect_rec))
{
if ((arr_ts_diff > (float)(16 * frame_length)))
{
//1/2 second
if ((late_diff > 8000.0f) && !bwest_str->in_wait_period)
{
delay_correction_factor = 0.7f;
bwest_str->in_wait_period = 55;
bwest_str->start_wait_period = arr_ts;
immediate_set = 1;
}
//320 ms
else if (late_diff > 5120.0f && !bwest_str->in_wait_period)
{
delay_correction_factor = 0.8f;
immediate_set = 1;
bwest_str->in_wait_period = 44;
bwest_str->start_wait_period = arr_ts;
}
}
}
if ((bwest_str->prev_rec_rtp_rate > bwest_str->rec_bw_avg) &&
(rec_rtp_rate > bwest_str->rec_bw_avg) &&
!bwest_str->in_wait_period)
{
/* test if still in initiation period and increment counter */
if (bwest_str->count_tot_updates_rec++ > 99)
{
/* constant weight after initiation part */
weight = 0.01f;
}
else
{
/* weight decreases with number of updates */
weight = 1.0f / (float) bwest_str->count_tot_updates_rec;
}
/* Bottle Neck Estimation */
/* limit outliers */
/* if more than 25 ms too much */
if (arr_ts_diff > frame_length * FS/1000 + 400.0f)
{
// in samples, why 25ms??
arr_ts_diff = frame_length * FS/1000 + 400.0f;
}
if(arr_ts_diff < (frame_length * FS/1000) - 160.0f)
{
/* don't allow it to be less than frame rate - 10 ms */
arr_ts_diff = (float)frame_length * FS/1000 - 160.0f;
}
/* compute inverse receiving rate for last packet */
curr_bw_inv = arr_ts_diff / ((float)(pksize + HEADER_SIZE) *
8.0f * FS); // (180+35)*8*16000 = 27.5 Mbit....
if(curr_bw_inv <
(1.0f / (MAX_ISAC_BW + bwest_str->rec_header_rate)))
{
// don't allow inv rate to be larger than MAX
curr_bw_inv = (1.0f /
(MAX_ISAC_BW + bwest_str->rec_header_rate));
}
/* update bottle neck rate estimate */
bwest_str->rec_bw_inv = weight * curr_bw_inv +
(1.0f - weight) * bwest_str->rec_bw_inv;
/* reset time-since-update counter */
bwest_str->last_update_ts = arr_ts;
bwest_str->last_reduction_ts = arr_ts + 3 * FS;
bwest_str->num_pkts_rec = 0;
/* Jitter Estimation */
/* projected difference between arrival times */
t_diff_proj = ((float)(pksize + HEADER_SIZE) * 8.0f *
1000.0f) / bwest_str->rec_bw_avg;
// difference between projected and actual
// arrival time differences
arr_time_noise = (float)(arr_ts_diff*1000.0f/FS) -
t_diff_proj;
arr_time_noise_abs = (float) fabs( arr_time_noise );
/* long term averaged absolute jitter */
bwest_str->rec_jitter = weight * arr_time_noise_abs +
(1.0f - weight) * bwest_str->rec_jitter;
if (bwest_str->rec_jitter > 10.0f)
{
bwest_str->rec_jitter = 10.0f;
}
/* short term averaged absolute jitter */
bwest_str->rec_jitter_short_term_abs = 0.05f *
arr_time_noise_abs + 0.95f *
bwest_str->rec_jitter_short_term_abs;
/* short term averaged jitter */
bwest_str->rec_jitter_short_term = 0.05f * arr_time_noise +
0.95f * bwest_str->rec_jitter_short_term;
}
}
}
else
{
// reset time-since-update counter when
// receiving the first 9 packets
bwest_str->last_update_ts = arr_ts;
bwest_str->last_reduction_ts = arr_ts + 3*FS;
bwest_str->num_pkts_rec = 0;
bwest_str->count_tot_updates_rec++;
}
/* limit minimum bottle neck rate */
if (bwest_str->rec_bw_inv > 1.0f / ((float)MIN_ISAC_BW +
bwest_str->rec_header_rate))
{
bwest_str->rec_bw_inv = 1.0f / ((float)MIN_ISAC_BW +
bwest_str->rec_header_rate);
}
// limit maximum bitrate
if (bwest_str->rec_bw_inv < 1.0f / ((float)MAX_ISAC_BW +
bwest_str->rec_header_rate))
{
bwest_str->rec_bw_inv = 1.0f / ((float)MAX_ISAC_BW +
bwest_str->rec_header_rate);
}
/* store frame length */
bwest_str->prev_frame_length = frame_length;
/* store far-side transmission rate */
bwest_str->prev_rec_rtp_rate = rec_rtp_rate;
/* store far-side RTP time stamp */
bwest_str->prev_rec_rtp_number = rtp_number;
// Replace bwest_str->rec_max_delay by the new
// value (atomic operation)
bwest_str->rec_max_delay = 3.0f * bwest_str->rec_jitter;
/* store send and arrival time stamp */
bwest_str->prev_rec_arr_ts = arr_ts ;
bwest_str->prev_rec_send_ts = send_ts;
/* Replace bwest_str->rec_bw by the new value (atomic operation) */
bwest_str->rec_bw = (int32_t)(1.0f / bwest_str->rec_bw_inv -
bwest_str->rec_header_rate);
if (immediate_set)
{
bwest_str->rec_bw = (int32_t) (delay_correction_factor *
(float) bwest_str->rec_bw);
if (bwest_str->rec_bw < (int32_t) MIN_ISAC_BW)
{
bwest_str->rec_bw = (int32_t) MIN_ISAC_BW;
}
bwest_str->rec_bw_avg = bwest_str->rec_bw +
bwest_str->rec_header_rate;
bwest_str->rec_bw_avg_Q = (float) bwest_str->rec_bw;
bwest_str->rec_jitter_short_term = 0.0f;
bwest_str->rec_bw_inv = 1.0f / (bwest_str->rec_bw +
bwest_str->rec_header_rate);
bwest_str->count_tot_updates_rec = 1;
immediate_set = 0;
bwest_str->consecLatency = 0;
bwest_str->numConsecLatePkts = 0;
}
return 0;
}
/* This function updates the send bottle neck rate */
/* Index - integer (range 0...23) indicating bottle neck & jitter as estimated by other side */
/* returns 0 if everything went fine, -1 otherwise */
int16_t WebRtcIsac_UpdateUplinkBwImpl(
BwEstimatorstr* bwest_str,
int16_t index,
enum IsacSamplingRate encoderSamplingFreq)
{
RTC_DCHECK(!bwest_str->external_bw_info.in_use);
if((index < 0) || (index > 23))
{
return -ISAC_RANGE_ERROR_BW_ESTIMATOR;
}
/* UPDATE ESTIMATES FROM OTHER SIDE */
if(encoderSamplingFreq == kIsacWideband)
{
if(index > 11)
{
index -= 12;
/* compute the jitter estimate as decoded on the other side */
bwest_str->send_max_delay_avg = 0.9f * bwest_str->send_max_delay_avg +
0.1f * (float)MAX_ISAC_MD;
}
else
{
/* compute the jitter estimate as decoded on the other side */
bwest_str->send_max_delay_avg = 0.9f * bwest_str->send_max_delay_avg +
0.1f * (float)MIN_ISAC_MD;
}
/* compute the BN estimate as decoded on the other side */
bwest_str->send_bw_avg = 0.9f * bwest_str->send_bw_avg +
0.1f * kQRateTableWb[index];
}
else
{
/* compute the BN estimate as decoded on the other side */
bwest_str->send_bw_avg = 0.9f * bwest_str->send_bw_avg +
0.1f * kQRateTableSwb[index];
}
if (bwest_str->send_bw_avg > (float) 28000 && !bwest_str->hsn_detect_snd)
{
bwest_str->num_consec_snt_pkts_over_30k++;
if (bwest_str->num_consec_snt_pkts_over_30k >= 66)
{
//approx 2 seconds with 30ms frames
bwest_str->hsn_detect_snd = 1;
}
}
else if (!bwest_str->hsn_detect_snd)
{
bwest_str->num_consec_snt_pkts_over_30k = 0;
}
return 0;
}
// called when there is upper-band bit-stream to update jitter
// statistics.
int16_t WebRtcIsac_UpdateUplinkJitter(
BwEstimatorstr* bwest_str,
int32_t index)
{
RTC_DCHECK(!bwest_str->external_bw_info.in_use);
if((index < 0) || (index > 23))
{
return -ISAC_RANGE_ERROR_BW_ESTIMATOR;
}
if(index > 0)
{
/* compute the jitter estimate as decoded on the other side */
bwest_str->send_max_delay_avg = 0.9f * bwest_str->send_max_delay_avg +
0.1f * (float)MAX_ISAC_MD;
}
else
{
/* compute the jitter estimate as decoded on the other side */
bwest_str->send_max_delay_avg = 0.9f * bwest_str->send_max_delay_avg +
0.1f * (float)MIN_ISAC_MD;
}
return 0;
}
// Returns the bandwidth/jitter estimation code (integer 0...23)
// to put in the sending iSAC payload
void
WebRtcIsac_GetDownlinkBwJitIndexImpl(
BwEstimatorstr* bwest_str,
int16_t* bottleneckIndex,
int16_t* jitterInfo,
enum IsacSamplingRate decoderSamplingFreq)
{
float MaxDelay;
//uint16_t MaxDelayBit;
float rate;
float r;
float e1, e2;
const float weight = 0.1f;
const float* ptrQuantizationTable;
int16_t addJitterInfo;
int16_t minInd;
int16_t maxInd;
int16_t midInd;
if (bwest_str->external_bw_info.in_use) {
*bottleneckIndex = bwest_str->external_bw_info.bottleneck_idx;
*jitterInfo = bwest_str->external_bw_info.jitter_info;
return;
}
/* Get Max Delay Bit */
/* get unquantized max delay */
MaxDelay = (float)WebRtcIsac_GetDownlinkMaxDelay(bwest_str);
if ( ((1.f - weight) * bwest_str->rec_max_delay_avg_Q + weight *
MAX_ISAC_MD - MaxDelay) > (MaxDelay - (1.f-weight) *
bwest_str->rec_max_delay_avg_Q - weight * MIN_ISAC_MD) )
{
jitterInfo[0] = 0;
/* update quantized average */
bwest_str->rec_max_delay_avg_Q =
(1.f - weight) * bwest_str->rec_max_delay_avg_Q + weight *
(float)MIN_ISAC_MD;
}
else
{
jitterInfo[0] = 1;
/* update quantized average */
bwest_str->rec_max_delay_avg_Q =
(1.f-weight) * bwest_str->rec_max_delay_avg_Q + weight *
(float)MAX_ISAC_MD;
}
// Get unquantized rate.
rate = (float)WebRtcIsac_GetDownlinkBandwidth(bwest_str);
/* Get Rate Index */
if(decoderSamplingFreq == kIsacWideband)
{
ptrQuantizationTable = kQRateTableWb;
addJitterInfo = 1;
maxInd = 11;
}
else
{
ptrQuantizationTable = kQRateTableSwb;
addJitterInfo = 0;
maxInd = 23;
}
minInd = 0;
while(maxInd > minInd + 1)
{
midInd = (maxInd + minInd) >> 1;
if(rate > ptrQuantizationTable[midInd])
{
minInd = midInd;
}
else
{
maxInd = midInd;
}
}
// Chose the index which gives results an average which is closest
// to rate
r = (1 - weight) * bwest_str->rec_bw_avg_Q - rate;
e1 = weight * ptrQuantizationTable[minInd] + r;
e2 = weight * ptrQuantizationTable[maxInd] + r;
e1 = (e1 > 0)? e1:-e1;
e2 = (e2 > 0)? e2:-e2;
if(e1 < e2)
{
bottleneckIndex[0] = minInd;
}
else
{
bottleneckIndex[0] = maxInd;
}
bwest_str->rec_bw_avg_Q = (1 - weight) * bwest_str->rec_bw_avg_Q +
weight * ptrQuantizationTable[bottleneckIndex[0]];
bottleneckIndex[0] += jitterInfo[0] * 12 * addJitterInfo;
bwest_str->rec_bw_avg = (1 - weight) * bwest_str->rec_bw_avg + weight *
(rate + bwest_str->rec_header_rate);
}
/* get the bottle neck rate from far side to here, as estimated on this side */
int32_t WebRtcIsac_GetDownlinkBandwidth( const BwEstimatorstr *bwest_str)
{
int32_t rec_bw;
float jitter_sign;
float bw_adjust;
RTC_DCHECK(!bwest_str->external_bw_info.in_use);
/* create a value between -1.0 and 1.0 indicating "average sign" of jitter */
jitter_sign = bwest_str->rec_jitter_short_term /
bwest_str->rec_jitter_short_term_abs;
/* adjust bw proportionally to negative average jitter sign */
bw_adjust = 1.0f - jitter_sign * (0.15f + 0.15f * jitter_sign * jitter_sign);
/* adjust Rate if jitter sign is mostly constant */
rec_bw = (int32_t)(bwest_str->rec_bw * bw_adjust);
/* limit range of bottle neck rate */
if (rec_bw < MIN_ISAC_BW)
{
rec_bw = MIN_ISAC_BW;
}
else if (rec_bw > MAX_ISAC_BW)
{
rec_bw = MAX_ISAC_BW;
}
return rec_bw;
}
/* Returns the max delay (in ms) */
int32_t
WebRtcIsac_GetDownlinkMaxDelay(const BwEstimatorstr *bwest_str)
{
int32_t rec_max_delay;
RTC_DCHECK(!bwest_str->external_bw_info.in_use);
rec_max_delay = (int32_t)(bwest_str->rec_max_delay);
/* limit range of jitter estimate */
if (rec_max_delay < MIN_ISAC_MD)
{
rec_max_delay = MIN_ISAC_MD;
}
else if (rec_max_delay > MAX_ISAC_MD)
{
rec_max_delay = MAX_ISAC_MD;
}
return rec_max_delay;
}
/* Clamp val to the closed interval [min,max]. */
static int32_t clamp(int32_t val, int32_t min, int32_t max) {
RTC_DCHECK_LE(min, max);
return val < min ? min : (val > max ? max : val);
}
int32_t WebRtcIsac_GetUplinkBandwidth(const BwEstimatorstr* bwest_str) {
return bwest_str->external_bw_info.in_use
? bwest_str->external_bw_info.send_bw_avg
: clamp(bwest_str->send_bw_avg, MIN_ISAC_BW, MAX_ISAC_BW);
}
int32_t WebRtcIsac_GetUplinkMaxDelay(const BwEstimatorstr* bwest_str) {
return bwest_str->external_bw_info.in_use
? bwest_str->external_bw_info.send_max_delay_avg
: clamp(bwest_str->send_max_delay_avg, MIN_ISAC_MD, MAX_ISAC_MD);
}
void WebRtcIsacBw_GetBandwidthInfo(BwEstimatorstr* bwest_str,
enum IsacSamplingRate decoder_sample_rate_hz,
IsacBandwidthInfo* bwinfo) {
RTC_DCHECK(!bwest_str->external_bw_info.in_use);
bwinfo->in_use = 1;
bwinfo->send_bw_avg = WebRtcIsac_GetUplinkBandwidth(bwest_str);
bwinfo->send_max_delay_avg = WebRtcIsac_GetUplinkMaxDelay(bwest_str);
WebRtcIsac_GetDownlinkBwJitIndexImpl(bwest_str, &bwinfo->bottleneck_idx,
&bwinfo->jitter_info,
decoder_sample_rate_hz);
}
void WebRtcIsacBw_SetBandwidthInfo(BwEstimatorstr* bwest_str,
const IsacBandwidthInfo* bwinfo) {
memcpy(&bwest_str->external_bw_info, bwinfo,
sizeof bwest_str->external_bw_info);
}
/*
* update long-term average bitrate and amount of data in buffer
* returns minimum payload size (bytes)
*/
int WebRtcIsac_GetMinBytes(
RateModel* State,
int StreamSize, /* bytes in bitstream */
const int FrameSamples, /* samples per frame */
const double BottleNeck, /* bottle neck rate; excl headers (bps) */
const double DelayBuildUp, /* max delay from bottleneck buffering (ms) */
enum ISACBandwidth bandwidth
/*,int16_t frequentLargePackets*/)
{
double MinRate = 0.0;
int MinBytes;
double TransmissionTime;
int burstInterval = BURST_INTERVAL;
// first 10 packets @ low rate, then INIT_BURST_LEN packets @
// fixed rate of INIT_RATE bps
if (State->InitCounter > 0)
{
if (State->InitCounter-- <= INIT_BURST_LEN)
{
if(bandwidth == isac8kHz)
{
MinRate = INIT_RATE_WB;
}
else
{
MinRate = INIT_RATE_SWB;
}
}
else
{
MinRate = 0;
}
}
else
{
/* handle burst */
if (State->BurstCounter)
{
if (State->StillBuffered < (1.0 - 1.0/BURST_LEN) * DelayBuildUp)
{
/* max bps derived from BottleNeck and DelayBuildUp values */
MinRate = (1.0 + (FS/1000) * DelayBuildUp /
(double)(BURST_LEN * FrameSamples)) * BottleNeck;
}
else
{
// max bps derived from StillBuffered and DelayBuildUp
// values
MinRate = (1.0 + (FS/1000) * (DelayBuildUp -
State->StillBuffered) / (double)FrameSamples) * BottleNeck;
if (MinRate < 1.04 * BottleNeck)
{
MinRate = 1.04 * BottleNeck;
}
}
State->BurstCounter--;
}
}
/* convert rate from bits/second to bytes/packet */
MinBytes = (int) (MinRate * FrameSamples / (8.0 * FS));
/* StreamSize will be adjusted if less than MinBytes */
if (StreamSize < MinBytes)
{
StreamSize = MinBytes;
}
/* keep track of when bottle neck was last exceeded by at least 1% */
if (StreamSize * 8.0 * FS / FrameSamples > 1.01 * BottleNeck) {
if (State->PrevExceed) {
/* bottle_neck exceded twice in a row, decrease ExceedAgo */
State->ExceedAgo -= /*BURST_INTERVAL*/ burstInterval / (BURST_LEN - 1);
if (State->ExceedAgo < 0)
State->ExceedAgo = 0;
}
else
{
State->ExceedAgo += (FrameSamples * 1000) / FS; /* ms */
State->PrevExceed = 1;
}
}
else
{
State->PrevExceed = 0;
State->ExceedAgo += (FrameSamples * 1000) / FS; /* ms */
}
/* set burst flag if bottle neck not exceeded for long time */
if ((State->ExceedAgo > burstInterval) &&
(State->BurstCounter == 0))
{
if (State->PrevExceed)
{
State->BurstCounter = BURST_LEN - 1;
}
else
{
State->BurstCounter = BURST_LEN;
}
}
/* Update buffer delay */
TransmissionTime = StreamSize * 8.0 * 1000.0 / BottleNeck; /* ms */
State->StillBuffered += TransmissionTime;
State->StillBuffered -= (FrameSamples * 1000) / FS; /* ms */
if (State->StillBuffered < 0.0)
{
State->StillBuffered = 0.0;
}
return MinBytes;
}
/*
* update long-term average bitrate and amount of data in buffer
*/
void WebRtcIsac_UpdateRateModel(
RateModel *State,
int StreamSize, /* bytes in bitstream */
const int FrameSamples, /* samples per frame */
const double BottleNeck) /* bottle neck rate; excl headers (bps) */
{
double TransmissionTime;
/* avoid the initial "high-rate" burst */
State->InitCounter = 0;
/* Update buffer delay */
TransmissionTime = StreamSize * 8.0 * 1000.0 / BottleNeck; /* ms */
State->StillBuffered += TransmissionTime;
State->StillBuffered -= (FrameSamples * 1000) / FS; /* ms */
if (State->StillBuffered < 0.0)
State->StillBuffered = 0.0;
}
void WebRtcIsac_InitRateModel(
RateModel *State)
{
State->PrevExceed = 0; /* boolean */
State->ExceedAgo = 0; /* ms */
State->BurstCounter = 0; /* packets */
State->InitCounter = INIT_BURST_LEN + 10; /* packets */
State->StillBuffered = 1.0; /* ms */
}
int WebRtcIsac_GetNewFrameLength(
double bottle_neck,
int current_framesamples)
{
int new_framesamples;
const int Thld_20_30 = 20000;
//const int Thld_30_20 = 30000;
const int Thld_30_20 = 1000000; // disable 20 ms frames
const int Thld_30_60 = 18000;
//const int Thld_30_60 = 0; // disable 60 ms frames
const int Thld_60_30 = 27000;
new_framesamples = current_framesamples;
/* find new framelength */
switch(current_framesamples) {
case 320:
if (bottle_neck < Thld_20_30)
new_framesamples = 480;
break;
case 480:
if (bottle_neck < Thld_30_60)
new_framesamples = 960;
else if (bottle_neck > Thld_30_20)
new_framesamples = 320;
break;
case 960:
if (bottle_neck >= Thld_60_30)
new_framesamples = 480;
break;
}
return new_framesamples;
}
double WebRtcIsac_GetSnr(
double bottle_neck,
int framesamples)
{
double s2nr;
const double a_20 = -30.0;
const double b_20 = 0.8;
const double c_20 = 0.0;
const double a_30 = -23.0;
const double b_30 = 0.48;
const double c_30 = 0.0;
const double a_60 = -23.0;
const double b_60 = 0.53;
const double c_60 = 0.0;
/* find new SNR value */
switch(framesamples) {
case 320:
s2nr = a_20 + b_20 * bottle_neck * 0.001 + c_20 * bottle_neck *
bottle_neck * 0.000001;
break;
case 480:
s2nr = a_30 + b_30 * bottle_neck * 0.001 + c_30 * bottle_neck *
bottle_neck * 0.000001;
break;
case 960:
s2nr = a_60 + b_60 * bottle_neck * 0.001 + c_60 * bottle_neck *
bottle_neck * 0.000001;
break;
default:
s2nr = 0;
}
return s2nr;
}