{"id":576,"date":"2022-03-17T23:19:52","date_gmt":"2022-03-17T15:19:52","guid":{"rendered":"https:\/\/www.fanyamin.com\/wordpress\/?p=576"},"modified":"2022-03-19T17:19:52","modified_gmt":"2022-03-19T09:19:52","slug":"webrtc-%e6%ba%90%e7%a0%81%e9%98%85%e8%af%bb%e7%ac%94%e8%ae%b0%e4%b9%8b-trendlineestimator","status":"publish","type":"post","link":"https:\/\/www.fanyamin.com\/wordpress\/?p=576","title":{"rendered":"WebRTC \u6e90\u7801\u9605\u8bfb\u7b14\u8bb0\u4e4b TrendlineEstimator"},"content":{"rendered":"<h1>Trendline<\/h1>\n<p>\u8d8b\u52bf\u7ebf\u4f30\u7b97\u5668\u6240\u5b9e\u73b0\u7684\u63a5\u53e3\u79f0\u4e3a DelayIncreaseDetectorInterface, \u610f\u8c13\u5ef6\u8fdf\u589e\u957f\u68c0\u6d4b\u5668.<\/p>\n<p>\u6bcf\u4e00\u4e2a\u53cd\u9988\u7684 PacketResult \u90fd\u4f1a\u7528\u6765\u66f4\u65b0\u8fd9\u4e2a\u8d8b\u52bf\u7ebf, \u8fd9\u4e2a\u8d8b\u52bf\u7ebf\u7684\u659c\u7387\u53cd\u5e94\u4e86\u7f51\u7edc\u5ef6\u8fdf\u7684\u53d8\u5316,<br \/>\n\u53ef\u4ee5\u4ece\u8d8b\u52bf\u7ebf\u7684\u659c\u7387\u548c\u81ea\u9002\u5e94\u7684\u9608\u503c\u53ef\u80fd\u5f97\u51fa\u5e26\u5bbd\u7684\u4f7f\u7528\u72b6\u51b5:<\/p>\n<ul>\n<li>kBwNormal: \u5e26\u5bbd\u4f7f\u7528\u6b63\u5e38<\/li>\n<li>kBwUnderusing: \u5e26\u5bbd\u4f7f\u7528\u4e0d\u8db3<\/li>\n<li>kBwOverusing: \u5e26\u5bbd\u4f7f\u7528\u8fc7\u5ea6<\/li>\n<\/ul>\n<pre><code class=\"language-cpp\">\nclass TrendlineEstimator : public DelayIncreaseDetectorInterface {\n public:\n  TrendlineEstimator(const WebRtcKeyValueConfig* key_value_config,\n                     NetworkStatePredictor* network_state_predictor);\n\n  ~TrendlineEstimator() override;\n\/*\n* \u7528\u65b0\u7684\u91c7\u6837\u6765\u66f4\u65b0\u4f30\u7b97\u5668, \u8fd9\u4e2a delta \u662f\u6307\u5305\u7ec4\u4e2d\u7b2c\u4e00\u4e2a\u5305\u548c\u6700\u540e\u4e00\u4e2a\u5305\u4e4b\u95f4\u7684\u53d1\u9001\u65f6\u95f4,\u6216\u63a5\u6536\u65f6\u95f4\u5dee\n* Update the estimator with a new sample. The deltas should represent deltas\n* between timestamp groups as defined by the InterArrival class.\n* parameters: \n*   recv_delta_ms: received time delta between the first packet and last packet of a group\n*   send_delta_ms: send time delta between the first packet and last packet of a group \n*   send_time_ms: packet \u7684\u53d1\u9001\u65f6\u95f4\n*   arrival_time_ms:  packet \u7684\u5230\u8fbe\u65f6\u95f4\n*   packet_size: packet \u7684\u5927\u5c0f\n*   calculated_deltas: \u8981\u4e0d\u8981\u8ba1\u7b97 deltas \n*\/\n  void Update(double recv_delta_ms,\n              double send_delta_ms,\n              int64_t send_time_ms,\n              int64_t arrival_time_ms,\n              size_t packet_size,\n              bool calculated_deltas) override;\n  \/\/\u5982\u679c\u63a5\u6536\u7684\u6837\u672c\u7d2f\u79ef\u5230\u4e86\u4e00\u5b9a\u6570\u91cf(window_size),\u5c31\u6765\u66f4\u65b0\u8d8b\u52bf\u7ebf\n  void UpdateTrendline(double recv_delta_ms,\n                       double send_delta_ms,\n                       int64_t send_time_ms,\n                       int64_t arrival_time_ms,\n                       size_t packet_size);\n  \/\/\u83b7\u53d6\u7f51\u7edc\u5e26\u5bbd\u7684\u4f7f\u7528\u72b6\u6001:\u6b63\u5e38\uff0c\u4f7f\u7528\u8fc7\u5ea6\uff0c\u8fd8\u662f\u4f7f\u7528\u4e0d\u8db3\n  BandwidthUsage State() const override;\n\u3000\/\/\u8d8b\u52bf\u7ebf\u7684 x \u8f74\u5c31\u662f arrival_time_ms(\u5176\u5b9e\u8981\u51cf\u5c0f\u7b2c\u4e00\u4e2a\u5305\u7684\u5230\u8fbe\u65f6\u95f4), y \u8f74\u662f smoothed_delay_ms (\u5e73\u6ed1\u8fc7\u7684\u5ef6\u8fdf\u65f6\u95f4\u5dee)\n  struct PacketTiming {\n    PacketTiming(double arrival_time_ms,\n                 double smoothed_delay_ms,\n                 double raw_delay_ms)\n        : arrival_time_ms(arrival_time_ms),\n          smoothed_delay_ms(smoothed_delay_ms),\n          raw_delay_ms(raw_delay_ms) {}\n    double arrival_time_ms;\n    double smoothed_delay_ms;\n    double raw_delay_ms;\n  };\n\n private:\n  friend class GoogCcStatePrinter;\n  \/\/\u6839\u636e\u8d8b\u52bf,\u548c\u53ef\u8c03\u8282\u7684\u9608\u503c\u6765\u68c0\u6d4b\u7f51\u7edc\u72b6\u51b5\n  void Detect(double trend, double ts_delta, int64_t now_ms);\n  \/\/\u6839\u636e\u5f53\u524d\u8ba1\u7b97\u51fa\u6765\u7684\u8d8b\u52bf(\u589e\u76ca\u8fc7\u7684), \u9002\u65f6\u5730\u4fee\u6b63\u9608\u503c, \u4ee5\u63d0\u9ad8\u5176\u5408\u7406\u6027\u548c\u654f\u611f\u5ea6, \u56fa\u5b9a\u4e0d\u53d8\u7684\u9608\u503c\u53ef\u80fd\u53cd\u5e94\u8fdf\u7f13, \u53ef\u80fd\u4f1a\u88ab\u3000TCP\u3000\u7684\u62e5\u585e\u63a7\u5236\u7ed9\u997f\u6b7b\n  void UpdateThreshold(double modified_offset, int64_t now_ms);\n\n  \/\/ Parameters.\n  TrendlineEstimatorSettings settings_;\n  const double smoothing_coef_;\n  const double threshold_gain_;\n  \/\/ Used by the existing threshold.\n  int num_of_deltas_;\n  \/\/ Keep the arrival times small by using the change from the first packet.\n  int64_t first_arrival_time_ms_;\n  \/\/ Exponential backoff filtering.\n  double accumulated_delay_;\n  double smoothed_delay_;\n  \/\/ Linear least squares regression.\n  std::deque&lt;PacketTiming&gt; delay_hist_;\n\n  const double k_up_;\n  const double k_down_;\n  double overusing_time_threshold_;\n  double threshold_;\n  double prev_modified_trend_;\n  int64_t last_update_ms_;\n  double prev_trend_;\n  double time_over_using_;\n  int overuse_counter_;\n  BandwidthUsage hypothesis_;\n  BandwidthUsage hypothesis_predicted_;\n  NetworkStatePredictor* network_state_predictor_;\n\n  RTC_DISALLOW_COPY_AND_ASSIGN(TrendlineEstimator);\n};<\/code><\/pre>\n<p>\u914d\u7f6e\u7c7b\u51b3\u5b9a\u4e86<\/p>\n<ul>\n<li>\u8981\u4e0d\u8981\u5c06\u6837\u672c\u6392\u5e8f<\/li>\n<li>\u8981\u4e0d\u8981\u6839\u636e\u4ece\u5f00\u59cb\u7684 7 \u4e2a\u5305(beginning_packets=7)\u5230\u7ed3\u675f\u7684 7 \u4e2a\u5305(end_packets=7)\u7684\u6700\u5c0f\u5ef6\u8fdf\u4e4b\u95f4\u7684\u5dee\u8ba1\u7b97\u51fa\u6700\u5927\u659c\u7387\u6765\u9650\u5236\u8d8b\u52bf\u7ebf\u7684\u659c\u7387\u7684\u6700\u5927\u503c<\/li>\n<li>\u7a97\u53e3\u5927\u5c0f\u4e5f\u5c31\u662f\u7528\u4e0d\u8ba1\u7b97\u8d8b\u52bf\u7ebf\u659c\u7387\u7684\u961f\u5217\u957f\u5ea6, \u9ed8\u8ba4\u4e3a20<\/li>\n<\/ul>\n<pre><code class=\"language-cpp\">struct TrendlineEstimatorSettings {\n  static constexpr char kKey[] = &quot;WebRTC-Bwe-TrendlineEstimatorSettings&quot;;\n  static constexpr unsigned kDefaultTrendlineWindowSize = 20;\n\n  TrendlineEstimatorSettings() = delete;\n  explicit TrendlineEstimatorSettings(\n      const WebRtcKeyValueConfig* key_value_config);\n\n  \/\/ Sort the packets in the window. Should be redundant,\n  \/\/ but then almost no cost.\n  bool enable_sort = false;\n\n  \/\/ Cap the trendline slope based on the minimum delay seen\n  \/\/ in the beginning_packets and end_packets respectively.\n  bool enable_cap = false;\n  unsigned beginning_packets = 7;\n  unsigned end_packets = 7;\n  double cap_uncertainty = 0.0;\n  \/\/\u7528\u6765\u8ba1\u7b97\u8d8b\u52bf\u7ebf\u7684\u7a97\u53e3\u4e2d\u7684\u5305\u7684\u4e2a\u6570,\u9ed8\u8ba4\u4e3a20\n  \/\/ Size (in packets) of the window. \n  unsigned window_size = kDefaultTrendlineWindowSize;\n\n  std::unique_ptr&lt;StructParametersParser&gt; Parser();\n};<\/code><\/pre>\n<p>\u7ec6\u8282\u5f88\u591a, \u6839\u636e\u6700\u5c0f\u4e8c\u4e58\u6cd5\u7b97\u51fa\u659c\u7387, \u5c06\u659c\u7387\u4e58\u4ee5\u4e00\u4e2a\u589e\u76ca,\u518d\u548c threshold \u8fdb\u884c\u6bd4\u8f83, \u4ee5\u51b3\u5b9a\u662f\u5426\u4f7f\u7528\u4e0d\u8db3, \u8fd8\u662f\u4f7f\u7528\u8fc7\u5ea6.<\/p>\n<pre><code class=\"language-cpp\">TrendlineEstimator::TrendlineEstimator(\n    const WebRtcKeyValueConfig* key_value_config,\n    NetworkStatePredictor* network_state_predictor)\n    : settings_(key_value_config),\n      smoothing_coef_(kDefaultTrendlineSmoothingCoeff),\n      threshold_gain_(kDefaultTrendlineThresholdGain),\n      num_of_deltas_(0),\n      first_arrival_time_ms_(-1),\n      accumulated_delay_(0),\n      smoothed_delay_(0),\n      delay_hist_(),\n      k_up_(0.0087),\/\/\u9608\u503c\u5411\u4e0a\u8c03\u6574\u7684\u7cfb\u6570\n      k_down_(0.039), \/\/\u9608\u503c\u5411\u4e0b\u8c03\u6574\u7684\u7cfb\u6570\n      overusing_time_threshold_(kOverUsingTimeThreshold),\/\/= 10;\n      threshold_(12.5),\n      prev_modified_trend_(NAN),\n      last_update_ms_(-1),\n      prev_trend_(0.0),\n      time_over_using_(-1),\n      overuse_counter_(0),\n      hypothesis_(BandwidthUsage::kBwNormal),\n      hypothesis_predicted_(BandwidthUsage::kBwNormal),\n      network_state_predictor_(network_state_predictor) {\n  RTC_LOG(LS_INFO)\n      &lt;&lt; &quot;Using Trendline filter for delay change estimation with settings &quot;\n      &lt;&lt; settings_.Parser()-&gt;Encode() &lt;&lt; &quot; and &quot;\n      &lt;&lt; (network_state_predictor_ ? &quot;injected&quot; : &quot;no&quot;)\n      &lt;&lt; &quot; network state predictor&quot;;\n}<\/code><\/pre>\n<h2>\u4ee5\u6700\u65b0\u6837\u672c\u66f4\u65b0\u8d8b\u52bf\u7ebf<\/h2>\n<p>\u8fd9\u91cc\u7528\u5230\u4e86EWMA\u5bf9\u7d2f\u79ef\u7684\u5ef6\u8fdf\u68af\u5ea6\u505a\u5e73\u6ed1, EWMA\uff08Exponentially Weighted Moving Average \uff09 \u6307\u6570\u52a0\u6743\u79fb\u52a8\u5e73\u6ed1\u6cd5\uff08Exponential Smoothing\uff09\u662f\u5728\u79fb\u52a8\u5e73\u5747\u6cd5\u57fa\u7840\u4e0a\u53d1\u5c55\u8d77\u6765\u7684\u4e00\u79cd\u65f6\u95f4\u5e8f\u5217\u5206\u6790\u9884\u6d4b\u6cd5. <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.fanyamin.com\/wordpress\/wp-content\/uploads\/2022\/03\/image-1647577685630.png\" alt=\"\" \/><\/p>\n<pre><code class=\"language-cpp\">\nvoid TrendlineEstimator::UpdateTrendline(double recv_delta_ms,\n                                         double send_delta_ms,\n                                         int64_t send_time_ms,\n                                         int64_t arrival_time_ms,\n                                         size_t packet_size) {\n  const double delta_ms = recv_delta_ms - send_delta_ms;\n  ++num_of_deltas_;\n  \/\/\u4f7f\u7528\u6700\u5927\u4e0d\u8d85\u8fc71000\u4e2a\u6837\u672c\n  num_of_deltas_ = std::min(num_of_deltas_, kDeltaCounterMax);\n  if (first_arrival_time_ms_ == -1)\n    first_arrival_time_ms_ = arrival_time_ms;\n  \/\/\u6307\u6570\u9000\u907f\u8fc7\u6ee4,\u5c31\u662fEWMA \u6307\u6570\u52a0\u6743\u5e73\u5747,\u6743\u91cd\u4e3a 0.9\n  \/\/ Exponential backoff filter.\n  accumulated_delay_ += delta_ms;\n  BWE_TEST_LOGGING_PLOT(1, &quot;accumulated_delay_ms&quot;, arrival_time_ms,\n                        accumulated_delay_);\n  smoothed_delay_ = smoothing_coef_ * smoothed_delay_ +\n                    (1 - smoothing_coef_) * accumulated_delay_;\n  BWE_TEST_LOGGING_PLOT(1, &quot;smoothed_delay_ms&quot;, arrival_time_ms,\n                        smoothed_delay_);\n\n  RTC_LOG(LS_INFO) &lt;&lt; &quot;[BWE_TRACE] accumulated_delay_ms, &quot; &lt;&lt; arrival_time_ms &lt;&lt; &quot;, &quot; &lt;&lt; accumulated_delay_;\n  RTC_LOG(LS_INFO) &lt;&lt; &quot;[BWE_TRACE] smoothed_delay_ms, &quot; &lt;&lt; arrival_time_ms &lt;&lt; &quot;, &quot; &lt;&lt; smoothed_delay_;\n\n  \/\/ Maintain packet window\n  delay_hist_.emplace_back(\n      static_cast&lt;double&gt;(arrival_time_ms - first_arrival_time_ms_),\n      smoothed_delay_, accumulated_delay_);\n  if (settings_.enable_sort) {\n    for (size_t i = delay_hist_.size() - 1;\n         i &gt; 0 &amp;&amp;\n         delay_hist_[i].arrival_time_ms &lt; delay_hist_[i - 1].arrival_time_ms;\n         --i) {\n      std::swap(delay_hist_[i], delay_hist_[i - 1]);\n    }\n  }\n  if (delay_hist_.size() &gt; settings_.window_size)\n    delay_hist_.pop_front();\n\n  \/\/ Simple linear regression.\n  double trend = prev_trend_;\n  if (delay_hist_.size() == settings_.window_size) {\n    \/\/ Update trend_ if it is possible to fit a line to the data. The delay\n    \/\/ trend can be seen as an estimate of (send_rate - capacity)\/capacity.\n    \/\/ 0 &lt; trend &lt; 1   -&gt;  the delay increases, queues are filling up\n    \/\/   trend == 0    -&gt;  the delay does not change\n    \/\/   trend &lt; 0     -&gt;  the delay decreases, queues are being emptied\n    trend = LinearFitSlope(delay_hist_).value_or(trend);\n    if (settings_.enable_cap) {\n      absl::optional&lt;double&gt; cap = ComputeSlopeCap(delay_hist_, settings_);\n      \/\/ We only use the cap to filter out overuse detections, not\n      \/\/ to detect additional underuses.\n      if (trend &gt;= 0 &amp;&amp; cap.has_value() &amp;&amp; trend &gt; cap.value()) {\n        trend = cap.value();\n      }\n    }\n  }\n  BWE_TEST_LOGGING_PLOT(1, &quot;trendline_slope&quot;, arrival_time_ms, trend);\n  RTC_LOG(LS_INFO) &lt;&lt; &quot;[BWE_TRACE] trendline_slope, &quot; &lt;&lt; arrival_time_ms &lt;&lt; &quot;, &quot; &lt;&lt; trend;\n\n  Detect(trend, send_delta_ms, arrival_time_ms);\n}<\/code><\/pre>\n<h2>\u961f\u5217\u4e2d\u7684\u6837\u672c\u7d2f\u79ef\u5230\u4e8620\u4e2a,\u5c31\u5f00\u59cb\u8ba1\u7b97\u659c\u7387<\/h2>\n<p>\u6700\u5c0f\u4e8c\u4e58\u6cd5, \u516c\u5f0f\u5982\u4e0b<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.fanyamin.com\/wordpress\/wp-content\/uploads\/2022\/03\/image-1647577400422.png\" alt=\"\" \/><\/p>\n<pre><code class=\"language-cpp\">absl::optional&lt;double&gt; LinearFitSlope(\n    const std::deque&lt;TrendlineEstimator::PacketTiming&gt;&amp; packets) {\n  RTC_DCHECK(packets.size() &gt;= 2);\n  \/\/ Compute the &quot;center of mass&quot;.\n  double sum_x = 0;\n  double sum_y = 0;\n  for (const auto&amp; packet : packets) {\n    sum_x += packet.arrival_time_ms;\n    sum_y += packet.smoothed_delay_ms;\n  }\n  double x_avg = sum_x \/ packets.size();\n  double y_avg = sum_y \/ packets.size();\n  \/\/ Compute the slope k = \\sum (x_i-x_avg)(y_i-y_avg) \/ \\sum (x_i-x_avg)^2\n  double numerator = 0;\n  double denominator = 0;\n  for (const auto&amp; packet : packets) {\n    double x = packet.arrival_time_ms;\n    double y = packet.smoothed_delay_ms;\n    numerator += (x - x_avg) * (y - y_avg);\n    denominator += (x - x_avg) * (x - x_avg);\n  }\n  if (denominator == 0)\n    return absl::nullopt;\n  return numerator \/ denominator;\n}<\/code><\/pre>\n<h2>\u68c0\u6d4b\u662f\u5426\u5e26\u5bbd\u4f7f\u7528\u72b6\u6001<\/h2>\n<pre><code class=\"language-cpp\">void TrendlineEstimator::Detect(double trend, double ts_delta, int64_t now_ms) {\n  if (num_of_deltas_ &lt; 2) {\n    hypothesis_ = BandwidthUsage::kBwNormal;\n    return;\n  }\n  \/\/\u8fd9\u4e2a\u659c\u7387\u8981\u4e58\u4ee5\u6837\u672c\u7684\u6570\u91cf(\u6700\u5c0f\u4e3a kMinNumDeltas = 60), \u518d\u4e58\u4ee5\u4e00\u4e2a\u589e\u76ca\u503c threshold_gain_(\u9ed8\u8ba4\u4e3akDefaultTrendlineThresholdGain = 4), \u8981\u4e0d\u7136\u592a\u5c0f\u4e86, \u6bd4\u8f83\u8d77\u6765\u4e0d\u65b9\u4fbf\n\n  const double modified_trend =\n      std::min(num_of_deltas_, kMinNumDeltas) * trend * threshold_gain_;\n  prev_modified_trend_ = modified_trend;\n  BWE_TEST_LOGGING_PLOT(1, &quot;T&quot;, now_ms, modified_trend);\n  BWE_TEST_LOGGING_PLOT(1, &quot;threshold&quot;, now_ms, threshold_);\n\n  RTC_LOG(LS_INFO) &lt;&lt; &quot;[BWE_TRACE] T, &quot; &lt;&lt; now_ms &lt;&lt; &quot;, &quot; &lt;&lt; modified_trend;\n  RTC_LOG(LS_INFO) &lt;&lt; &quot;[BWE_TRACE] threshold, &quot; &lt;&lt; now_ms &lt;&lt; &quot;, &quot; &lt;&lt; threshold_;\n  \/\/\u5982\u679c\u589e\u76ca\u8fc7\u7684\u659c\u7387\u5927\u4e8e threshold, \u518d\u68c0\u67e5\u8fc7\u5ea6\u4f7f\u7528\u7684\u65f6\u95f4\u548c\u6b21\u6570\n  if (modified_trend &gt; threshold_) {\n    if (time_over_using_ == -1) {\n      \/\/ Initialize the timer. Assume that we&#039;ve been\n      \/\/ over-using half of the time since the previous\n      \/\/ sample.\n      time_over_using_ = ts_delta \/ 2;\n    } else {\n      \/\/ Increment timer\n      time_over_using_ += ts_delta;\n    }\n    overuse_counter_++;\n    \/\/\u5982\u679c\u8fc7\u5ea6\u4f7f\u7528\u7684\u65f6\u95f4\u5dee &gt; \u8fc7\u5ea6\u4f7f\u7528\u7684\u9608\u503c, \u5e76\u4e14\u8fc7\u5ea6\u4f7f\u7528\u7684\u6b21\u6570\u5927\u4e8e1\n    if (time_over_using_ &gt; overusing_time_threshold_ &amp;&amp; overuse_counter_ &gt; 1) {\n      if (trend &gt;= prev_trend_) {\n        time_over_using_ = 0;\n        overuse_counter_ = 0;\n        hypothesis_ = BandwidthUsage::kBwOverusing;\n      }\n    }\n  } else if (modified_trend &lt; -threshold_) {\n    time_over_using_ = -1;\n    overuse_counter_ = 0;\n    hypothesis_ = BandwidthUsage::kBwUnderusing;\n  } else {\n    time_over_using_ = -1;\n    overuse_counter_ = 0;\n    hypothesis_ = BandwidthUsage::kBwNormal;\n  }\n  prev_trend_ = trend;\n  UpdateThreshold(modified_trend, now_ms);\n}   <\/code><\/pre>\n<h2>\u4fee\u6539 Threshold<\/h2>\n<p>\u4e3a\u907f\u514d\u8def\u7531\u961f\u5217\u8fc7\u5c0f\u6216\u7531\u4e8e\u5e76\u53d1\u7684TCP flow \u7ade\u4e89\u6240\u9020\u6210\u7684\u9965\u997f, \u8fd9\u4e2a\u9608\u503c\u7684\u8bbe\u7f6e\u5f88\u5173\u952e. \u9608\u503c\u5982\u679c\u592a\u5c0f\u4f1a\u5bf9\u4e8e\u7f51\u7edc\u7684\u77ac\u65f6\u5e72\u6270\u8fc7\u4e8e\u654f\u611f, \u5982\u679c\u592a\u5927\u5219\u4f1a\u53cd\u5e94\u592a\u8fdf\u949d, \u5f88\u96be\u8bbe\u7f6e\u4e00\u4e2a\u5408\u9002\u7684\u503c. GCC v2 \u91c7\u7528\u4e86\u4e00\u79cd\u5728 GCC v1 \u4e2d\u5b9a\u4e49\u7684\u81ea\u9002\u5e94\u7684\u9608\u503c Adaptive threshold<\/p>\n<pre><code class=\"language-cpp\">\nconstexpr double kMaxAdaptOffsetMs = 15.0;\nconstexpr double kOverUsingTimeThreshold = 10;\nconstexpr int kMinNumDeltas = 60;\nconstexpr int kDeltaCounterMax = 1000;\n\nvoid TrendlineEstimator::UpdateThreshold(double modified_trend,\n                                         int64_t now_ms) {\n  if (last_update_ms_ == -1)\n    last_update_ms_ = now_ms;\n  \/\/\u5982\u679c modified_trend \u6bd4\u5f53\u524d\u7684\u9608\u503c\u7684\u5dee\u503c\u8d85\u8fc7 15, \u8fd9\u5f88\u53ef\u80fd\u662f\u4e00\u4e2a\u7a81\u53d1\u60c5\u51b5,\u4e0d\u4f5c\u4fee\u6539\n  if (fabs(modified_trend) &gt; threshold_ + kMaxAdaptOffsetMs) {\n    \/\/ Avoid adapting the threshold to big latency spikes, caused e.g.,\n    \/\/ by a sudden capacity drop.\n    last_update_ms_ = now_ms;\n    return;\n  }\n  \/\/\u9884\u8bbe\u7684\u8c03\u6574\u7cfb\u6570  k_up_(0.0087),  k_down_(0.039),\n  const double k = fabs(modified_trend) &lt; threshold_ ? k_down_ : k_up_;\n  const int64_t kMaxTimeDeltaMs = 100;\n  \/\/\u53d6\u5f53\u524d\u4e0e\u4e0a\u6b21\u4fee\u6539\u4e4b\u95f4\u7684\u6837\u672c\u6570, \u4e0d\u5927\u4e8e100\n  int64_t time_delta_ms = std::min(now_ms - last_update_ms_, kMaxTimeDeltaMs);\n  \/\/threshold_ \u52a0\u4e0a\u6216\u51cf\u53bb\u8c03\u6574\u7684\u503c\n  threshold_ += k * (fabs(modified_trend) - threshold_) * time_delta_ms;\n  \/\/\u786e\u4fdd threshold_ \u5728 6 \u548c 600 \u4e4b\u95f4\n  threshold_ = rtc::SafeClamp(threshold_, 6.f, 600.f);\n  last_update_ms_ = now_ms;\n}\n<\/code><\/pre>\n<h1>DelayBasedBwe<\/h1>\n<ul>\n<li>\u57fa\u4e8e\u5ef6\u8fdf\u7684\u5e26\u5bbd\u4f30\u7b97\u5668, \u5176\u4e2d\u7684 video_delay<em>detector<\/em> \u53ca audio_delay<em>detector<\/em> \u5c31\u662f TrendlineEstimator<\/li>\n<\/ul>\n<pre><code class=\"language-cpp\">video_delay_detector_(new TrendlineEstimator(key_value_config_, network_state_predictor_)),\naudio_delay_detector_(new TrendlineEstimator(key_value_config_, network_state_predictor_)),\n<\/code><\/pre>\n<h1>InterArrivalDelta<\/h1>\n<pre><code class=\"language-cpp\">\n\/\/ Helper class to compute the inter-arrival time delta and the size delta\n\/\/ between two send bursts. This code is branched from\n\/\/ modules\/remote_bitrate_estimator\/inter_arrival.\nclass InterArrivalDelta {\n public:\n  \/\/ After this many packet groups received out of order InterArrival will\n  \/\/ reset, assuming that clocks have made a jump.\n  static constexpr int kReorderedResetThreshold = 3;\n  static constexpr TimeDelta kArrivalTimeOffsetThreshold =\n      TimeDelta::Seconds(3);\n\n  \/\/ A send time group is defined as all packets with a send time which are at\n  \/\/ most send_time_group_length older than the first timestamp in that\n  \/\/ group.\n  explicit InterArrivalDelta(TimeDelta send_time_group_length);\n\n  InterArrivalDelta() = delete;\n  InterArrivalDelta(const InterArrivalDelta&amp;) = delete;\n  InterArrivalDelta&amp; operator=(const InterArrivalDelta&amp;) = delete;\n\n  \/\/ This function returns true if a delta was computed, or false if the current\n  \/\/ group is still incomplete or if only one group has been completed.\n  \/\/ `send_time` is the send time.\n  \/\/ `arrival_time` is the time at which the packet arrived.\n  \/\/ `packet_size` is the size of the packet.\n  \/\/ `timestamp_delta` (output) is the computed send time delta.\n  \/\/ `arrival_time_delta_ms` (output) is the computed arrival-time delta.\n  \/\/ `packet_size_delta` (output) is the computed size delta.\n  bool ComputeDeltas(Timestamp send_time,\n                     Timestamp arrival_time,\n                     Timestamp system_time,\n                     size_t packet_size,\n                     TimeDelta* send_time_delta,\n                     TimeDelta* arrival_time_delta,\n                     int* packet_size_delta);\n\n private:\n  struct SendTimeGroup {\n    SendTimeGroup()\n        : size(0),\n          first_send_time(Timestamp::MinusInfinity()),\n          send_time(Timestamp::MinusInfinity()),\n          first_arrival(Timestamp::MinusInfinity()),\n          complete_time(Timestamp::MinusInfinity()),\n          last_system_time(Timestamp::MinusInfinity()) {}\n\n    bool IsFirstPacket() const { return complete_time.IsInfinite(); }\n\n    size_t size;\n    Timestamp first_send_time;\n    Timestamp send_time;\n    Timestamp first_arrival;\n    Timestamp complete_time;\n    Timestamp last_system_time;\n  };\n\n  \/\/ Returns true if the last packet was the end of the current batch and the\n  \/\/ packet with `send_time` is the first of a new batch.\n  bool NewTimestampGroup(Timestamp arrival_time, Timestamp send_time) const;\n\n  bool BelongsToBurst(Timestamp arrival_time, Timestamp send_time) const;\n\n  void Reset();\n\n  const TimeDelta send_time_group_length_;\n  SendTimeGroup current_timestamp_group_;\n  SendTimeGroup prev_timestamp_group_;\n  int num_consecutive_reordered_packets_;\n};<\/code><\/pre>\n<p>\u8fd9\u4e2a\u7c7b\u7528\u6765\u8ba1\u7b97\u4e24\u6b21\u53d1\u9001\u9ad8\u5cf0\u4e4b\u95f4\u7684 &quot;\u5230\u8fbe\u65f6\u95f4\u5dee inter-arrival time&quot; \u548c &quot;\u5927\u5c0f\u5dee size delta&quot;, \u65b9\u6cd5\u4e3a<\/p>\n<pre><code class=\"language-cpp\">  bool NewTimestampGroup(Timestamp arrival_time, Timestamp send_time) const;\n\n  bool BelongsToBurst(Timestamp arrival_time, Timestamp send_time) const;<\/code><\/pre>\n<p>\u5982\u4f55\u5224\u65ad\u54ea\u4e9b\u5305\u5c5e\u4e8e\u4e00\u4e2a\u5305\u7ec4 group, \u65b9\u6cd5\u4e3a NewTimestampGroup \u548c BelongsToBurst<\/p>\n<pre><code class=\"language-cpp\">constexpr TimeDelta kSendTimeGroupLength = TimeDelta::Millis(5);\n\n\/\/ Assumes that `timestamp` is not reordered compared to\n\/\/ `current_timestamp_group_`.\nbool InterArrivalDelta::NewTimestampGroup(Timestamp arrival_time,\n                                          Timestamp send_time) const {\n  if (current_timestamp_group_.IsFirstPacket()) {\n    return false;\n  } else if (BelongsToBurst(arrival_time, send_time)) {\n    return false;\n  } else {\n    return send_time - current_timestamp_group_.first_send_time &gt;\n           send_time_group_length_;\n  }\n}\n\nbool InterArrivalDelta::BelongsToBurst(Timestamp arrival_time,\n                                       Timestamp send_time) const {\n  RTC_DCHECK(current_timestamp_group_.complete_time.IsFinite());\n  TimeDelta arrival_time_delta =\n      arrival_time - current_timestamp_group_.complete_time;\n  TimeDelta send_time_delta = send_time - current_timestamp_group_.send_time;\n  if (send_time_delta.IsZero())\n    return true;\n  TimeDelta propagation_delta = arrival_time_delta - send_time_delta;\n  if (propagation_delta &lt; TimeDelta::Zero() &amp;&amp;\n      arrival_time_delta &lt;= kBurstDeltaThreshold &amp;&amp;\n      arrival_time - current_timestamp_group_.first_arrival &lt; kMaxBurstDuration)\n    return true;\n  return false;\n}\n<\/code><\/pre>\n<h1>Log<\/h1>\n<pre><code>[034:772][47868] (rtp_transport_controller_send.cc:627): Creating fallback congestion controller\n[034:772][28552] (peer_connection.cc:1827): Changing IceConnectionState 1 =&gt; 2\n[034:772][48504] (rtp_transport_controller_send.cc:370): SignalNetworkState Up\n[034:772][47868] (loss_based_bwe_v2.cc:113): The configuration does not specify that the estimator should be enabled, disabling it.\n[034:772][47868] (alr_experiment.cc:79): Using ALR experiment settings: pacing factor: 1, max pacer queue length: 2875, ALR bandwidth usage percent: 80, ALR start budget level percent: 40, ALR end budget level percent: -60, ALR experiment group ID: 3\n[034:772][47868] (trendline_estimator.cc:185): Using Trendline filter for delay change estimation with settings sort:false,cap:false,beginning_packets:7,end_packets:7,cap_uncertainty:0,window_size:20 and no network state predictor\n[034:772][47868] (trendline_estimator.cc:185): Using Trendline filter for delay change estimation with settings sort:false,cap:false,beginning_packets:7,end_packets:7,cap_uncertainty:0,window_size:20 and no network state predictor\n[034:772][47868] (aimd_rate_control.cc:112): Using aimd rate control with back off factor 0.85\n[034:772][47868] (delay_based_bwe.cc:88): Initialized DelayBasedBwe with separate audio overuse detectionenabled:false,packet_threshold:10,time_threshold:1 s and alr limited backoff disabled\n[034:772][47868] (delay_based_bwe.cc:301): BWE Setting start bitrate to: 300 kbps\n[034:772][47868] (goog_cc_network_control.cc:648): [BWE_TRACE] fraction_loss, 538940584,0\n[034:772][47868] (goog_cc_network_control.cc:649): [BWE_TRACE] rtt_ms, 538940584,0\n[034:772][47868] (goog_cc_network_control.cc:650): [BWE_TRACE] Target_bitrate_kbps, 538940584,300\n[034:772][47868] (probe_controller.cc:280): Measured bitrate: 300000 Minimum to probe further: 1260000\n[034:772][47868] (goog_cc_network_control.cc:711): bwe 538940584 pushback_target_bps=300000 estimate_bps=300000\n[034:772][47868] (bitrate_allocator.cc:394): Current BWE 300000\n[034:772][14136] (pacing_controller.cc:229): bwe:pacer_updated pacing_kbps=330 padding_budget_kbps=0\n[034:772][14136] (bitrate_prober.cc:114): Probe cluster (bitrate:min bytes:min packets): (900000:1688:5)\n[034:772][14136] (bitrate_prober.cc:114): Probe cluster (bitrate:min bytes:min packets): (1800000:3375:5)<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Trendline \u8d8b\u52bf\u7ebf\u4f30\u7b97\u5668\u6240\u5b9e\u73b0\u7684\u63a5\u53e3\u79f0\u4e3a DelayIncreaseDetectorInterface, \u610f\u8c13\u5ef6\u8fdf\u589e\u957f\u68c0\u6d4b\u5668. \u6bcf\u4e00\u4e2a\u53cd\u9988\u7684 PacketResult \u90fd\u4f1a\u7528\u6765\u66f4\u65b0\u8fd9\u4e2a\u8d8b\u52bf\u7ebf, \u8fd9\u4e2a\u8d8b\u52bf\u7ebf\u7684\u659c\u7387\u53cd\u5e94\u4e86\u7f51\u7edc\u5ef6\u8fdf\u7684\u53d8\u5316, \u53ef\u4ee5\u4ece\u8d8b\u52bf\u7ebf\u7684\u659c\u7387\u548c\u81ea\u9002\u5e94\u7684\u9608\u503c\u53ef\u80fd\u5f97\u51fa\u5e26\u5bbd\u7684\u4f7f\u7528\u72b6\u51b5: kBwNormal: \u5e26\u5bbd\u4f7f\u7528\u6b63\u5e38 kBwUnderusing: \u5e26\u5bbd\u4f7f\u7528\u4e0d\u8db3 kBwOverusing: \u5e26\u5bbd\u4f7f\u7528\u8fc7\u5ea6 class TrendlineEstimator : public DelayIncreaseDetectorInterface { public: TrendlineEstimator(const WebRtcKeyValueConfig* key_value_config, NetworkStatePredictor* network_state_predictor); ~TrendlineEstimator() override; \/* * \u7528\u65b0\u7684\u91c7\u6837\u6765\u66f4\u65b0\u4f30\u7b97\u5668, \u8fd9\u4e2a delta \u662f\u6307\u5305\u7ec4\u4e2d\u7b2c\u4e00\u4e2a\u5305\u548c\u6700\u540e\u4e00\u4e2a\u5305\u4e4b\u95f4\u7684\u53d1\u9001\u65f6\u95f4,\u6216\u63a5\u6536\u65f6\u95f4\u5dee * Update the estimator with a new sample. The deltas should represent deltas * between timestamp groups as defined by [&hellip;] <a class=\"read-more\" href=\"https:\/\/www.fanyamin.com\/wordpress\/?p=576\" title=\"Permanent Link to: WebRTC \u6e90\u7801\u9605\u8bfb\u7b14\u8bb0\u4e4b TrendlineEstimator\">&rarr;Read&nbsp;more<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-576","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/576"}],"collection":[{"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=576"}],"version-history":[{"count":24,"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/576\/revisions"}],"predecessor-version":[{"id":635,"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/576\/revisions\/635"}],"wp:attachment":[{"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=576"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=576"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=576"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}