| /* | 
 |  *  Copyright 2025 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. | 
 |  */ | 
 |  | 
 | #include "modules/congestion_controller/scream/delay_based_congestion_control.h" | 
 |  | 
 | #include <algorithm> | 
 |  | 
 | #include "api/transport/network_types.h" | 
 | #include "api/units/data_size.h" | 
 | #include "api/units/time_delta.h" | 
 | #include "modules/congestion_controller/scream/scream_v2_parameters.h" | 
 |  | 
 | namespace webrtc { | 
 |  | 
 | DelayBasedCongestionControl::DelayBasedCongestionControl( | 
 |     ScreamV2Parameters params) | 
 |     : params_(params), | 
 |       base_delay_history_(params_.base_delay_window_length.Get()) { | 
 |   base_delay_history_.Insert(TimeDelta::PlusInfinity()); | 
 | } | 
 |  | 
 | void DelayBasedCongestionControl::OnTransportPacketsFeedback( | 
 |     const TransportPacketsFeedback& msg) { | 
 |   if (msg.PacketsWithFeedback().empty()) { | 
 |     return; | 
 |   } | 
 |   last_smoothed_rtt_ = msg.smoothed_rtt; | 
 |   TimeDelta one_way_delay = TimeDelta::PlusInfinity(); | 
 |   for (const PacketResult& packet : msg.SortedByReceiveTime()) { | 
 |     one_way_delay = packet.receive_time - packet.sent_packet.send_time; | 
 |     next_base_delay_ = std::min(next_base_delay_, one_way_delay); | 
 |  | 
 |     if (params_.use_all_packets_when_calculating_queue_delay.Get()) { | 
 |       UpdateQueueDelayAverage(one_way_delay); | 
 |     } | 
 |   } | 
 |  | 
 |   if (!params_.use_all_packets_when_calculating_queue_delay.Get() && | 
 |       (msg.feedback_time - last_update_qdelay_avg_time_) >= | 
 |           std::min(params_.virtual_rtt.Get(), msg.smoothed_rtt)) { | 
 |     last_update_qdelay_avg_time_ = msg.feedback_time; | 
 |     UpdateQueueDelayAverage(one_way_delay); | 
 |   } | 
 |  | 
 |   if (msg.feedback_time - last_base_delay_update_ >= | 
 |       params_.base_delay_history_update_interval.Get()) { | 
 |     base_delay_history_.Insert(next_base_delay_); | 
 |     last_base_delay_update_ = msg.feedback_time; | 
 |     next_base_delay_ = TimeDelta::PlusInfinity(); | 
 |   } | 
 | } | 
 |  | 
 | void DelayBasedCongestionControl::UpdateQueueDelayAverage( | 
 |     TimeDelta one_way_delay) { | 
 |   TimeDelta current_qdelay = | 
 |       one_way_delay - std::min(next_base_delay_, base_delay_history_.GetMin()); | 
 |   // `queue_delay_avg_` is updated with a slow attack,fast decay EWMA | 
 |   // filter. | 
 |   if (current_qdelay < queue_delay_avg_) { | 
 |     queue_delay_avg_ = current_qdelay; | 
 |   } else { | 
 |     queue_delay_avg_ = | 
 |         params_.queue_delay_avg_g.Get() * current_qdelay + | 
 |         (1.0 - params_.queue_delay_avg_g.Get()) * queue_delay_avg_; | 
 |   } | 
 | } | 
 |  | 
 | bool DelayBasedCongestionControl::IsQueueDelayDetected() const { | 
 |   return queue_delay_avg_ > params_.queue_delay_target.Get() * | 
 |                                 params_.queue_delay_increased_threshold.Get(); | 
 | } | 
 |  | 
 | bool DelayBasedCongestionControl::ShouldReduceReferenceWindow() const { | 
 |   return (queue_delay_avg_ > params_.queue_delay_target.Get() * | 
 |                                  params_.queue_delay_threshold.Get()); | 
 | } | 
 |  | 
 | DataSize DelayBasedCongestionControl::UpdateReferenceWindow( | 
 |     DataSize ref_window, | 
 |     double virtual_alpha_lim) const { | 
 |   // `min_delay_based_bwe_`put a lower bound on the reference window. | 
 |   DataSize min_allowed_reference_window = | 
 |       min_delay_based_bwe_ * last_smoothed_rtt_; | 
 |  | 
 |   if (ref_window < min_allowed_reference_window) { | 
 |     return min_allowed_reference_window; | 
 |   } | 
 |   double l4s_alpha_v = std::clamp( | 
 |       4.0 * virtual_alpha_lim * | 
 |           (queue_delay_avg_ - params_.queue_delay_target.Get() * | 
 |                                   params_.queue_delay_threshold.Get()) / | 
 |           (params_.queue_delay_target.Get() * | 
 |            params_.queue_delay_threshold.Get()), | 
 |       0.0, 1.0); | 
 |   return std::max( | 
 |       min_allowed_reference_window, | 
 |       (1 - l4s_alpha_v * params_.queue_delay_threshold.Get()) * ref_window); | 
 | } | 
 |  | 
 | }  // namespace webrtc |