summaryrefslogtreecommitdiff
path: root/webrtc/modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.c
diff options
context:
space:
mode:
Diffstat (limited to 'webrtc/modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.c')
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.c1031
1 files changed, 1031 insertions, 0 deletions
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.c b/webrtc/modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.c
new file mode 100644
index 0000000..82fd053
--- /dev/null
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.c
@@ -0,0 +1,1031 @@
+/*
+ * 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 "webrtc/modules/audio_coding/codecs/isac/main/include/isac.h"
+
+#include <assert.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;
+
+ assert(!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)
+{
+ assert(!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)
+{
+ assert(!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;
+
+ assert(!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;
+
+ assert(!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) {
+ assert(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) {
+ assert(!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;
+
+}