/* * Copyright (c) 2011 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 /* 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, }; WebRtc_Word32 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; } default: return -1; } 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 = (WebRtc_Word32)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 = (WebRtc_Word32)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; } default: return -1; } 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; 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 */ WebRtc_Word16 WebRtcIsac_UpdateBandwidthEstimator( BwEstimatorstr *bwest_str, const WebRtc_UWord16 rtp_number, const WebRtc_Word32 frame_length, const WebRtc_UWord32 send_ts, const WebRtc_UWord32 arr_ts, const WebRtc_Word32 pksize /*, const WebRtc_UWord16 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; // 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((WebRtc_UWord32)(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)((WebRtc_UWord32)(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 = (WebRtc_Word16)((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 = (WebRtc_Word32)(1.0f / bwest_str->rec_bw_inv - bwest_str->rec_header_rate); if (immediate_set) { bwest_str->rec_bw = (WebRtc_Word32) (delay_correction_factor * (float) bwest_str->rec_bw); if (bwest_str->rec_bw < (WebRtc_Word32) MIN_ISAC_BW) { bwest_str->rec_bw = (WebRtc_Word32) 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 */ WebRtc_Word16 WebRtcIsac_UpdateUplinkBwImpl( BwEstimatorstr* bwest_str, WebRtc_Word16 index, enum IsacSamplingRate encoderSamplingFreq) { 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. WebRtc_Word16 WebRtcIsac_UpdateUplinkJitter( BwEstimatorstr* bwest_str, WebRtc_Word32 index) { 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 WebRtc_UWord16 WebRtcIsac_GetDownlinkBwJitIndexImpl( BwEstimatorstr* bwest_str, WebRtc_Word16* bottleneckIndex, WebRtc_Word16* jitterInfo, enum IsacSamplingRate decoderSamplingFreq) { float MaxDelay; //WebRtc_UWord16 MaxDelayBit; float rate; float r; float e1, e2; const float weight = 0.1f; const float* ptrQuantizationTable; WebRtc_Word16 addJitterInfo; WebRtc_Word16 minInd; WebRtc_Word16 maxInd; WebRtc_Word16 midInd; /* 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); return 0; } /* get the bottle neck rate from far side to here, as estimated on this side */ WebRtc_Word32 WebRtcIsac_GetDownlinkBandwidth( const BwEstimatorstr *bwest_str) { WebRtc_Word32 rec_bw; float jitter_sign; float bw_adjust; /* 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 = (WebRtc_Word32)(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) */ WebRtc_Word32 WebRtcIsac_GetDownlinkMaxDelay(const BwEstimatorstr *bwest_str) { WebRtc_Word32 rec_max_delay; rec_max_delay = (WebRtc_Word32)(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; } /* get the bottle neck rate from here to far side, as estimated by far side */ void WebRtcIsac_GetUplinkBandwidth( const BwEstimatorstr* bwest_str, WebRtc_Word32* bitRate) { /* limit range of bottle neck rate */ if (bwest_str->send_bw_avg < MIN_ISAC_BW) { *bitRate = MIN_ISAC_BW; } else if (bwest_str->send_bw_avg > MAX_ISAC_BW) { *bitRate = MAX_ISAC_BW; } else { *bitRate = (WebRtc_Word32)(bwest_str->send_bw_avg); } return; } /* Returns the max delay value from the other side in ms */ WebRtc_Word32 WebRtcIsac_GetUplinkMaxDelay(const BwEstimatorstr *bwest_str) { WebRtc_Word32 send_max_delay; send_max_delay = (WebRtc_Word32)(bwest_str->send_max_delay_avg); /* limit range of jitter estimate */ if (send_max_delay < MIN_ISAC_MD) { send_max_delay = MIN_ISAC_MD; } else if (send_max_delay > MAX_ISAC_MD) { send_max_delay = MAX_ISAC_MD; } return send_max_delay; } /* * 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 /*,WebRtc_Word16 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; }