| /* |
| * Copyright (c) 2026 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. |
| */ |
| #ifndef MODULES_CONGESTION_CONTROLLER_ECT1_POLICY_H_ |
| #define MODULES_CONGESTION_CONTROLLER_ECT1_POLICY_H_ |
| |
| #include <optional> |
| |
| #include "api/units/time_delta.h" |
| #include "api/units/timestamp.h" |
| |
| namespace webrtc { |
| |
| // Decides if RTP packets should be sent with an ECT(1) marking, for example to |
| // support L4S as described in RFC 9331. |
| // |
| // ECT(1) is used if the negotiated feedback format reports the ECN marking of |
| // received packets and the congestion controller adapts to ECN. It is disabled |
| // until the network route changes if the network path bleaches the marking to |
| // Not-ECT, or if feedback stops arriving while packets are sent as ECT(1). The |
| // latter can happen when feedback is lost due to temporary network issues, so |
| // it is retried once per route. |
| // |
| // A path that drops ECT(1) from the start is detected quickly, since no |
| // feedback has been received on the route yet. Once ECT(1) is known to work, |
| // a much longer time without feedback is needed, so that a temporary outage |
| // is not mistaken for the same thing. A working path can start dropping the |
| // marking mid call, since traffic can be rerouted over a different middlebox |
| // without the ICE candidate pair changing. |
| class Ect1Policy { |
| public: |
| // Whether the remote peer reports the ECN marking of received packets back to |
| // the sender, for example with the RTCP feedback message in RFC 8888. |
| void SetFeedbackSupportsEcn(bool supports_ecn); |
| // Whether the congestion controller reacts to reported CE markings. |
| void SetCongestionControllerSupportsEcn(bool supports_ecn); |
| void OnNetworkRouteChanged(); |
| // `has_bleached_ect1` is true if a feedback report showed at least one |
| // packet that was sent as ECT(1) arriving as Not-ECT. `has_preserved_ect1` |
| // is true if it showed at least one arriving still ECN capable. Both are |
| // false if the report said nothing about the marking, which is the case |
| // until the first packet sent as ECT(1) is reported received. |
| void OnPacketsFeedback(bool has_bleached_ect1, bool has_preserved_ect1); |
| |
| // Must be called for every sent RTP packet. `sent_as_ect1` is whether the |
| // packet actually carried the marking. |
| void OnPacketSent(Timestamp send_time, bool sent_as_ect1); |
| |
| bool ShouldSendEct1() const; |
| |
| private: |
| void LogIfDecisionChanged(); |
| |
| // How long to wait for feedback before assuming ECT(1) packets are dropped. |
| TimeDelta Ect1FeedbackTimeout() const; |
| |
| bool feedback_supports_ecn_ = false; |
| bool congestion_controller_supports_ecn_ = false; |
| bool route_bleaches_ect1_ = false; |
| // When the route was judged to drop ECT(1) packets. Unset if it was not. |
| std::optional<Timestamp> ect1_drop_detected_time_; |
| // Whether the single retry allowed on this route has been used. |
| bool ect1_drop_retried_ = false; |
| bool ect1_preserved_on_route_ = false; |
| // Does not count time when nothing was sent. |
| TimeDelta time_sending_ect1_without_feedback_ = TimeDelta::Zero(); |
| // Send time of the last RTP packet, whatever its marking. |
| std::optional<Timestamp> last_send_time_; |
| bool logged_send_ect1_ = false; |
| }; |
| |
| } // namespace webrtc |
| |
| #endif // MODULES_CONGESTION_CONTROLLER_ECT1_POLICY_H_ |