/* 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; }
// 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 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; }
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); }
/* 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; }
/**************************************************************************** * WebRtcIsacfix_UpdateUplinkBwImpl(...) * * This function updates bottle neck rate received from other side in payload * and calculates a new bottle neck to send to the other side. * * Input/Output: * - bweStr : struct containing bandwidth information. * - rtpNumber : value from RTP packet, from NetEq * - frameSize : length of signal frame in ms, from iSAC decoder * - sendTime : value in RTP header giving send time in samples * - arrivalTime : 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 * * Return value : 0 if everything went fine, * -1 otherwise */ int32_t WebRtcIsacfix_UpdateUplinkBwImpl(BwEstimatorstr *bweStr, const uint16_t rtpNumber, const int16_t frameSize, const uint32_t sendTime, const uint32_t arrivalTime, const size_t pksize, const uint16_t Index) { uint16_t weight = 0; uint32_t currBwInv = 0; uint16_t recRtpRate; uint32_t arrTimeProj; int32_t arrTimeDiff; int32_t arrTimeNoise; int32_t arrTimeNoiseAbs; int32_t sendTimeDiff; int32_t delayCorrFactor = DELAY_CORRECTION_MED; int32_t lateDiff = 0; int16_t immediateSet = 0; int32_t frameSizeSampl; int32_t temp; int32_t msec; uint32_t exponent; uint32_t reductionFactor; uint32_t numBytesInv; int32_t sign; uint32_t byteSecondsPerBit; uint32_t tempLower; uint32_t tempUpper; int32_t recBwAvgInv; int32_t numPktsExpected; int16_t errCode; RTC_DCHECK(!bweStr->external_bw_info.in_use); /* UPDATE ESTIMATES FROM OTHER SIDE */ /* The function also checks if Index has a valid value */ errCode = WebRtcIsacfix_UpdateUplinkBwRec(bweStr, Index); if (errCode <0) { return(errCode); } /* UPDATE ESTIMATES ON THIS SIDE */ /* Bits per second per byte * 1/30 or 1/60 */ if (frameSize == 60) { /* If frameSize changed since last call, from 30 to 60, recalculate some values */ if ( (frameSize != bweStr->prevFrameSizeMs) && (bweStr->countUpdates > 0)) { bweStr->countUpdates = 10; bweStr->recHeaderRate = kRecHeaderRate[1]; bweStr->maxBwInv = kInvBandwidth[3]; bweStr->minBwInv = kInvBandwidth[2]; bweStr->recBwInv = 1073741824 / (bweStr->recBw + bweStr->recHeaderRate); } /* kBitsByteSec is in Q15 */ recRtpRate = (int16_t)((kBitsByteSec * pksize) >> 15) + bweStr->recHeaderRate; } else { /* If frameSize changed since last call, from 60 to 30, recalculate some values */ if ( (frameSize != bweStr->prevFrameSizeMs) && (bweStr->countUpdates > 0)) {
/* 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; }