diff --git a/node/src/Transport.ts b/node/src/Transport.ts index fb65f2e4d2..40d0ceb9b4 100644 --- a/node/src/Transport.ts +++ b/node/src/Transport.ts @@ -56,7 +56,40 @@ export type TransportTuple = /** * Valid types for 'trace' event. */ -export type TransportTraceEventType = 'probation' | 'bwe'; +export type TransportTraceEventType = 'probation' | 'bwe' | 'bweStats'; + +/** + * bweStats typings for trace event. + */ +export type TransportTraceEventBweStatsInfo = { + estimatedBitrate: number; + delay: { + slope: number; + rSquared: number; + threshold: number; + rtt: number; + rateControlState: number; + delayDetectorState: number; + }; + probe: { + estimatedBitrate: number; + }; + loss: { + inherent: number; + avg: number; + estimatedBitrate: number; + sendingRate: number; + }; + alr: boolean; + ackBitrate: number; + desiredBitrate: number; + effectiveDesiredBitrate: number; + minBitrate: number; + maxBitrate: number; + startBitrate: number; + maxPaddingBitrate: number; + sendingRate: number; +}; /** * 'trace' event data. @@ -81,7 +114,7 @@ export type TransportTraceEventData = /** * Per type information. */ - info: any; + info: TransportTraceEventBweStatsInfo | any; }; export type SctpState = 'new' | 'connecting' | 'connected' | 'failed' | 'closed'; diff --git a/node/src/Worker.ts b/node/src/Worker.ts index eefa9c8018..f0747fcc97 100644 --- a/node/src/Worker.ts +++ b/node/src/Worker.ts @@ -63,16 +63,17 @@ export type WorkerSettings = * certificate is dynamically created. */ dtlsPrivateKeyFile?: string; - + /* eslint-disable max-len */ /** * Field trials for libwebrtc. * @private * * NOTE: For advanced users only. An invalid value will make the worker crash. * Default value is - * "WebRTC-Bwe-AlrLimitedBackoff/Enabled/". + * "WebRTC-Bwe-AlrLimitedBackoff/Enabled/WebRTC-Bwe-LossBasedBweV2/BwRampupUpperBoundFactor:1.1,TrendlineIntegrationEnabled:true/WebRTC-Bwe-RobustThroughputEstimatorSettings/enabled/" */ libwebrtcFieldTrials?: string; + /* eslint-enable max-len */ /** * Custom application data. diff --git a/rust/src/worker.rs b/rust/src/worker.rs index 431b2a9222..73a34f6fef 100644 --- a/rust/src/worker.rs +++ b/rust/src/worker.rs @@ -186,7 +186,7 @@ pub struct WorkerSettings { /// /// NOTE: For advanced users only. An invalid value will make the worker crash. /// Default value is - /// "WebRTC-Bwe-AlrLimitedBackoff/Enabled/". + /// "WebRTC-Bwe-AlrLimitedBackoff/Enabled/WebRTC-Bwe-LossBasedBweV2/BwRampupUpperBoundFactor:1.1,TrendlineIntegrationEnabled:true/WebRTC-Bwe-RobustThroughputEstimatorSettings/enabled/" #[doc(hidden)] pub libwebrtc_field_trials: Option, /// Function that will be called under worker thread before worker starts, can be used for diff --git a/worker/deps/libwebrtc/libwebrtc.gyp b/worker/deps/libwebrtc/libwebrtc.gyp index bc786cf165..eb84186549 100644 --- a/worker/deps/libwebrtc/libwebrtc.gyp +++ b/worker/deps/libwebrtc/libwebrtc.gyp @@ -52,7 +52,6 @@ 'libwebrtc/modules/congestion_controller/goog_cc/link_capacity_estimator.cc', 'libwebrtc/modules/congestion_controller/goog_cc/alr_detector.cc', 'libwebrtc/modules/congestion_controller/goog_cc/probe_controller.cc', - 'libwebrtc/modules/congestion_controller/goog_cc/median_slope_estimator.cc', 'libwebrtc/modules/congestion_controller/goog_cc/bitrate_estimator.cc', 'libwebrtc/modules/congestion_controller/goog_cc/trendline_estimator.cc', 'libwebrtc/modules/congestion_controller/goog_cc/delay_based_bwe.cc', @@ -110,7 +109,6 @@ 'libwebrtc/modules/bitrate_controller/send_side_bandwidth_estimation.h', 'libwebrtc/modules/congestion_controller/goog_cc/bitrate_estimator.h', 'libwebrtc/modules/congestion_controller/goog_cc/link_capacity_estimator.h', - 'libwebrtc/modules/congestion_controller/goog_cc/median_slope_estimator.h', 'libwebrtc/modules/congestion_controller/goog_cc/probe_controller.h', 'libwebrtc/modules/congestion_controller/goog_cc/trendline_estimator.h', 'libwebrtc/modules/congestion_controller/goog_cc/goog_cc_network_control.h', diff --git a/worker/deps/libwebrtc/libwebrtc/api/transport/network_control.h b/worker/deps/libwebrtc/libwebrtc/api/transport/network_control.h index f1ea92db8e..829f582a8f 100644 --- a/worker/deps/libwebrtc/libwebrtc/api/transport/network_control.h +++ b/worker/deps/libwebrtc/libwebrtc/api/transport/network_control.h @@ -32,6 +32,13 @@ class TargetTransferRateObserver { virtual void OnStartRateUpdate(DataRate) {} }; +class BweStatsTracer { +public: + virtual ~BweStatsTracer() = default; + virtual void OnBweStats(BweStats) = 0; +}; + + // Configuration sent to factory create function. The parameters here are // optional to use for a network controller implementation. struct NetworkControllerConfig { @@ -72,7 +79,11 @@ class NetworkControllerInterface { // Called round trip time has been calculated by protocol specific mechanisms. virtual NetworkControlUpdate OnRoundTripTimeUpdate(RoundTripTimeUpdate) = 0; // Called when a packet is sent on the network. - virtual NetworkControlUpdate OnSentPacket(SentPacket) = 0; + virtual NetworkControlUpdate OnSentPacket( + SentPacket) = 0; + // Called when a packet is received from the remote client. + virtual NetworkControlUpdate OnReceivedPacket( + ReceivedPacket) = 0; // Called when the stream specific configuration has been updated. virtual NetworkControlUpdate OnStreamsConfig(StreamsConfig) = 0; // Called when target transfer rate constraints has been changed. @@ -85,6 +96,7 @@ class NetworkControllerInterface { TransportPacketsFeedback) = 0; // Called with network state estimate updates. virtual NetworkControlUpdate OnNetworkStateEstimate(NetworkStateEstimate) = 0; + virtual BweStats GetBweStats() = 0; }; // NetworkControllerFactoryInterface is an interface for creating a network @@ -108,7 +120,11 @@ class NetworkStateEstimator { // Gets the current best estimate according to the estimator. virtual absl::optional GetCurrentEstimate() = 0; // Called with per packet feedback regarding receive time. + // Used when the NetworkStateEstimator runs in the sending endpoint. virtual void OnTransportPacketsFeedback(const TransportPacketsFeedback&) = 0; + // Called with per packet feedback regarding receive time. + // Used when the NetworkStateEstimator runs in the receiving endpoint. + virtual void OnReceivedPacket(const PacketResult&) {} // Called when the receiving or sending endpoint changes address. virtual void OnRouteChange(const NetworkRouteChange&) = 0; virtual ~NetworkStateEstimator() = default; diff --git a/worker/deps/libwebrtc/libwebrtc/api/transport/network_types.cc b/worker/deps/libwebrtc/libwebrtc/api/transport/network_types.cc index d0a0c4a05f..bf3f5ed06d 100644 --- a/worker/deps/libwebrtc/libwebrtc/api/transport/network_types.cc +++ b/worker/deps/libwebrtc/libwebrtc/api/transport/network_types.cc @@ -13,11 +13,14 @@ #include namespace webrtc { -// TODO(srte): Revert to using default after removing union member. -StreamsConfig::StreamsConfig() {} +StreamsConfig::StreamsConfig() = default; StreamsConfig::StreamsConfig(const StreamsConfig&) = default; StreamsConfig::~StreamsConfig() = default; +BweStats::BweStats() = default; +BweStats::BweStats(const BweStats&) = default; +BweStats::~BweStats() = default; + TargetRateConstraints::TargetRateConstraints() = default; TargetRateConstraints::TargetRateConstraints(const TargetRateConstraints&) = default; @@ -49,7 +52,7 @@ std::vector TransportPacketsFeedback::ReceivedWithSendInfo() const { std::vector res; for (const PacketResult& fb : packet_feedbacks) { - if (fb.receive_time.IsFinite()) { + if (fb.IsReceived()) { res.push_back(fb); } } @@ -59,7 +62,7 @@ std::vector TransportPacketsFeedback::ReceivedWithSendInfo() std::vector TransportPacketsFeedback::LostWithSendInfo() const { std::vector res; for (const PacketResult& fb : packet_feedbacks) { - if (fb.receive_time.IsPlusInfinity()) { + if (!fb.IsReceived()) { res.push_back(fb); } } @@ -75,7 +78,7 @@ std::vector TransportPacketsFeedback::SortedByReceiveTime() const { std::vector res; for (const PacketResult& fb : packet_feedbacks) { - if (fb.receive_time.IsFinite()) { + if (fb.IsReceived()) { res.push_back(fb); } } diff --git a/worker/deps/libwebrtc/libwebrtc/api/transport/network_types.h b/worker/deps/libwebrtc/libwebrtc/api/transport/network_types.h index 20ab6aaba7..02d94553bb 100644 --- a/worker/deps/libwebrtc/libwebrtc/api/transport/network_types.h +++ b/worker/deps/libwebrtc/libwebrtc/api/transport/network_types.h @@ -15,6 +15,8 @@ #include "api/units/data_size.h" #include "api/units/time_delta.h" #include "api/units/timestamp.h" +#include "modules/congestion_controller/goog_cc/delay_increase_detector_interface.h" +#include "modules/remote_bitrate_estimator/include/bwe_defines.h" #include #include @@ -24,6 +26,50 @@ namespace webrtc { // Configuration +// Represents constraints and rates related to the currently enabled streams. +// This is used as input to the congestion controller via the StreamsConfig +// struct. +struct BitrateAllocationLimits { + // The total minimum send bitrate required by all sending streams. + DataRate min_allocatable_rate = DataRate::Zero(); + // The total maximum allocatable bitrate for all currently available streams. + DataRate max_allocatable_rate = DataRate::Zero(); + // The max bitrate to use for padding. The sum of the per-stream max padding + // rate. + DataRate max_padding_rate = DataRate::Zero(); +}; + +struct LossEstimatorState { + ~LossEstimatorState() = default; + absl::optional bandwidth_estimate = DataRate::Zero(); + double inherent_loss; + double avg_loss; + absl::optional sending_rate = DataRate::Zero(); +}; + +struct DelayBasedBweState { + RateControlState rate_control_state; + DelayIncreaseDetectorInterface::RegressionResult trend; + BandwidthUsage delay_detector_state; + double threshold; +}; + +struct BweStats { + BweStats(); + BweStats(const BweStats&); + ~BweStats(); + Timestamp time = Timestamp::PlusInfinity(); + absl::optional estimated_bitrate; + absl::optional acknowledged_bitrate; + DelayBasedBweState delay; + TimeDelta rtt = TimeDelta::ms(0); + bool in_alr = false; + LossEstimatorState loss_estimator_state; + absl::optional probe_bitrate; +}; + + + // Use StreamsConfig for information about streams that is required for specific // adjustments to the algorithms in network controllers. Especially useful // for experiments. @@ -34,9 +80,9 @@ struct StreamsConfig { Timestamp at_time = Timestamp::PlusInfinity(); absl::optional requests_alr_probing; absl::optional pacing_factor; - union { - absl::optional min_total_allocated_bitrate = absl::nullopt; - }; + + // TODO: (srte) Use BitrateAllocationLimits here. + absl::optional min_total_allocated_bitrate; absl::optional max_padding_rate; absl::optional max_total_allocated_bitrate; }; @@ -84,13 +130,20 @@ struct PacedPacketInfo { int probe_cluster_id = kNotAProbe; int probe_cluster_min_probes = -1; int probe_cluster_min_bytes = -1; + int probe_cluster_bytes_sent = 0; }; struct SentPacket { Timestamp send_time = Timestamp::PlusInfinity(); + // Size of packet with overhead up to IP layer. DataSize size = DataSize::Zero(); + // Size of preceeding packets that are not part of feedback. DataSize prior_unacked_data = DataSize::Zero(); + // Probe cluster id and parameters including bitrate, number of packets and + // number of bytes. PacedPacketInfo pacing_info; + // True if the packet is an audio packet, false for video, padding, RTX etc. + bool audio = false; // Transport independent sequence number, any tracked packet should have a // sequence number that is unique over the whole call and increasing by 1 for // each packet. @@ -138,6 +191,8 @@ struct PacketResult { PacketResult(const PacketResult&); ~PacketResult(); + inline bool IsReceived() const { return !receive_time.IsPlusInfinity(); } + SentPacket sent_packet; Timestamp receive_time = Timestamp::PlusInfinity(); }; @@ -166,6 +221,7 @@ struct TransportPacketsFeedback { struct NetworkEstimate { Timestamp at_time = Timestamp::PlusInfinity(); + // Deprecated, use TargetTransferRate::target_rate instead. DataRate bandwidth = DataRate::Infinity(); TimeDelta round_trip_time = TimeDelta::PlusInfinity(); TimeDelta bwe_period = TimeDelta::PlusInfinity(); @@ -199,6 +255,8 @@ struct TargetTransferRate { // The estimate on which the target rate is based on. NetworkEstimate network_estimate; DataRate target_rate = DataRate::Zero(); + DataRate stable_target_rate = DataRate::Zero(); + double cwnd_reduce_ratio = 0; }; // Contains updates of network controller comand state. Using optionals to diff --git a/worker/deps/libwebrtc/libwebrtc/call/rtp_transport_controller_send.cc b/worker/deps/libwebrtc/libwebrtc/call/rtp_transport_controller_send.cc index f99aaa2846..b9fe0c2b30 100644 --- a/worker/deps/libwebrtc/libwebrtc/call/rtp_transport_controller_send.cc +++ b/worker/deps/libwebrtc/libwebrtc/call/rtp_transport_controller_send.cc @@ -61,6 +61,7 @@ RtpTransportControllerSend::RtpTransportControllerSend( : packet_router_(packet_router), pacer_(packet_router_), observer_(nullptr), + stats_tracer_(nullptr), controller_factory_override_(controller_factory), process_interval_(controller_factory_override_->GetProcessInterval()), last_report_block_time_(Timestamp::ms(DepLibUV::GetTimeMsInt64())), @@ -143,6 +144,12 @@ void RtpTransportControllerSend::RegisterTargetTransferRateObserver( MaybeCreateControllers(); } +void RtpTransportControllerSend::RegisterBweStatsTracer(webrtc::BweStatsTracer* tracer) { + MS_ASSERT(stats_tracer_ == nullptr, "stats_tracer already set"); + + stats_tracer_ = tracer; +} + void RtpTransportControllerSend::OnNetworkAvailability(bool network_available) { MS_DEBUG_DEV("<<<<< network_available:%s", network_available ? "true" : "false"); @@ -242,6 +249,7 @@ void RtpTransportControllerSend::OnTransportFeedback( PostUpdates(controller_->OnTransportPacketsFeedback(*feedback_msg)); pacer_.UpdateOutstandingData( transport_feedback_adapter_.GetOutstandingData().bytes()); + stats_tracer_->OnBweStats(controller_->GetBweStats()); } void RtpTransportControllerSend::OnRemoteNetworkEstimate( diff --git a/worker/deps/libwebrtc/libwebrtc/call/rtp_transport_controller_send.h b/worker/deps/libwebrtc/libwebrtc/call/rtp_transport_controller_send.h index 7ffc321717..696abb34b5 100644 --- a/worker/deps/libwebrtc/libwebrtc/call/rtp_transport_controller_send.h +++ b/worker/deps/libwebrtc/libwebrtc/call/rtp_transport_controller_send.h @@ -61,6 +61,8 @@ class RtpTransportControllerSend final void SetPacingFactor(float pacing_factor) override; void RegisterTargetTransferRateObserver( TargetTransferRateObserver* observer) override; + void RegisterBweStatsTracer( + BweStatsTracer* tracer) override; void OnNetworkAvailability(bool network_available) override; RtcpBandwidthObserver* GetBandwidthObserver() override; void EnablePeriodicAlrProbing(bool enable) override; @@ -102,6 +104,8 @@ class RtpTransportControllerSend final TargetTransferRateObserver* observer_; + BweStatsTracer* stats_tracer_; + NetworkControllerFactoryInterface* const controller_factory_override_; TransportFeedbackAdapter transport_feedback_adapter_; diff --git a/worker/deps/libwebrtc/libwebrtc/call/rtp_transport_controller_send_interface.h b/worker/deps/libwebrtc/libwebrtc/call/rtp_transport_controller_send_interface.h index 1575f45b78..9bdbfa4dac 100644 --- a/worker/deps/libwebrtc/libwebrtc/call/rtp_transport_controller_send_interface.h +++ b/worker/deps/libwebrtc/libwebrtc/call/rtp_transport_controller_send_interface.h @@ -36,6 +36,7 @@ struct NetworkRoute; namespace webrtc { class TargetTransferRateObserver; +class BweStatsTracer; class Transport; class PacedSender; class PacketFeedbackObserver; @@ -99,6 +100,8 @@ class RtpTransportControllerSendInterface { // PacketFeedbackObserver* observer) = 0; virtual void RegisterTargetTransferRateObserver( TargetTransferRateObserver* observer) = 0; + virtual void RegisterBweStatsTracer( + BweStatsTracer* tracer) = 0; virtual void OnNetworkAvailability(bool network_available) = 0; virtual RtcpBandwidthObserver* GetBandwidthObserver() = 0; virtual void EnablePeriodicAlrProbing(bool enable) = 0; diff --git a/worker/deps/libwebrtc/libwebrtc/modules/bitrate_controller/loss_based_bandwidth_estimation.cc b/worker/deps/libwebrtc/libwebrtc/modules/bitrate_controller/loss_based_bandwidth_estimation.cc index b434510b99..988ce204cf 100644 --- a/worker/deps/libwebrtc/libwebrtc/modules/bitrate_controller/loss_based_bandwidth_estimation.cc +++ b/worker/deps/libwebrtc/libwebrtc/modules/bitrate_controller/loss_based_bandwidth_estimation.cc @@ -8,10 +8,11 @@ * be found in the AUTHORS file in the root of the source tree. */ +#include "absl/strings/match.h" #include "modules/bitrate_controller/loss_based_bandwidth_estimation.h" +#include "api/transport/webrtc_key_value_config.h" #include "api/units/data_rate.h" #include "api/units/time_delta.h" -#include "system_wrappers/source/field_trial.h" #include #include @@ -21,6 +22,10 @@ namespace webrtc { namespace { const char kBweLossBasedControl[] = "WebRTC-Bwe-LossBasedControl"; +// Expecting RTCP feedback to be sent with roughly 1s intervals, a 5s gap +// indicates a channel outage. +constexpr TimeDelta kMaxRtcpFeedbackInterval = TimeDelta::Millis<5000>(); + // Increase slower when RTT is high. double GetIncreaseFactor(const LossBasedControlConfig& config, TimeDelta rtt) { // Clamp the RTT @@ -70,10 +75,16 @@ double ExponentialUpdate(TimeDelta window, TimeDelta interval) { return 1.0f - exp(interval / window * -1.0); } +bool IsEnabled(const WebRtcKeyValueConfig* key_value_config, + absl::string_view name) { + return key_value_config->Lookup(name).find("Enabled") == 0; +} + } // namespace -LossBasedControlConfig::LossBasedControlConfig() - : enabled(field_trial::IsEnabled(kBweLossBasedControl)), +LossBasedControlConfig::LossBasedControlConfig( + const WebRtcKeyValueConfig* key_value_config) + : enabled(IsEnabled(key_value_config, kBweLossBasedControl)), min_increase_factor("min_incr", 1.02), max_increase_factor("max_incr", 1.08), increase_low_rtt("incr_low_rtt", TimeDelta::ms(200)), @@ -85,26 +96,27 @@ LossBasedControlConfig::LossBasedControlConfig() increase_offset("incr_offset", DataRate::bps(1000)), loss_bandwidth_balance_increase("balance_incr", DataRate::kbps(0.5)), loss_bandwidth_balance_decrease("balance_decr", DataRate::kbps(4)), + loss_bandwidth_balance_reset("balance_reset", DataRate::kbps(0.1)), loss_bandwidth_balance_exponent("exponent", 0.5), allow_resets("resets", false), decrease_interval("decr_intvl", TimeDelta::ms(300)), loss_report_timeout("timeout", TimeDelta::ms(6000)) { - std::string trial_string = field_trial::FindFullName(kBweLossBasedControl); ParseFieldTrial( {&min_increase_factor, &max_increase_factor, &increase_low_rtt, &increase_high_rtt, &decrease_factor, &loss_window, &loss_max_window, &acknowledged_rate_max_window, &increase_offset, &loss_bandwidth_balance_increase, &loss_bandwidth_balance_decrease, - &loss_bandwidth_balance_exponent, &allow_resets, &decrease_interval, - &loss_report_timeout}, - trial_string); + &loss_bandwidth_balance_reset, &loss_bandwidth_balance_exponent, + &allow_resets, &decrease_interval, &loss_report_timeout}, + key_value_config->Lookup(kBweLossBasedControl)); } LossBasedControlConfig::LossBasedControlConfig(const LossBasedControlConfig&) = default; LossBasedControlConfig::~LossBasedControlConfig() = default; -LossBasedBandwidthEstimation::LossBasedBandwidthEstimation() - : config_(LossBasedControlConfig()), +LossBasedBandwidthEstimation::LossBasedBandwidthEstimation( + const WebRtcKeyValueConfig* key_value_config) + : config_(key_value_config), average_loss_(0), average_loss_max_(0), loss_based_bitrate_(DataRate::Zero()), @@ -161,9 +173,14 @@ void LossBasedBandwidthEstimation::UpdateAcknowledgedBitrate( } } -void LossBasedBandwidthEstimation::Update(Timestamp at_time, - DataRate min_bitrate, - TimeDelta last_round_trip_time) { +DataRate LossBasedBandwidthEstimation::Update(Timestamp at_time, + DataRate min_bitrate, + DataRate wanted_bitrate, + TimeDelta last_round_trip_time) { + if (loss_based_bitrate_.IsZero()) { + loss_based_bitrate_ = wanted_bitrate; + } + // Only increase if loss has been low for some time. const double loss_estimate_for_increase = average_loss_max_; // Avoid multiple decreases from averaging over one loss spike. @@ -173,8 +190,15 @@ void LossBasedBandwidthEstimation::Update(Timestamp at_time, !has_decreased_since_last_loss_report_ && (at_time - time_last_decrease_ >= last_round_trip_time + config_.decrease_interval); + // If packet lost reports are too old, dont increase bitrate. + const bool loss_report_valid = + at_time - last_loss_packet_report_ < 1.2 * kMaxRtcpFeedbackInterval; - if (loss_estimate_for_increase < loss_increase_threshold()) { + if (loss_report_valid && config_.allow_resets && + loss_estimate_for_increase < loss_reset_threshold()) { + loss_based_bitrate_ = wanted_bitrate; + } else if (loss_report_valid && + loss_estimate_for_increase < loss_increase_threshold()) { // Increase bitrate by RTT-adaptive ratio. DataRate new_increased_bitrate = min_bitrate * GetIncreaseFactor(config_, last_round_trip_time) + @@ -200,14 +224,21 @@ void LossBasedBandwidthEstimation::Update(Timestamp at_time, loss_based_bitrate_ = new_decreased_bitrate; } } + return loss_based_bitrate_; } -void LossBasedBandwidthEstimation::Reset(DataRate bitrate) { +void LossBasedBandwidthEstimation::Initialize(DataRate bitrate) { loss_based_bitrate_ = bitrate; average_loss_ = 0; average_loss_max_ = 0; } +double LossBasedBandwidthEstimation::loss_reset_threshold() const { + return LossFromBitrate(loss_based_bitrate_, + config_.loss_bandwidth_balance_reset, + config_.loss_bandwidth_balance_exponent); +} + double LossBasedBandwidthEstimation::loss_increase_threshold() const { return LossFromBitrate(loss_based_bitrate_, config_.loss_bandwidth_balance_increase, @@ -223,14 +254,4 @@ double LossBasedBandwidthEstimation::loss_decrease_threshold() const { DataRate LossBasedBandwidthEstimation::decreased_bitrate() const { return config_.decrease_factor * acknowledged_bitrate_max_; } - -void LossBasedBandwidthEstimation::MaybeReset(DataRate bitrate) { - if (config_.allow_resets) - Reset(bitrate); -} - -void LossBasedBandwidthEstimation::SetInitialBitrate(DataRate bitrate) { - Reset(bitrate); -} - } // namespace webrtc diff --git a/worker/deps/libwebrtc/libwebrtc/modules/bitrate_controller/loss_based_bandwidth_estimation.h b/worker/deps/libwebrtc/libwebrtc/modules/bitrate_controller/loss_based_bandwidth_estimation.h index 015c74505c..06948d4e38 100644 --- a/worker/deps/libwebrtc/libwebrtc/modules/bitrate_controller/loss_based_bandwidth_estimation.h +++ b/worker/deps/libwebrtc/libwebrtc/modules/bitrate_controller/loss_based_bandwidth_estimation.h @@ -16,13 +16,15 @@ #include "api/units/time_delta.h" #include "api/units/timestamp.h" #include "rtc_base/experiments/field_trial_parser.h" +#include "api/transport/webrtc_key_value_config.h" + #include namespace webrtc { struct LossBasedControlConfig { - LossBasedControlConfig(); + explicit LossBasedControlConfig(const WebRtcKeyValueConfig* key_value_config); LossBasedControlConfig(const LossBasedControlConfig&); LossBasedControlConfig& operator=(const LossBasedControlConfig&) = default; ~LossBasedControlConfig(); @@ -38,23 +40,34 @@ struct LossBasedControlConfig { FieldTrialParameter increase_offset; FieldTrialParameter loss_bandwidth_balance_increase; FieldTrialParameter loss_bandwidth_balance_decrease; + FieldTrialParameter loss_bandwidth_balance_reset; FieldTrialParameter loss_bandwidth_balance_exponent; FieldTrialParameter allow_resets; FieldTrialParameter decrease_interval; FieldTrialParameter loss_report_timeout; }; +// Estimates an upper BWE limit based on loss. +// It requires knowledge about lost packets and acknowledged bitrate. +// Ie, this class require transport feedback. class LossBasedBandwidthEstimation { public: - LossBasedBandwidthEstimation(); - void Update(Timestamp at_time, - DataRate min_bitrate, - TimeDelta last_round_trip_time); + explicit LossBasedBandwidthEstimation( + const WebRtcKeyValueConfig* key_value_config); + // Returns the new estimate. + DataRate Update(Timestamp at_time, + DataRate min_bitrate, + DataRate wanted_bitrate, + TimeDelta last_round_trip_time); void UpdateAcknowledgedBitrate(DataRate acknowledged_bitrate, Timestamp at_time); - void MaybeReset(DataRate bitrate); - void SetInitialBitrate(DataRate bitrate); + void Initialize(DataRate bitrate); bool Enabled() const { return config_.enabled; } + // Returns true if LossBasedBandwidthEstimation is enabled and have + // received loss statistics. Ie, this class require transport feedback. + bool InUse() const { + return Enabled() && last_loss_packet_report_.IsFinite(); + } void UpdateLossStatistics(const std::vector& packet_results, Timestamp at_time); DataRate GetEstimate() const { return loss_based_bitrate_; } @@ -64,9 +77,11 @@ class LossBasedBandwidthEstimation { void Reset(DataRate bitrate); double loss_increase_threshold() const; double loss_decrease_threshold() const; + double loss_reset_threshold() const; + DataRate decreased_bitrate() const; - LossBasedControlConfig config_; + const LossBasedControlConfig config_; double average_loss_; double average_loss_max_; DataRate loss_based_bitrate_; diff --git a/worker/deps/libwebrtc/libwebrtc/modules/bitrate_controller/loss_based_bwe_v2.cc b/worker/deps/libwebrtc/libwebrtc/modules/bitrate_controller/loss_based_bwe_v2.cc new file mode 100644 index 0000000000..d5af11a137 --- /dev/null +++ b/worker/deps/libwebrtc/libwebrtc/modules/bitrate_controller/loss_based_bwe_v2.cc @@ -0,0 +1,1252 @@ +/* + * Copyright 2021 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. + */ +#define MS_CLASS "webrtc::LossBasedBweV2" +// #define MS_LOG_DEV_LEVEL 3 + +#include "modules/bitrate_controller/loss_based_bwe_v2.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "absl/algorithm/container.h" +#include "absl/types/optional.h" +// #include "api/field_trials_view.h" +#include "api/network_state_predictor.h" +#include "api/transport/network_types.h" +#include "api/units/data_rate.h" +#include "api/units/data_size.h" +#include "api/units/time_delta.h" +#include "api/units/timestamp.h" +#include "modules/remote_bitrate_estimator/include/bwe_defines.h" +#include "rtc_base/experiments/field_trial_list.h" +#include "rtc_base/experiments/field_trial_parser.h" + +#include "DepLibUV.hpp" +#include "Logger.hpp" + +namespace webrtc { + +namespace { + +bool IsValid(DataRate datarate) { + return datarate.IsFinite(); +} + +bool IsValid(absl::optional datarate) { + return datarate.has_value() && IsValid(datarate.value()); +} + +bool IsValid(Timestamp timestamp) { + return timestamp.IsFinite(); +} + +struct PacketResultsSummary { + int num_packets = 0; + int num_lost_packets = 0; + DataSize total_size = DataSize::Zero(); + Timestamp first_send_time = Timestamp::PlusInfinity(); + Timestamp last_send_time = Timestamp::MinusInfinity(); +}; + +// Returns a `PacketResultsSummary` where `first_send_time` is `PlusInfinity, +// and `last_send_time` is `MinusInfinity`, if `packet_results` is empty. +PacketResultsSummary GetPacketResultsSummary( + std::vector packet_results) { + PacketResultsSummary packet_results_summary; + + packet_results_summary.num_packets = packet_results.size(); + for (const PacketResult& packet : packet_results) { + if (!packet.IsReceived()) { + packet_results_summary.num_lost_packets++; + } + packet_results_summary.total_size += packet.sent_packet.size; + packet_results_summary.first_send_time = std::min( + packet_results_summary.first_send_time, packet.sent_packet.send_time); + packet_results_summary.last_send_time = std::max( + packet_results_summary.last_send_time, packet.sent_packet.send_time); + } + + return packet_results_summary; +} + +double GetLossProbability(double inherent_loss, + DataRate loss_limited_bandwidth, + DataRate sending_rate) { + if (inherent_loss < 0.0 || inherent_loss > 1.0) { + MS_WARN_TAG(bwe, "Terent loss must be in [0,1]: %f", inherent_loss); + inherent_loss = std::min(std::max(inherent_loss, 0.0), 1.0); + } + if (!sending_rate.IsFinite()) { + MS_WARN_TAG(bwe, "The sending rate must be finite: %" PRIi64 "", sending_rate.bps()); + } + if (!loss_limited_bandwidth.IsFinite()) { + MS_WARN_TAG(bwe, "The loss limited bandwidth must be finite: %" PRIi64 "", loss_limited_bandwidth.bps()); + } + + double loss_probability = inherent_loss; + if (IsValid(sending_rate) && IsValid(loss_limited_bandwidth) && + (sending_rate > loss_limited_bandwidth)) { + loss_probability += (1 - inherent_loss) * + (sending_rate - loss_limited_bandwidth) / sending_rate; + } + return std::min(std::max(loss_probability, 1.0e-6), 1.0 - 1.0e-6); +} + +} // namespace + +LossBasedBweV2::LossBasedBweV2(const WebRtcKeyValueConfig* key_value_config) + : config_(CreateConfig(key_value_config)) { + if (!config_.has_value()) { + MS_WARN_TAG(bwe, "The configuration does not specify that the estimator should be enabled, disabling it."); + return; + } + if (!IsConfigValid()) { + MS_WARN_TAG(bwe,"The configuration is not valid, disabling the estimator."); + config_.reset(); + return; + } + + current_estimate_.inherent_loss = config_->initial_inherent_loss_estimate; + observations_.resize(config_->observation_window_size); + temporal_weights_.resize(config_->observation_window_size); + instant_upper_bound_temporal_weights_.resize( + config_->observation_window_size); + CalculateTemporalWeights(); +} + +void LossBasedBweV2::Reset() { + acknowledged_bitrate_ = absl::nullopt; + + current_estimate_.inherent_loss = config_->initial_inherent_loss_estimate; + current_estimate_.loss_limited_bandwidth = max_bitrate_; + + observations_.clear(); + temporal_weights_.clear(); + instant_upper_bound_temporal_weights_.clear(); + + observations_.resize(config_->observation_window_size); + temporal_weights_.resize(config_->observation_window_size); + instant_upper_bound_temporal_weights_.resize( + config_->observation_window_size); + + CalculateTemporalWeights(); + + num_observations_ = 0; + + partial_observation_.num_lost_packets = 0; + partial_observation_.num_packets = 0; + partial_observation_.size = DataSize::Zero(); + + last_send_time_most_recent_observation_ = Timestamp::PlusInfinity(); + last_time_estimate_reduced_ = Timestamp::MinusInfinity(); + + cached_instant_upper_bound_ = absl::nullopt; + delay_detector_states_.clear(); + recovering_after_loss_timestamp_ = Timestamp::MinusInfinity(); + bandwidth_limit_in_current_window_ = DataRate::PlusInfinity(); + current_state_ = LossBasedState::kDelayBasedEstimate; + probe_bitrate_ = DataRate::PlusInfinity(); + delay_based_estimate_ = DataRate::PlusInfinity(); + upper_link_capacity_ = DataRate::PlusInfinity(); + + instant_loss_debounce_counter_ = 0; + kInstantLossDebounceDuration = TimeDelta::seconds(2); + instant_loss_debounce_start_ = Timestamp::MinusInfinity(); + instant_loss_threshold_ = Timestamp::MinusInfinity(); +} + +bool LossBasedBweV2::IsEnabled() const { + // MS_DEBUG_DEV("Loss V2 is Enabled: %d ", config_.has_value()); + return config_.has_value(); +} + +bool LossBasedBweV2::IsReady() const { + return IsEnabled() && IsValid(current_estimate_.loss_limited_bandwidth) && + num_observations_ > 0; +} + +LossBasedBweV2::Result LossBasedBweV2::GetLossBasedResult() { + Result result; + result.state = current_state_; + if (!IsReady()) { + if (!IsEnabled()) { + MS_WARN_TAG(bwe, "The estimator must be enabled before it can be used."); + } else { + if (!IsValid(current_estimate_.loss_limited_bandwidth)) { + MS_WARN_TAG(bwe, "The estimator must be initialized before it can be used."); + } + if (num_observations_ <= 0) { + MS_WARN_TAG(bwe, "The estimator must receive enough loss statistics before it can be used."); + } + } + result.bandwidth_estimate = IsValid(delay_based_estimate_) + ? delay_based_estimate_ + : DataRate::PlusInfinity(); + return result; + } + + auto instant_limit = GetInstantUpperBound(); +/* MS_DEBUG_DEV("Using %s, Inherent Loss limit %f, %" PRIi64 ", Delay limit %" PRIi64 ", Instant Loss limit %" PRIi64 ",average loss ratio is %f, acknowledged bitrate %" PRIi64 "", + current_estimate_.loss_limited_bandwidth.bps() <= delay_based_estimate_.bps() ? "Loss" : "Delay", + current_estimate_.inherent_loss, + current_estimate_.loss_limited_bandwidth.bps(), + delay_based_estimate_.IsFinite() ? delay_based_estimate_.bps() : 0, + instant_limit.IsFinite() ? instant_limit.bps() : 0, + GetAverageReportedLossRatio(), + IsValid(acknowledged_bitrate_) ? acknowledged_bitrate_->bps() : -1);*/ + if (instant_loss_debounce_stop_.IsFinite() && (DepLibUV::GetTimeMsInt64() - instant_loss_debounce_stop_.ms()) < 500) { + auto decreased_rate = rate_before_last_instant_loss_ * 0.85; + MS_DEBUG_DEV("recently recovered from instant loss [rate_before_loss: %lld, recover_rate: %lld]", + rate_before_last_instant_loss_.bps(), + decreased_rate.bps() + ); + + result.bandwidth_estimate = decreased_rate; + current_estimate_.loss_limited_bandwidth = decreased_rate; + return result; + } else if (instant_loss_debounce_stop_.IsFinite() && (DepLibUV::GetTimeMsInt64() - instant_loss_debounce_stop_.ms()) > 500) { + instant_loss_debounce_stop_ = Timestamp::MinusInfinity(); + } + + if (IsValid(delay_based_estimate_)) { + result.bandwidth_estimate = + std::min({current_estimate_.loss_limited_bandwidth, + instant_limit, delay_based_estimate_}); + } else { + result.bandwidth_estimate = std::min( + current_estimate_.loss_limited_bandwidth, instant_limit); + } + return result; +} + +void LossBasedBweV2::SetAcknowledgedBitrate(DataRate acknowledged_bitrate) { + if (IsValid(acknowledged_bitrate)) { + acknowledged_bitrate_ = acknowledged_bitrate; + } else { + MS_WARN_TAG(bwe, "The acknowledged bitrate must be finite: %" PRIi64 "", acknowledged_bitrate.bps()); + } +} + +void LossBasedBweV2::SetBandwidthEstimate(DataRate bandwidth_estimate) { + if (IsValid(bandwidth_estimate)) { + current_estimate_.loss_limited_bandwidth = bandwidth_estimate; + } else { + MS_WARN_TAG(bwe, "The bandwidth estimate must be finite: %" PRIi64 "", bandwidth_estimate.bps()); + } +} + +void LossBasedBweV2::SetMinMaxBitrate(DataRate min_bitrate, + DataRate max_bitrate) { + if (IsValid(min_bitrate)) { + min_bitrate_ = min_bitrate; + } else { + MS_WARN_TAG(bwe, "The min bitrate must be finite: %" PRIi64 "", min_bitrate.bps()); + } + + if (IsValid(max_bitrate)) { + max_bitrate_ = max_bitrate; + } else { + MS_WARN_TAG(bwe, "The max bitrate must be finite: %" PRIi64 "", max_bitrate.bps()); + } +} + +void LossBasedBweV2::SetProbeBitrate(absl::optional probe_bitrate) { + if (probe_bitrate.has_value() && IsValid(probe_bitrate.value())) { + if (!IsValid(probe_bitrate_) || probe_bitrate_ > probe_bitrate.value()) { + MS_DEBUG_DEV("Probe bitrate = %lld", probe_bitrate.value().bps()); + probe_bitrate_ = probe_bitrate.value(); + } + } +} + +void LossBasedBweV2::UpdateBandwidthEstimate( + std::vector packet_results, + DataRate delay_based_estimate, + BandwidthUsage delay_detector_state, + absl::optional probe_bitrate, + DataRate upper_link_capacity) { + delay_based_estimate_ = delay_based_estimate; + upper_link_capacity_ = upper_link_capacity; + if (!IsEnabled()) { + MS_WARN_TAG(bwe, "The estimator must be enabled before it can be used."); + return; + } + SetProbeBitrate(probe_bitrate); + if (packet_results.empty()) { + MS_WARN_TAG(bwe, "The estimate cannot be updated without any loss statistics."); + return; + } + + if (!PushBackObservation(packet_results, delay_detector_state)) { + return; + } + + if (!IsValid(current_estimate_.loss_limited_bandwidth)) { + MS_WARN_TAG(bwe, "The estimator must be initialized before it can be used."); + return; + } + + ChannelParameters best_candidate = current_estimate_; + double objective_max = std::numeric_limits::lowest(); + for (ChannelParameters candidate : GetCandidates()) { + NewtonsMethodUpdate(candidate); + + const double candidate_objective = GetObjective(candidate); + if (candidate_objective > objective_max) { + objective_max = candidate_objective; + best_candidate = candidate; + } + } + if (best_candidate.loss_limited_bandwidth < + current_estimate_.loss_limited_bandwidth) { + last_time_estimate_reduced_ = last_send_time_most_recent_observation_; + } + + // Do not increase the estimate if the average loss is greater than current + // inherent loss. + if (GetAverageReportedLossRatio() > best_candidate.inherent_loss && + config_->not_increase_if_inherent_loss_less_than_average_loss && + current_estimate_.loss_limited_bandwidth < + best_candidate.loss_limited_bandwidth) { + best_candidate.loss_limited_bandwidth = + current_estimate_.loss_limited_bandwidth; + } + +/* if (IsValid(delay_based_estimate_) && current_estimate_.inherent_loss > config_->inherent_loss_upper_bound_offset) { + best_candidate.loss_limited_bandwidth = delay_based_estimate_; + }*/ + + if (IsBandwidthLimitedDueToLoss()) { + // Bound the estimate increase if: + // 1. The estimate has been increased for less than + // `delayed_increase_window` ago, and + // 2. The best candidate is greater than bandwidth_limit_in_current_window. + if (recovering_after_loss_timestamp_.IsFinite() && + recovering_after_loss_timestamp_ + config_->delayed_increase_window > + last_send_time_most_recent_observation_ && + best_candidate.loss_limited_bandwidth > + bandwidth_limit_in_current_window_) { + best_candidate.loss_limited_bandwidth = + bandwidth_limit_in_current_window_; + } + + bool increasing_when_loss_limited = + IsEstimateIncreasingWhenLossLimited(best_candidate); + // Bound the best candidate by the acked bitrate unless there is a recent + // probe result. + if (increasing_when_loss_limited && !IsValid(probe_bitrate_) && + IsValid(acknowledged_bitrate_)) { + best_candidate.loss_limited_bandwidth = + IsValid(best_candidate.loss_limited_bandwidth) + ? std::min(best_candidate.loss_limited_bandwidth, + config_->bandwidth_rampup_upper_bound_factor * + (*acknowledged_bitrate_)) + : config_->bandwidth_rampup_upper_bound_factor * + (*acknowledged_bitrate_); + } + + // Use probe bitrate as the estimate as probe bitrate is trusted to be + // correct. After being used, the probe bitrate is reset. + if (config_->probe_integration_enabled && IsValid(probe_bitrate_)) { + best_candidate.loss_limited_bandwidth = + std::min(probe_bitrate_, best_candidate.loss_limited_bandwidth); + probe_bitrate_ = DataRate::MinusInfinity(); + } + } + + if (IsEstimateIncreasingWhenLossLimited(best_candidate) && + best_candidate.loss_limited_bandwidth < delay_based_estimate) { + current_state_ = LossBasedState::kIncreasing; + } else if (best_candidate.loss_limited_bandwidth < delay_based_estimate_) { + current_state_ = LossBasedState::kDecreasing; + } else if (best_candidate.loss_limited_bandwidth >= delay_based_estimate_) { + current_state_ = LossBasedState::kDelayBasedEstimate; + } + current_estimate_ = best_candidate; + + if (IsBandwidthLimitedDueToLoss() && + (recovering_after_loss_timestamp_.IsInfinite() || + recovering_after_loss_timestamp_ + config_->delayed_increase_window < + last_send_time_most_recent_observation_)) { + bandwidth_limit_in_current_window_ = + std::max(kCongestionControllerMinBitrate, + current_estimate_.loss_limited_bandwidth * + config_->max_increase_factor); + recovering_after_loss_timestamp_ = last_send_time_most_recent_observation_; + } +} + +bool LossBasedBweV2::IsEstimateIncreasingWhenLossLimited( + const ChannelParameters& best_candidate) +{ + return (current_estimate_.loss_limited_bandwidth < best_candidate.loss_limited_bandwidth || + (current_estimate_.loss_limited_bandwidth == best_candidate.loss_limited_bandwidth && + current_state_ == LossBasedState::kIncreasing)) && + IsBandwidthLimitedDueToLoss(); +} +// Returns a `LossBasedBweV2::Config` iff the `key_value_config` specifies a +// configuration for the `LossBasedBweV2` which is explicitly enabled. +absl::optional LossBasedBweV2::CreateConfig( + const WebRtcKeyValueConfig* key_value_config) +{ + FieldTrialParameter enabled("Enabled", true); + FieldTrialParameter bandwidth_rampup_upper_bound_factor( + "BwRampupUpperBoundFactor", 1000000.0); + FieldTrialParameter rampup_acceleration_max_factor("BwRampupAccelMaxFactor", 0.0); + FieldTrialParameter rampup_acceleration_maxout_time("BwRampupAccelMaxoutTime", TimeDelta::seconds(60)); + FieldTrialList candidate_factors("CandidateFactors", { 1.02, 1.0, 0.95 }); + FieldTrialParameter higher_bandwidth_bias_factor("HigherBwBiasFactor", 0.0002); + FieldTrialParameter higher_log_bandwidth_bias_factor("HigherLogBwBiasFactor", 0.02); + FieldTrialParameter inherent_loss_lower_bound("InherentLossLowerBound", 1.0e-3); + FieldTrialParameter loss_threshold_of_high_bandwidth_preference( + "LossThresholdOfHighBandwidthPreference", 0.15); + FieldTrialParameter bandwidth_preference_smoothing_factor( + "BandwidthPreferenceSmoothingFactor", 0.002); + FieldTrialParameter inherent_loss_upper_bound_bandwidth_balance( + "InherentLossUpperBoundBwBalance", DataRate::kbps(75.0)); + FieldTrialParameter inherent_loss_upper_bound_offset("InherentLossUpperBoundOffset", 0.03); + FieldTrialParameter initial_inherent_loss_estimate("InitialInherentLossEstimate", 0.01); + FieldTrialParameter newton_iterations("NewtonIterations", 1); + FieldTrialParameter newton_step_size("NewtonStepSize", 0.75); + FieldTrialParameter append_acknowledged_rate_candidate("AckedRateCandidate", true); + FieldTrialParameter append_delay_based_estimate_candidate("DelayBasedCandidate", true); + FieldTrialParameter observation_duration_lower_bound( + "ObservationDurationLowerBound", TimeDelta::ms(250)); + FieldTrialParameter observation_window_size("ObservationWindowSize", 50); + FieldTrialParameter sending_rate_smoothing_factor("SendingRateSmoothingFactor", 0.0); + FieldTrialParameter instant_upper_bound_temporal_weight_factor( + "InstantUpperBoundTemporalWeightFactor", 0.9); + FieldTrialParameter instant_upper_bound_bandwidth_balance( + "InstantUpperBoundBwBalance", DataRate::kbps(75.0)); + FieldTrialParameter instant_upper_bound_loss_offset("InstantUpperBoundLossOffset", 0.07); + FieldTrialParameter temporal_weight_factor("TemporalWeightFactor", 0.9); + FieldTrialParameter bandwidth_backoff_lower_bound_factor("BwBackoffLowerBoundFactor", 1.0); + FieldTrialParameter trendline_integration_enabled("TrendlineIntegrationEnabled", false); + FieldTrialParameter trendline_observations_window_size("TrendlineObservationsWindowSize", 5); + FieldTrialParameter max_increase_factor("MaxIncreaseFactor", 1.3); + FieldTrialParameter delayed_increase_window("DelayedIncreaseWindow", TimeDelta::ms(300)); + FieldTrialParameter use_acked_bitrate_only_when_overusing( + "UseAckedBitrateOnlyWhenOverusing", false); + FieldTrialParameter not_increase_if_inherent_loss_less_than_average_loss( + "NotIncreaseIfInherentLossLessThanAverageLoss", true); + FieldTrialParameter high_loss_rate_threshold("HighLossRateThreshold", 1.0); + FieldTrialParameter bandwidth_cap_at_high_loss_rate( + "BandwidthCapAtHighLossRate", DataRate::kbps(500.0)); + FieldTrialParameter slope_of_bwe_high_loss_func("SlopeOfBweHighLossFunc", 1000); + FieldTrialParameter probe_integration_enabled("ProbeIntegrationEnabled", false); + FieldTrialParameter bound_by_upper_link_capacity_when_loss_limited( + "BoundByUpperLinkCapacityWhenLossLimited", true); + if (key_value_config) { + ParseFieldTrial({&enabled, + &bandwidth_rampup_upper_bound_factor, + &rampup_acceleration_max_factor, + &rampup_acceleration_maxout_time, + &candidate_factors, + &higher_bandwidth_bias_factor, + &higher_log_bandwidth_bias_factor, + &inherent_loss_lower_bound, + &loss_threshold_of_high_bandwidth_preference, + &bandwidth_preference_smoothing_factor, + &inherent_loss_upper_bound_bandwidth_balance, + &inherent_loss_upper_bound_offset, + &initial_inherent_loss_estimate, + &newton_iterations, + &newton_step_size, + &append_acknowledged_rate_candidate, + &append_delay_based_estimate_candidate, + &observation_duration_lower_bound, + &observation_window_size, + &sending_rate_smoothing_factor, + &instant_upper_bound_temporal_weight_factor, + &instant_upper_bound_bandwidth_balance, + &instant_upper_bound_loss_offset, + &temporal_weight_factor, + &bandwidth_backoff_lower_bound_factor, + &trendline_integration_enabled, + &trendline_observations_window_size, + &max_increase_factor, + &delayed_increase_window, + &use_acked_bitrate_only_when_overusing, + ¬_increase_if_inherent_loss_less_than_average_loss, + &probe_integration_enabled, + &high_loss_rate_threshold, + &bandwidth_cap_at_high_loss_rate, + &slope_of_bwe_high_loss_func, + &bound_by_upper_link_capacity_when_loss_limited}, + key_value_config->Lookup("WebRTC-Bwe-LossBasedBweV2")); + } + + absl::optional config; + if (!enabled.Get()) { + return config; + } + config.emplace(); + config->bandwidth_rampup_upper_bound_factor = + bandwidth_rampup_upper_bound_factor.Get(); + config->rampup_acceleration_max_factor = rampup_acceleration_max_factor.Get(); + config->rampup_acceleration_maxout_time = + rampup_acceleration_maxout_time.Get(); + config->candidate_factors = candidate_factors.Get(); + config->higher_bandwidth_bias_factor = higher_bandwidth_bias_factor.Get(); + config->higher_log_bandwidth_bias_factor = + higher_log_bandwidth_bias_factor.Get(); + config->inherent_loss_lower_bound = inherent_loss_lower_bound.Get(); + config->loss_threshold_of_high_bandwidth_preference = + loss_threshold_of_high_bandwidth_preference.Get(); + config->bandwidth_preference_smoothing_factor = + bandwidth_preference_smoothing_factor.Get(); + config->inherent_loss_upper_bound_bandwidth_balance = + inherent_loss_upper_bound_bandwidth_balance.Get(); + config->inherent_loss_upper_bound_offset = + inherent_loss_upper_bound_offset.Get(); + config->initial_inherent_loss_estimate = initial_inherent_loss_estimate.Get(); + config->newton_iterations = newton_iterations.Get(); + config->newton_step_size = newton_step_size.Get(); + config->append_acknowledged_rate_candidate = + append_acknowledged_rate_candidate.Get(); + config->append_delay_based_estimate_candidate = + append_delay_based_estimate_candidate.Get(); + config->observation_duration_lower_bound = + observation_duration_lower_bound.Get(); + config->observation_window_size = observation_window_size.Get(); + config->sending_rate_smoothing_factor = sending_rate_smoothing_factor.Get(); + config->instant_upper_bound_temporal_weight_factor = + instant_upper_bound_temporal_weight_factor.Get(); + config->instant_upper_bound_bandwidth_balance = + instant_upper_bound_bandwidth_balance.Get(); + config->instant_upper_bound_loss_offset = + instant_upper_bound_loss_offset.Get(); + config->temporal_weight_factor = temporal_weight_factor.Get(); + config->bandwidth_backoff_lower_bound_factor = + bandwidth_backoff_lower_bound_factor.Get(); + config->trendline_integration_enabled = trendline_integration_enabled.Get(); + config->trendline_observations_window_size = + trendline_observations_window_size.Get(); + config->max_increase_factor = max_increase_factor.Get(); + config->delayed_increase_window = delayed_increase_window.Get(); + config->use_acked_bitrate_only_when_overusing = + use_acked_bitrate_only_when_overusing.Get(); + config->not_increase_if_inherent_loss_less_than_average_loss = + not_increase_if_inherent_loss_less_than_average_loss.Get(); + config->high_loss_rate_threshold = high_loss_rate_threshold.Get(); + config->bandwidth_cap_at_high_loss_rate = + bandwidth_cap_at_high_loss_rate.Get(); + config->slope_of_bwe_high_loss_func = slope_of_bwe_high_loss_func.Get(); + config->probe_integration_enabled = probe_integration_enabled.Get(); + config->bound_by_upper_link_capacity_when_loss_limited = + bound_by_upper_link_capacity_when_loss_limited.Get(); + + + std::string candidate_factors_str; + + MS_DEBUG_TAG(bwe, "Loss V2 settings: "); + MS_DEBUG_TAG(bwe, "Enabled: %d ", enabled.Get()); + MS_DEBUG_TAG(bwe, "bandwidth_rampup_upper_bound_factor: %f ", config->bandwidth_rampup_upper_bound_factor); + MS_DEBUG_TAG(bwe, "rampup_acceleration_max_factor: %f ", config->rampup_acceleration_max_factor); + MS_DEBUG_TAG(bwe, "rampup_acceleration_maxout_time: %" PRIi64 "", config->rampup_acceleration_maxout_time.ms()); + for (double candidate_factor : config->candidate_factors) { + MS_DEBUG_TAG(bwe, "candidate_factor: %f", candidate_factor); + } + MS_DEBUG_TAG(bwe, "higher_bandwidth_bias_factor: %f ", config->higher_bandwidth_bias_factor); + MS_DEBUG_TAG(bwe, "slope_of_bwe_high_loss_func: %f ", config->slope_of_bwe_high_loss_func); + MS_DEBUG_TAG(bwe, "slope_of_bwe_high_loss_func: %f ", config->slope_of_bwe_high_loss_func); + MS_DEBUG_TAG(bwe, "higher_log_bandwidth_bias_factor: %f ", config->higher_log_bandwidth_bias_factor); + MS_DEBUG_TAG(bwe, "inherent_loss_lower_bound: %f ", config->inherent_loss_lower_bound); + MS_DEBUG_TAG(bwe, "loss_threshold_of_high_bandwidth_preference: %f ", config->loss_threshold_of_high_bandwidth_preference); + MS_DEBUG_TAG(bwe, "bandwidth_preference_smoothing_factor: %f ", config->bandwidth_preference_smoothing_factor); + MS_DEBUG_TAG(bwe, "inherent_loss_upper_bound_bandwidth_balance: %" PRIi64 "", config->inherent_loss_upper_bound_bandwidth_balance.bps()); + MS_DEBUG_TAG(bwe, "inherent_loss_upper_bound_offset: %f ", config->inherent_loss_upper_bound_offset); + MS_DEBUG_TAG(bwe, "initial_inherent_loss_estimate: %f ", config->initial_inherent_loss_estimate); + MS_DEBUG_TAG(bwe, "newton_iterations: %d ", config->newton_iterations); + MS_DEBUG_TAG(bwe, "newton_step_size: %f ", config->newton_step_size); + MS_DEBUG_TAG(bwe, "append_acknowledged_rate_candidate: %d ", config->append_acknowledged_rate_candidate); + MS_DEBUG_TAG(bwe, "append_delay_based_estimate_candidate: %d ", config->append_delay_based_estimate_candidate); + MS_DEBUG_TAG(bwe, "observation_duration_lower_bound: %" PRIi64 "", config->observation_duration_lower_bound.ms()); + MS_DEBUG_TAG(bwe, "observation_window_size: %d ", config->observation_window_size); + MS_DEBUG_TAG(bwe, "sending_rate_smoothing_factor: %f ", config->sending_rate_smoothing_factor); + MS_DEBUG_TAG(bwe, "instant_upper_bound_temporal_weight_factor: %f ", config->instant_upper_bound_temporal_weight_factor); + MS_DEBUG_TAG(bwe, "instant_upper_bound_bandwidth_balance: %" PRIi64 "", config->instant_upper_bound_bandwidth_balance.bps()); + MS_DEBUG_TAG(bwe, "instant_upper_bound_loss_offset: %f ", config->instant_upper_bound_loss_offset); + MS_DEBUG_TAG(bwe, "temporal_weight_factor: %f ", config->temporal_weight_factor); + MS_DEBUG_TAG(bwe, "bandwidth_backoff_lower_bound_factor: %f ", config->bandwidth_backoff_lower_bound_factor); + MS_DEBUG_TAG(bwe, "trendline_integration_enabled: %d ", config->trendline_integration_enabled); + MS_DEBUG_TAG(bwe, "trendline_observations_window_size: %d ", config->trendline_observations_window_size); + MS_DEBUG_TAG(bwe, "max_increase_factor: %f ", config->max_increase_factor); + MS_DEBUG_TAG(bwe, "delayed_increase_window: %" PRIi64 "", config->delayed_increase_window.ms()); + MS_DEBUG_TAG(bwe, "use_acked_bitrate_only_when_overusing: %d ", config->use_acked_bitrate_only_when_overusing); + MS_DEBUG_TAG(bwe, "not_increase_if_inherent_loss_less_than_average_loss: %d ", config->not_increase_if_inherent_loss_less_than_average_loss); + MS_DEBUG_TAG(bwe, "high_loss_rate_threshold: %f ", config->high_loss_rate_threshold); + MS_DEBUG_TAG(bwe, "bandwidth_cap_at_high_loss_rate: %" PRIi64 "", config->bandwidth_cap_at_high_loss_rate.bps()); + MS_DEBUG_TAG(bwe, "slope_of_bwe_high_loss_func: %f ", config->slope_of_bwe_high_loss_func); + + return config; +} + +bool LossBasedBweV2::IsConfigValid() const { + MS_DEBUG_DEV("Validating lossV2 config"); + if (!config_.has_value()) { + return false; + } + + bool valid = true; + + if (config_->bandwidth_rampup_upper_bound_factor <= 1.0) { + MS_WARN_TAG(bwe, "The bandwidth rampup upper bound factor must be greater than 1: %f", + config_->bandwidth_rampup_upper_bound_factor); + valid = false; + } + if (config_->rampup_acceleration_max_factor < 0.0) { + MS_WARN_TAG(bwe, "The rampup acceleration max factor must be non-negative.: %f", + config_->rampup_acceleration_max_factor); + valid = false; + } + if (config_->rampup_acceleration_maxout_time <= TimeDelta::Zero()) { + MS_WARN_TAG(bwe, "The rampup acceleration maxout time must be above zero: %" PRIi64 "", + config_->rampup_acceleration_maxout_time.seconds()); + valid = false; + } + for (double candidate_factor : config_->candidate_factors) { + if (candidate_factor <= 0.0) { + MS_WARN_TAG(bwe, "All candidate factors must be greater than zero: %f", candidate_factor); + valid = false; + } + } + + // Ensure that the configuration allows generation of at least one candidate + // other than the current estimate. + if (!config_->append_acknowledged_rate_candidate && + !config_->append_delay_based_estimate_candidate && + !absl::c_any_of(config_->candidate_factors, + [](double cf) { return cf != 1.0; })) { + MS_WARN_TAG(bwe, "The configuration does not allow generating candidates. Specify " + "a candidate factor other than 1.0, allow the acknowledged rate " + "to be a candidate, and/or allow the delay based estimate to be a " + "candidate."); + valid = false; + } + + if (config_->higher_bandwidth_bias_factor < 0.0) { + MS_WARN_TAG(bwe, "The higher bandwidth bias factor must be non-negative: %f", + config_->higher_bandwidth_bias_factor); + valid = false; + } + if (config_->inherent_loss_lower_bound < 0.0 || + config_->inherent_loss_lower_bound >= 1.0) { + MS_WARN_TAG(bwe, "The inherent loss lower bound must be in [0, 1] %f ", + config_->inherent_loss_lower_bound); + valid = false; + } + if (config_->loss_threshold_of_high_bandwidth_preference < 0.0 || + config_->loss_threshold_of_high_bandwidth_preference >= 1.0) { + MS_WARN_TAG(bwe, "The loss threshold of high bandwidth preference must be in [0, 1]: %f", + config_->loss_threshold_of_high_bandwidth_preference); + valid = false; + } + if (config_->bandwidth_preference_smoothing_factor <= 0.0 || + config_->bandwidth_preference_smoothing_factor > 1.0) { + MS_WARN_TAG(bwe, "The bandwidth preference smoothing factor must be in [0, 1]: %f", + config_->bandwidth_preference_smoothing_factor); + valid = false; + } + if (config_->inherent_loss_upper_bound_bandwidth_balance <= + DataRate::Zero()) { + MS_WARN_TAG(bwe, "The inherent loss upper bound bandwidth balance must be positive: %" PRIi64 "", + config_->inherent_loss_upper_bound_bandwidth_balance.bps()); + valid = false; + } + if (config_->inherent_loss_upper_bound_offset < + config_->inherent_loss_lower_bound || + config_->inherent_loss_upper_bound_offset >= 1.0) { + MS_WARN_TAG(bwe, "The inherent loss upper bound must be greater than or equal to the inherent " + "loss lower bound, which is %f, and less than 1: %f", + config_->inherent_loss_lower_bound, + config_->inherent_loss_upper_bound_offset); + valid = false; + } + if (config_->initial_inherent_loss_estimate < 0.0 || + config_->initial_inherent_loss_estimate >= 1.0) { + MS_WARN_TAG(bwe, "The initial inherent loss estimate must be in [0, 1]: %f", + config_->initial_inherent_loss_estimate); + valid = false; + } + if (config_->newton_iterations <= 0) { + MS_WARN_TAG(bwe, "The number of Newton iterations must be positive: %d", + config_->newton_iterations); + valid = false; + } + if (config_->newton_step_size <= 0.0) { + MS_WARN_TAG(bwe, "The Newton step size must be positive: %f", + config_->newton_step_size); + valid = false; + } + if (config_->observation_duration_lower_bound <= TimeDelta::Zero()) { + MS_WARN_TAG(bwe, "The observation duration lower bound must be positive: %" PRIi64 " ms", + config_->observation_duration_lower_bound.ms()); + valid = false; + } + if (config_->observation_window_size < 2) { + MS_WARN_TAG(bwe, "The observation window size must be at least 2: %d", + config_->observation_window_size); + valid = false; + } + if (config_->sending_rate_smoothing_factor < 0.0 || + config_->sending_rate_smoothing_factor >= 1.0) { + MS_WARN_TAG(bwe, "The sending rate smoothing factor must be in (0, 1): %f", + config_->sending_rate_smoothing_factor); + valid = false; + } + if (config_->instant_upper_bound_temporal_weight_factor <= 0.0 || + config_->instant_upper_bound_temporal_weight_factor > 1.0) { + MS_WARN_TAG(bwe, "The instant upper bound temporal weight factor must be in (0, 1] %f", + config_->instant_upper_bound_temporal_weight_factor); + valid = false; + } + if (config_->instant_upper_bound_bandwidth_balance <= DataRate::Zero()) { + MS_WARN_TAG(bwe, "The instant upper bound bandwidth balance must be positive: %" PRIi64 "", + config_->instant_upper_bound_bandwidth_balance.bps()); + valid = false; + } + if (config_->instant_upper_bound_loss_offset < 0.0 || + config_->instant_upper_bound_loss_offset >= 1.0) { + MS_WARN_TAG(bwe, "The instant upper bound loss offset must be in [0, 1): %f", + config_->instant_upper_bound_loss_offset); + valid = false; + } + if (config_->temporal_weight_factor <= 0.0 || + config_->temporal_weight_factor > 1.0) { + MS_WARN_TAG(bwe, "The temporal weight factor must be in (0, 1]: %f", + config_->temporal_weight_factor); + valid = false; + } + if (config_->bandwidth_backoff_lower_bound_factor > 1.0) { + MS_WARN_TAG(bwe, "The bandwidth backoff lower bound factor must not be greater than 1: %f", + config_->bandwidth_backoff_lower_bound_factor); + valid = false; + } + if (config_->trendline_observations_window_size < 1) { + MS_WARN_TAG(bwe, "The trendline window size must be at least 1: %d", + config_->trendline_observations_window_size); + valid = false; + } + if (config_->max_increase_factor <= 0.0) { + MS_WARN_TAG(bwe, "The maximum increase factor must be positive: %f", config_->max_increase_factor); + valid = false; + } + if (config_->delayed_increase_window <= TimeDelta::Zero()) { + MS_WARN_TAG(bwe, "The delayed increase window must be positive: %" PRIi64 " ms", + config_->delayed_increase_window.ms()); + valid = false; + } + if (config_->high_loss_rate_threshold <= 0.0 || + config_->high_loss_rate_threshold > 1.0) { + MS_WARN_TAG(bwe, "The high loss rate threshold must be in (0, 1]: %f", + config_->high_loss_rate_threshold); + valid = false; + } + return valid; +} + +LossEstimatorState LossBasedBweV2::GetState() const { + LossEstimatorState state; + state.inherent_loss = current_estimate_.inherent_loss; + state.avg_loss = GetAverageReportedLossRatio(); + state.bandwidth_estimate = current_estimate_.loss_limited_bandwidth; + state.sending_rate = last_sending_rate_.IsFinite() ? last_sending_rate_ : DataRate::bps(0); + return state; +} + +double LossBasedBweV2::GetAverageReportedLossRatio() const { + if (num_observations_ <= 0) { + return 0.0; + } + + double num_packets = 0; + double num_lost_packets = 0; + for (const Observation& observation : observations_) { + if (!observation.IsInitialized()) { + continue; + } + + double instant_temporal_weight = + instant_upper_bound_temporal_weights_[(num_observations_ - 1) - + observation.id]; + num_packets += instant_temporal_weight * observation.num_packets; + num_lost_packets += instant_temporal_weight * observation.num_lost_packets; + } + + return num_lost_packets / num_packets; +} + +DataRate LossBasedBweV2::GetCandidateBandwidthUpperBound() const { + DataRate candidate_bandwidth_upper_bound = max_bitrate_; + if (IsBandwidthLimitedDueToLoss() && + IsValid(bandwidth_limit_in_current_window_)) { + candidate_bandwidth_upper_bound = bandwidth_limit_in_current_window_; + } + + if (config_->trendline_integration_enabled) { + candidate_bandwidth_upper_bound = + std::min(GetInstantUpperBound(), candidate_bandwidth_upper_bound); + if (IsValid(delay_based_estimate_)) { + candidate_bandwidth_upper_bound = + std::min(delay_based_estimate_, candidate_bandwidth_upper_bound); + } + } + + if (!acknowledged_bitrate_.has_value()) + return candidate_bandwidth_upper_bound; + + if (config_->rampup_acceleration_max_factor > 0.0) { + const TimeDelta time_since_bandwidth_reduced = std::min( + config_->rampup_acceleration_maxout_time, + std::max(TimeDelta::Zero(), last_send_time_most_recent_observation_ - + last_time_estimate_reduced_)); + const double rampup_acceleration = config_->rampup_acceleration_max_factor * + time_since_bandwidth_reduced / + config_->rampup_acceleration_maxout_time; + + candidate_bandwidth_upper_bound += + rampup_acceleration * (*acknowledged_bitrate_); + } + return candidate_bandwidth_upper_bound; +} + +std::vector LossBasedBweV2::GetCandidates() + const { + std::vector bandwidths; + bool can_increase_bitrate = TrendlineEsimateAllowBitrateIncrease(); + for (double candidate_factor : config_->candidate_factors) { + if (!can_increase_bitrate && candidate_factor > 1.0) { + continue; + } + //MS_DEBUG_DEV("Pushing loss_limited_bandwidth candidate rate: %lld", (candidate_factor * current_estimate_.loss_limited_bandwidth).bps()); + bandwidths.push_back(candidate_factor * + current_estimate_.loss_limited_bandwidth); + } + +/* if (acknowledged_bitrate_.has_value() && + config_->append_acknowledged_rate_candidate && + TrendlineEsimateAllowEmergencyBackoff()) { + // MS_DEBUG_DEV("Pushing acknowledged_bitrate_ candidate rate: %lld", (*acknowledged_bitrate_ * config_->bandwidth_backoff_lower_bound_factor).bps()); + bandwidths.push_back(*acknowledged_bitrate_ * + config_->bandwidth_backoff_lower_bound_factor); + }*/ + + if (IsValid(delay_based_estimate_) && + config_->append_delay_based_estimate_candidate) { + if (can_increase_bitrate && + delay_based_estimate_ > current_estimate_.loss_limited_bandwidth) { + // MS_DEBUG_DEV("Pushing delay_based_estimate_ candidate rate: %lld", delay_based_estimate_.bps()); + bandwidths.push_back(delay_based_estimate_); + } + } + + const DataRate candidate_bandwidth_upper_bound = + GetCandidateBandwidthUpperBound(); + + std::vector candidates; + candidates.resize(bandwidths.size()); + for (size_t i = 0; i < bandwidths.size(); ++i) { + ChannelParameters candidate = current_estimate_; + if (config_->trendline_integration_enabled) { + candidate.loss_limited_bandwidth = + std::min(bandwidths[i], candidate_bandwidth_upper_bound); + } else { + candidate.loss_limited_bandwidth = std::min( + bandwidths[i], std::max(current_estimate_.loss_limited_bandwidth, + candidate_bandwidth_upper_bound)); + } + candidate.inherent_loss = GetFeasibleInherentLoss(candidate); + // MS_DEBUG_DEV("candidate.loss_limited_bandwidth: %lld, candidate.inherent_loss: %f", candidate.loss_limited_bandwidth.bps(), candidate.inherent_loss); + candidates[i] = candidate; + } + return candidates; +} + +LossBasedBweV2::Derivatives LossBasedBweV2::GetDerivatives( + const ChannelParameters& channel_parameters) const { + Derivatives derivatives; + + for (const Observation& observation : observations_) { + if (!observation.IsInitialized()) { + continue; + } + + double loss_probability = GetLossProbability( + channel_parameters.inherent_loss, + channel_parameters.loss_limited_bandwidth, observation.sending_rate); + + double temporal_weight = + temporal_weights_[(num_observations_ - 1) - observation.id]; + + derivatives.first += + temporal_weight * + ((observation.num_lost_packets / loss_probability) - + (observation.num_received_packets / (1.0 - loss_probability))); + derivatives.second -= + temporal_weight * + ((observation.num_lost_packets / std::pow(loss_probability, 2)) + + (observation.num_received_packets / + std::pow(1.0 - loss_probability, 2))); + } + + if (derivatives.second >= 0.0) { +/* RTC_LOG(LS_ERROR) << "The second derivative is mathematically guaranteed " + "to be negative but is " + << derivatives.second << ".";*/ + derivatives.second = -1.0e-6; + } + + return derivatives; +} + +double LossBasedBweV2::GetFeasibleInherentLoss( + const ChannelParameters& channel_parameters) const { + return std::min( + std::max(channel_parameters.inherent_loss, + config_->inherent_loss_lower_bound), + GetInherentLossUpperBound(channel_parameters.loss_limited_bandwidth)); +} + +double LossBasedBweV2::GetInherentLossUpperBound(DataRate bandwidth) const { + if (bandwidth.IsZero()) { + return 1.0; + } + + double inherent_loss_upper_bound = + config_->inherent_loss_upper_bound_offset + + config_->inherent_loss_upper_bound_bandwidth_balance / bandwidth; + return std::min(inherent_loss_upper_bound, 1.0); +} + +double LossBasedBweV2::AdjustBiasFactor(double loss_rate, + double bias_factor) const { + return bias_factor * + (config_->loss_threshold_of_high_bandwidth_preference - loss_rate) / + (config_->bandwidth_preference_smoothing_factor + + std::abs(config_->loss_threshold_of_high_bandwidth_preference - + loss_rate)); +} + +double LossBasedBweV2::GetHighBandwidthBias(DataRate bandwidth) const { + if (IsValid(bandwidth)) { + const double average_reported_loss_ratio = GetAverageReportedLossRatio(); + return AdjustBiasFactor(average_reported_loss_ratio, + config_->higher_bandwidth_bias_factor) * + bandwidth.kbps() + + AdjustBiasFactor(average_reported_loss_ratio, + config_->higher_log_bandwidth_bias_factor) * + std::log(1.0 + bandwidth.kbps()); + } + return 0.0; +} + +double LossBasedBweV2::GetObjective( + const ChannelParameters& channel_parameters) const { + double objective = 0.0; + + const double high_bandwidth_bias = + GetHighBandwidthBias(channel_parameters.loss_limited_bandwidth); + + for (const Observation& observation : observations_) { + if (!observation.IsInitialized()) { + continue; + } + + double loss_probability = GetLossProbability( + channel_parameters.inherent_loss, + channel_parameters.loss_limited_bandwidth, observation.sending_rate); + + double temporal_weight = + temporal_weights_[(num_observations_ - 1) - observation.id]; + + objective += + temporal_weight * + ((observation.num_lost_packets * std::log(loss_probability)) + + (observation.num_received_packets * std::log(1.0 - loss_probability))); + objective += + temporal_weight * high_bandwidth_bias * observation.num_packets; + } + + return objective; +} + +DataRate LossBasedBweV2::GetSendingRate( + DataRate instantaneous_sending_rate) const { + if (num_observations_ <= 0) { + return instantaneous_sending_rate; + } + + const int most_recent_observation_idx = + (num_observations_ - 1) % config_->observation_window_size; + const Observation& most_recent_observation = + observations_[most_recent_observation_idx]; + DataRate sending_rate_previous_observation = + most_recent_observation.sending_rate; + + return config_->sending_rate_smoothing_factor * + sending_rate_previous_observation + + (1.0 - config_->sending_rate_smoothing_factor) * + instantaneous_sending_rate; +} + +DataRate LossBasedBweV2::GetInstantUpperBound() const { + return cached_instant_upper_bound_.value_or(max_bitrate_); +} + +void LossBasedBweV2::CalculateInstantUpperBound(DataRate sending_rate) { + DataRate instant_limit = max_bitrate_; + const double average_reported_loss_ratio = GetAverageReportedLossRatio(); + auto now = Timestamp::ms(DepLibUV::GetTimeMsInt64()); + if (instant_loss_debounce_start_.IsFinite()) { + if (average_reported_loss_ratio < config_->instant_upper_bound_loss_offset) { + instant_loss_debounce_start_ = Timestamp::MinusInfinity(); + instant_loss_threshold_ = Timestamp::MinusInfinity(); + instant_loss_debounce_stop_ = now; + MS_DEBUG_DEV("Resetting"); + } + } + if (average_reported_loss_ratio > config_->instant_upper_bound_loss_offset) + { + MS_DEBUG_DEV( + "average_reported_loss_ratio %f, config_->instant_upper_bound_loss_offset %f", + average_reported_loss_ratio, + config_->instant_upper_bound_loss_offset); + + DataRate current_estimate = current_estimate_.loss_limited_bandwidth; + + auto reduce_debounce_time = TimeDelta::ms(config_->observation_duration_lower_bound.ms() * 10); + // MS_NOTE: Here we create debounce mechanism, that must help in + // bursts smoothening. We reduce by first time by 0.85 all further times + // we reduce by 0.95 for 10 seconds with throttling of 2.5 s. If that does not help + // we fall back to old mechanism with BW balance. + if (!instant_loss_debounce_start_.IsFinite()) + { + instant_loss_debounce_start_ = now; + instant_loss_threshold_ = now; + MS_DEBUG_DEV("First Instant Loss"); + rate_before_last_instant_loss_ = current_estimate; + MS_DEBUG_DEV( + "Reducing current estimate %lld by factor %f", + current_estimate.bps(), + 0.85); + + cached_instant_upper_bound_ = current_estimate * 0.85; + + current_estimate_.loss_limited_bandwidth = cached_instant_upper_bound_.value(); + + MS_DEBUG_DEV("cached_instant_upper_bound_ %lld", cached_instant_upper_bound_->bps()); + return; + } + + if ((now - instant_loss_threshold_) < reduce_debounce_time) + { + MS_DEBUG_DEV( + "Debouncing loss estimate decease as %lld < %lld", + (now - instant_loss_threshold_).ms(), + reduce_debounce_time.ms()); + return; + } else if ((now - instant_loss_threshold_) > reduce_debounce_time && (now - instant_loss_debounce_start_ < kInstantLossDebounceDuration)) { + MS_DEBUG_DEV( + "Reducing current estimate %lld by factor %f", current_estimate.bps(), kInstantLossReduceFactor); + + cached_instant_upper_bound_ = current_estimate * kInstantLossReduceFactor; + + current_estimate_.loss_limited_bandwidth = cached_instant_upper_bound_.value(); + + MS_DEBUG_DEV("cached_instant_upper_bound_ %lld", cached_instant_upper_bound_->bps()); + instant_loss_threshold_ = now; + return; + } + + if (now - instant_loss_debounce_start_ > kInstantLossDebounceDuration) + { + MS_DEBUG_DEV("Reducing by BW balance formula"); + DataRate bandwidth_balance = config_->instant_upper_bound_bandwidth_balance; + + // MS_NOTE: In case of high sending rate the value of balance (75kbps) is too small, + // and leads to big BW drops even in the case of small loss ratio. + if (sending_rate.bps() > config_->instant_upper_bound_bandwidth_balance.bps() * 100) + { + bandwidth_balance = DataRate::bps((sending_rate.bps() / 100) * kBwBalanceMultiplicator); + } + + instant_limit = + bandwidth_balance / (average_reported_loss_ratio - config_->instant_upper_bound_loss_offset); + + MS_DEBUG_DEV( + "Instant Limit!, BW balance %" PRIi64 ", instant_limit %" PRIi64 + ", average_reported_loss_ratio %f, diff: %f, sending rate: %lld", + bandwidth_balance.bps(), + instant_limit.IsFinite() ? instant_limit.bps() : 0, + average_reported_loss_ratio, + average_reported_loss_ratio - config_->instant_upper_bound_loss_offset, + sending_rate.bps()); + + if (average_reported_loss_ratio > config_->high_loss_rate_threshold) + { + instant_limit = std::min( + instant_limit, + DataRate::kbps(std::max( + static_cast(min_bitrate_.kbps()), + config_->bandwidth_cap_at_high_loss_rate.kbps() - + config_->slope_of_bwe_high_loss_func * average_reported_loss_ratio))); + } + + if (IsBandwidthLimitedDueToLoss()) + { + if (IsValid(upper_link_capacity_) && config_->bound_by_upper_link_capacity_when_loss_limited) + { + instant_limit = std::min(instant_limit, upper_link_capacity_); + } + } + } + } + cached_instant_upper_bound_ = instant_limit; +} + +void LossBasedBweV2::CalculateTemporalWeights() { + for (int i = 0; i < config_->observation_window_size; ++i) { + temporal_weights_[i] = std::pow(config_->temporal_weight_factor, i); + instant_upper_bound_temporal_weights_[i] = + std::pow(config_->instant_upper_bound_temporal_weight_factor, i); + } +} + +void LossBasedBweV2::NewtonsMethodUpdate( + ChannelParameters& channel_parameters) const { + if (num_observations_ <= 0) { + return; + } + + for (int i = 0; i < config_->newton_iterations; ++i) { + const Derivatives derivatives = GetDerivatives(channel_parameters); + channel_parameters.inherent_loss -= + config_->newton_step_size * derivatives.first / derivatives.second; + channel_parameters.inherent_loss = + GetFeasibleInherentLoss(channel_parameters); + } +} + +bool LossBasedBweV2::TrendlineEsimateAllowBitrateIncrease() const { + if (!config_->trendline_integration_enabled) { + return true; + } + + for (const auto& detector_state : delay_detector_states_) { + if (detector_state == BandwidthUsage::kBwOverusing || + detector_state == BandwidthUsage::kBwUnderusing) { + return false; + } + } + return true; +} + +bool LossBasedBweV2::TrendlineEsimateAllowEmergencyBackoff() const { + if (!config_->trendline_integration_enabled) { + return true; + } + + if (!config_->use_acked_bitrate_only_when_overusing) { + return true; + } + + for (const auto& detector_state : delay_detector_states_) { + if (detector_state == BandwidthUsage::kBwOverusing) { + return true; + } + } + + return false; +} + +bool LossBasedBweV2::PushBackObservation( + std::vector packet_results, + BandwidthUsage delay_detector_state) { + delay_detector_states_.push_front(delay_detector_state); + if (static_cast(delay_detector_states_.size()) > + config_->trendline_observations_window_size) { + delay_detector_states_.pop_back(); + } + + if (packet_results.empty()) { + return false; + } + + PacketResultsSummary packet_results_summary = + GetPacketResultsSummary(packet_results); + + partial_observation_.num_packets += packet_results_summary.num_packets; + partial_observation_.num_lost_packets += + packet_results_summary.num_lost_packets; + partial_observation_.size += packet_results_summary.total_size; + + // This is the first packet report we have received. + if (!IsValid(last_send_time_most_recent_observation_)) { + last_send_time_most_recent_observation_ = + packet_results_summary.first_send_time; + } + + const Timestamp last_send_time = packet_results_summary.last_send_time; + const TimeDelta observation_duration = + last_send_time - last_send_time_most_recent_observation_; + // Too small to be meaningful. + if (observation_duration <= TimeDelta::Zero() || + (observation_duration < config_->observation_duration_lower_bound && + (delay_detector_state != BandwidthUsage::kBwOverusing || + !config_->trendline_integration_enabled))) { +/* MS_DEBUG_DEV("Observation Duration %" PRIi64 ", Delay detector state %s, trendline_integration_enabled, %d, Current estimate %" PRIi64 "", + observation_duration.ms(), + delay_detector_state == BandwidthUsage::kBwNormal ? "Normal" : + delay_detector_state == BandwidthUsage::kBwOverusing ? "Overusing" : "Underusing", + config_->trendline_integration_enabled, + current_estimate_.loss_limited_bandwidth.bps());*/ + return false; + } + + last_send_time_most_recent_observation_ = last_send_time; + last_sending_rate_ = GetSendingRate(partial_observation_.size / observation_duration); + + Observation observation; + observation.num_packets = partial_observation_.num_packets; + observation.num_lost_packets = partial_observation_.num_lost_packets; + observation.num_received_packets = + observation.num_packets - observation.num_lost_packets; + observation.sending_rate = last_sending_rate_; + observation.id = num_observations_++; + observations_[observation.id % config_->observation_window_size] = + observation; + + partial_observation_ = PartialObservation(); + + CalculateInstantUpperBound(last_sending_rate_); + + // MS_NOTE Here we reset loss estimator if there was not traffic in + // max_observation_duration_before_reset_, otherwise, we will stuck + // at low bitrate. + if (observation_duration > max_observation_duration_before_reset_) { + MS_DEBUG_TAG(bwe, "Too big observation duration, resetting stats"); + MS_DEBUG_TAG(bwe, "Current estimate bw: %" PRIi64 ", inherent_loss: %f", current_estimate_.loss_limited_bandwidth.bps(), current_estimate_.inherent_loss); + Reset(); + } + return true; +} + +bool LossBasedBweV2::IsBandwidthLimitedDueToLoss() const { + return current_state_ != LossBasedState::kDelayBasedEstimate; +} + +} // namespace webrtc diff --git a/worker/deps/libwebrtc/libwebrtc/modules/bitrate_controller/loss_based_bwe_v2.h b/worker/deps/libwebrtc/libwebrtc/modules/bitrate_controller/loss_based_bwe_v2.h new file mode 100644 index 0000000000..e14d44059e --- /dev/null +++ b/worker/deps/libwebrtc/libwebrtc/modules/bitrate_controller/loss_based_bwe_v2.h @@ -0,0 +1,220 @@ +/* + * Copyright 2021 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_GOOG_CC_LOSS_BASED_BWE_V2_H_ +#define MODULES_CONGESTION_CONTROLLER_GOOG_CC_LOSS_BASED_BWE_V2_H_ + +#include +#include +#include + +#include "absl/types/optional.h" +#include "api/network_state_predictor.h" +#include "api/transport/network_types.h" +#include "api/units/data_rate.h" +#include "api/units/data_size.h" +#include "api/units/time_delta.h" +#include "api/units/timestamp.h" +#include "api/transport/webrtc_key_value_config.h" + +namespace webrtc +{ + + // State of the loss based estimate, which can be either increasing/decreasing + // when network is loss limited, or equal to the delay based estimate. + enum class LossBasedState + { + kIncreasing = 0, + kDecreasing = 1, + kDelayBasedEstimate = 2 + }; + +class LossBasedBweV2 { + public: + struct Result { + ~Result() = default; + DataRate bandwidth_estimate = DataRate::Zero(); + LossBasedState state = LossBasedState::kDelayBasedEstimate; + }; + // Creates a disabled `LossBasedBweV2` if the + // `key_value_config` is not valid. + explicit LossBasedBweV2(const WebRtcKeyValueConfig* key_value_config); + + LossBasedBweV2(const LossBasedBweV2&) = delete; + LossBasedBweV2& operator=(const LossBasedBweV2&) = delete; + + ~LossBasedBweV2() = default; + + LossEstimatorState GetState() const; + + bool IsEnabled() const; + // Returns true iff a BWE can be calculated, i.e., the estimator has been + // initialized with a BWE and then has received enough `PacketResult`s. + bool IsReady() const; + + // Returns `DataRate::PlusInfinity` if no BWE can be calculated. + Result GetLossBasedResult(); + void SetAcknowledgedBitrate(DataRate acknowledged_bitrate); + void SetBandwidthEstimate(DataRate bandwidth_estimate); + void SetMinMaxBitrate(DataRate min_bitrate, DataRate max_bitrate); + void UpdateBandwidthEstimate( + std::vector packet_results, + DataRate delay_based_estimate, + BandwidthUsage delay_detector_state, + absl::optional probe_bitrate, + DataRate upper_link_capacity); + + private: + struct ChannelParameters + { + double inherent_loss = 0.0; + DataRate loss_limited_bandwidth = DataRate::MinusInfinity(); + }; + + struct Config + { + double bandwidth_rampup_upper_bound_factor = 0.0; + double rampup_acceleration_max_factor = 0.0; + TimeDelta rampup_acceleration_maxout_time = TimeDelta::Zero(); + std::vector candidate_factors; + double higher_bandwidth_bias_factor = 0.0; + double higher_log_bandwidth_bias_factor = 0.0; + double inherent_loss_lower_bound = 0.0; + double loss_threshold_of_high_bandwidth_preference = 0.0; + double bandwidth_preference_smoothing_factor = 0.0; + DataRate inherent_loss_upper_bound_bandwidth_balance = DataRate::MinusInfinity(); + double inherent_loss_upper_bound_offset = 0.0; + double initial_inherent_loss_estimate = 0.0; + int newton_iterations = 0; + double newton_step_size = 0.0; + bool append_acknowledged_rate_candidate = true; + bool append_delay_based_estimate_candidate = false; + TimeDelta observation_duration_lower_bound = TimeDelta::Zero(); + int observation_window_size = 0; + double sending_rate_smoothing_factor = 0.0; + double instant_upper_bound_temporal_weight_factor = 0.0; + DataRate instant_upper_bound_bandwidth_balance = DataRate::MinusInfinity(); + double instant_upper_bound_loss_offset = 0.0; + double temporal_weight_factor = 0.0; + double bandwidth_backoff_lower_bound_factor = 0.0; + bool trendline_integration_enabled = false; + int trendline_observations_window_size = 0; + double max_increase_factor = 0.0; + TimeDelta delayed_increase_window = TimeDelta::Zero(); + bool use_acked_bitrate_only_when_overusing = false; + bool not_increase_if_inherent_loss_less_than_average_loss = false; + double high_loss_rate_threshold = 1.0; + DataRate bandwidth_cap_at_high_loss_rate = DataRate::MinusInfinity(); + double slope_of_bwe_high_loss_func = 1000.0; + bool probe_integration_enabled = false; + bool bound_by_upper_link_capacity_when_loss_limited = false; + }; + + struct Derivatives { + double first = 0.0; + double second = 0.0; + }; + + struct Observation { + bool IsInitialized() const { return id != -1; } + + int num_packets = 0; + int num_lost_packets = 0; + int num_received_packets = 0; + DataRate sending_rate = DataRate::MinusInfinity(); + int id = -1; + }; + + struct PartialObservation { + int num_packets = 0; + int num_lost_packets = 0; + DataSize size = DataSize::Zero(); + }; + + static absl::optional CreateConfig( + const WebRtcKeyValueConfig* key_value_config); + bool IsConfigValid() const; + + // Returns `0.0` if not enough loss statistics have been received. + double GetAverageReportedLossRatio() const; + std::vector GetCandidates() const; + DataRate GetCandidateBandwidthUpperBound() const; + Derivatives GetDerivatives(const ChannelParameters& channel_parameters) const; + double GetFeasibleInherentLoss( + const ChannelParameters& channel_parameters) const; + double GetInherentLossUpperBound(DataRate bandwidth) const; + double AdjustBiasFactor(double loss_rate, double bias_factor) const; + double GetHighBandwidthBias(DataRate bandwidth) const; + double GetObjective(const ChannelParameters& channel_parameters) const; + DataRate GetSendingRate(DataRate instantaneous_sending_rate) const; + DataRate GetInstantUpperBound() const; + void CalculateInstantUpperBound(DataRate instantaneous_sending_rate); + + void CalculateTemporalWeights(); + void NewtonsMethodUpdate(ChannelParameters& channel_parameters) const; + + // Returns false if there exists a kBwOverusing or kBwUnderusing in the + // window. + bool TrendlineEsimateAllowBitrateIncrease() const; + + // Returns true if there exists an overusing state in the window. + bool TrendlineEsimateAllowEmergencyBackoff() const; + + // Returns false if no observation was created. + bool PushBackObservation(std::vector packet_results, + BandwidthUsage delay_detector_state); + void UpdateTrendlineEstimator( + const std::vector packet_feedbacks, + Timestamp at_time); + void UpdateDelayDetector(BandwidthUsage delay_detector_state); + bool IsEstimateIncreasingWhenLossLimited( + const ChannelParameters& best_candidate); + bool IsBandwidthLimitedDueToLoss() const; + void SetProbeBitrate(absl::optional probe_bitrate); + void Reset(); + + absl::optional acknowledged_bitrate_; + absl::optional config_; + ChannelParameters current_estimate_; + int num_observations_ = 0; + std::vector observations_; + PartialObservation partial_observation_; + Timestamp last_send_time_most_recent_observation_ = Timestamp::PlusInfinity(); + Timestamp last_time_estimate_reduced_ = Timestamp::MinusInfinity(); + absl::optional cached_instant_upper_bound_; + std::vector instant_upper_bound_temporal_weights_; + std::vector temporal_weights_; + std::deque delay_detector_states_; + Timestamp recovering_after_loss_timestamp_ = Timestamp::MinusInfinity(); + DataRate bandwidth_limit_in_current_window_ = DataRate::PlusInfinity(); + LossBasedState current_state_ = LossBasedState::kDelayBasedEstimate; + DataRate probe_bitrate_ = DataRate::PlusInfinity(); + DataRate delay_based_estimate_ = DataRate::PlusInfinity(); + DataRate upper_link_capacity_ = DataRate::PlusInfinity(); + // MS_NOTE: changed min bitrate from 1 to 100, this allows faster recover + // from huge drop. + DataRate min_bitrate_ = DataRate::kbps(100); + DataRate max_bitrate_ = DataRate::PlusInfinity(); + TimeDelta max_observation_duration_before_reset_ = TimeDelta::seconds(4); + double static constexpr kBwBalanceMultiplicator = 1.3; + size_t instant_loss_debounce_counter_ = 0; + TimeDelta kInstantLossDebounceDuration = TimeDelta::seconds(10); + Timestamp instant_loss_debounce_start_ = Timestamp::MinusInfinity(); + Timestamp instant_loss_threshold_ = Timestamp::MinusInfinity(); + + float kInstantLossReduceFactor = 0.95; + DataRate last_sending_rate_ = DataRate::PlusInfinity(); + DataRate rate_before_last_instant_loss_ = DataRate::PlusInfinity(); + Timestamp instant_loss_debounce_stop_ = Timestamp::MinusInfinity(); +}; + +} // namespace webrtc + +#endif // MODULES_CONGESTION_CONTROLLER_GOOG_CC_LOSS_BASED_BWE_V2_H_ diff --git a/worker/deps/libwebrtc/libwebrtc/modules/bitrate_controller/send_side_bandwidth_estimation.cc b/worker/deps/libwebrtc/libwebrtc/modules/bitrate_controller/send_side_bandwidth_estimation.cc index 2b12cf0fe2..0e094d6bf3 100644 --- a/worker/deps/libwebrtc/libwebrtc/modules/bitrate_controller/send_side_bandwidth_estimation.cc +++ b/worker/deps/libwebrtc/libwebrtc/modules/bitrate_controller/send_side_bandwidth_estimation.cc @@ -13,8 +13,10 @@ #include "modules/bitrate_controller/send_side_bandwidth_estimation.h" #include "modules/remote_bitrate_estimator/include/bwe_defines.h" +#include "api/transport/webrtc_key_value_config.h" #include "system_wrappers/source/field_trial.h" + #include "Logger.hpp" #include @@ -35,8 +37,6 @@ constexpr TimeDelta kLowBitrateLogPeriod = TimeDelta::Millis<10000>(); constexpr TimeDelta kRtcEventLogPeriod = TimeDelta::Millis<5000>(); // Expecting that RTCP feedback is sent uniformly within [0.5, 1.5]s intervals. constexpr TimeDelta kMaxRtcpFeedbackInterval = TimeDelta::Millis<5000>(); -constexpr int kFeedbackTimeoutIntervals = 3; -constexpr TimeDelta kTimeoutInterval = TimeDelta::Millis<1000>(); constexpr float kDefaultLowLossThreshold = 0.02f; constexpr float kDefaultHighLossThreshold = 0.1f; @@ -106,16 +106,20 @@ bool ReadBweLossExperimentParameters(float* low_loss_threshold, LinkCapacityTracker::LinkCapacityTracker() : tracking_rate("rate", TimeDelta::seconds(10)) { ParseFieldTrial({&tracking_rate}, - field_trial::FindFullName("WebRTC-Bwe-LinkCapacity")); + webrtc::field_trial::FindFullName("WebRTC-Bwe-LinkCapacity")); } LinkCapacityTracker::~LinkCapacityTracker() {} -void LinkCapacityTracker::OnOveruse(DataRate acknowledged_rate, - Timestamp at_time) { - capacity_estimate_bps_ = - std::min(capacity_estimate_bps_, acknowledged_rate.bps()); - last_link_capacity_update_ = at_time; +void LinkCapacityTracker::UpdateDelayBasedEstimate( + Timestamp at_time, + DataRate delay_based_bitrate) { + if (delay_based_bitrate < last_delay_based_estimate_) { + capacity_estimate_bps_ = + std::min(capacity_estimate_bps_, delay_based_bitrate.bps()); + last_link_capacity_update_ = at_time; + } + last_delay_based_estimate_ = delay_based_bitrate; } void LinkCapacityTracker::OnStartingRate(DataRate start_rate) { @@ -123,13 +127,17 @@ void LinkCapacityTracker::OnStartingRate(DataRate start_rate) { capacity_estimate_bps_ = start_rate.bps(); } -void LinkCapacityTracker::OnRateUpdate(DataRate acknowledged, +void LinkCapacityTracker::OnRateUpdate(absl::optional acknowledged, + DataRate target, Timestamp at_time) { - if (acknowledged.bps() > capacity_estimate_bps_) { + if (!acknowledged) + return; + DataRate acknowledged_target = std::min(*acknowledged, target); + if (acknowledged_target.bps() > capacity_estimate_bps_) { TimeDelta delta = at_time - last_link_capacity_update_; double alpha = delta.IsFinite() ? exp(-(delta / tracking_rate.Get())) : 0; capacity_estimate_bps_ = alpha * capacity_estimate_bps_ + - (1 - alpha) * acknowledged.bps(); + (1 - alpha) * acknowledged_target.bps(); } last_link_capacity_update_ = at_time; } @@ -145,28 +153,23 @@ DataRate LinkCapacityTracker::estimate() const { return DataRate::bps(capacity_estimate_bps_); } -RttBasedBackoff::RttBasedBackoff() - : rtt_limit_("limit", TimeDelta::PlusInfinity()), - drop_fraction_("fraction", 0.5), - drop_interval_("interval", TimeDelta::ms(300)), - persist_on_route_change_("persist"), - safe_timeout_("safe_timeout", true), +RttBasedBackoff::RttBasedBackoff(const WebRtcKeyValueConfig* key_value_config) + : disabled_("Disabled"), + configured_limit_("limit", TimeDelta::seconds(3)), + drop_fraction_("fraction", 0.8), + drop_interval_("interval", TimeDelta::seconds(1)), bandwidth_floor_("floor", DataRate::kbps(5)), + rtt_limit_(TimeDelta::PlusInfinity()), // By initializing this to plus infinity, we make sure that we never // trigger rtt backoff unless packet feedback is enabled. last_propagation_rtt_update_(Timestamp::PlusInfinity()), last_propagation_rtt_(TimeDelta::Zero()), last_packet_sent_(Timestamp::MinusInfinity()) { - ParseFieldTrial( - {&rtt_limit_, &drop_fraction_, &drop_interval_, &persist_on_route_change_, - &safe_timeout_, &bandwidth_floor_}, - field_trial::FindFullName("WebRTC-Bwe-MaxRttLimit")); -} - -void RttBasedBackoff::OnRouteChange() { - if (!persist_on_route_change_) { - last_propagation_rtt_update_ = Timestamp::PlusInfinity(); - last_propagation_rtt_ = TimeDelta::Zero(); + ParseFieldTrial({&disabled_, &configured_limit_, &drop_fraction_, + &drop_interval_, &bandwidth_floor_}, + key_value_config->Lookup("WebRTC-Bwe-MaxRttLimit")); + if (!disabled_) { + rtt_limit_ = configured_limit_.Get(); } } @@ -179,34 +182,33 @@ void RttBasedBackoff::UpdatePropagationRtt(Timestamp at_time, TimeDelta RttBasedBackoff::CorrectedRtt(Timestamp at_time) const { TimeDelta time_since_rtt = at_time - last_propagation_rtt_update_; TimeDelta timeout_correction = time_since_rtt; - if (safe_timeout_) { - // Avoid timeout when no packets are being sent. - TimeDelta time_since_packet_sent = at_time - last_packet_sent_; - timeout_correction = - std::max(time_since_rtt - time_since_packet_sent, TimeDelta::Zero()); - } + // Avoid timeout when no packets are being sent. + TimeDelta time_since_packet_sent = at_time - last_packet_sent_; + timeout_correction = + std::max(time_since_rtt - time_since_packet_sent, TimeDelta::Zero()); return timeout_correction + last_propagation_rtt_; } RttBasedBackoff::~RttBasedBackoff() = default; -SendSideBandwidthEstimation::SendSideBandwidthEstimation() - : lost_packets_since_last_loss_update_(0), +SendSideBandwidthEstimation::SendSideBandwidthEstimation( + const WebRtcKeyValueConfig* key_value_config) + : rtt_backoff_(key_value_config), + lost_packets_since_last_loss_update_(0), expected_packets_since_last_loss_update_(0), - current_bitrate_(DataRate::Zero()), - min_bitrate_configured_( - DataRate::bps(congestion_controller::GetMinBitrateBps())), + current_target_(DataRate::Zero()), + last_logged_target_(DataRate::Zero()), + min_bitrate_configured_(kCongestionControllerMinBitrate), max_bitrate_configured_(kDefaultMaxBitrate), last_low_bitrate_log_(Timestamp::MinusInfinity()), has_decreased_since_last_fraction_loss_(false), last_loss_feedback_(Timestamp::MinusInfinity()), last_loss_packet_report_(Timestamp::MinusInfinity()), - last_timeout_(Timestamp::MinusInfinity()), last_fraction_loss_(0), last_logged_fraction_loss_(0), last_round_trip_time_(TimeDelta::Zero()), - bwe_incoming_(DataRate::Zero()), - delay_based_bitrate_(DataRate::Zero()), + receiver_limit_(DataRate::PlusInfinity()), + delay_based_limit_(DataRate::PlusInfinity()), time_last_decrease_(Timestamp::MinusInfinity()), first_report_time_(Timestamp::MinusInfinity()), initially_lost_packets_(0), @@ -215,12 +217,14 @@ SendSideBandwidthEstimation::SendSideBandwidthEstimation() uma_rtt_state_(kNoUpdate), rampup_uma_stats_updated_(kNumUmaRampupMetrics, false), last_rtc_event_log_(Timestamp::MinusInfinity()), - in_timeout_experiment_( - webrtc::field_trial::IsEnabled("WebRTC-FeedbackTimeout")), low_loss_threshold_(kDefaultLowLossThreshold), high_loss_threshold_(kDefaultHighLossThreshold), - bitrate_threshold_(kDefaultBitrateThreshold) { - // RTC_DCHECK(event_log); + bitrate_threshold_(kDefaultBitrateThreshold), + loss_based_bandwidth_estimator_v1_(key_value_config), + loss_based_bandwidth_estimator_v2_(key_value_config), + loss_based_state_(LossBasedState::kDelayBasedEstimate), + disable_receiver_limit_caps_only_("Disabled") { + if (BweLossExperimentIsEnabled()) { uint32_t bitrate_threshold_kbps; if (ReadBweLossExperimentParameters(&low_loss_threshold_, @@ -232,6 +236,12 @@ SendSideBandwidthEstimation::SendSideBandwidthEstimation() bitrate_threshold_ = DataRate::kbps(bitrate_threshold_kbps); } } + ParseFieldTrial({&disable_receiver_limit_caps_only_}, + key_value_config->Lookup("WebRTC-Bwe-ReceiverLimitCapsOnly")); + if (LossBasedBandwidthEstimatorV2Enabled()) { + loss_based_bandwidth_estimator_v2_.SetMinMaxBitrate( + min_bitrate_configured_, max_bitrate_configured_); + } } SendSideBandwidthEstimation::~SendSideBandwidthEstimation() {} @@ -239,20 +249,18 @@ SendSideBandwidthEstimation::~SendSideBandwidthEstimation() {} void SendSideBandwidthEstimation::OnRouteChange() { lost_packets_since_last_loss_update_ = 0; expected_packets_since_last_loss_update_ = 0; - current_bitrate_ = DataRate::Zero(); - min_bitrate_configured_ = - DataRate::bps(congestion_controller::GetMinBitrateBps()); + current_target_ = DataRate::Zero(); + min_bitrate_configured_ = kCongestionControllerMinBitrate; max_bitrate_configured_ = kDefaultMaxBitrate; last_low_bitrate_log_ = Timestamp::MinusInfinity(); has_decreased_since_last_fraction_loss_ = false; last_loss_feedback_ = Timestamp::MinusInfinity(); last_loss_packet_report_ = Timestamp::MinusInfinity(); - last_timeout_ = Timestamp::MinusInfinity(); last_fraction_loss_ = 0; last_logged_fraction_loss_ = 0; last_round_trip_time_ = TimeDelta::Zero(); - bwe_incoming_ = DataRate::Zero(); - delay_based_bitrate_ = DataRate::Zero(); + receiver_limit_ = DataRate::PlusInfinity(); + delay_based_limit_ = DataRate::PlusInfinity(); time_last_decrease_ = Timestamp::MinusInfinity(); first_report_time_ = Timestamp::MinusInfinity(); initially_lost_packets_ = 0; @@ -260,8 +268,6 @@ void SendSideBandwidthEstimation::OnRouteChange() { uma_update_state_ = kNoUpdate; uma_rtt_state_ = kNoUpdate; last_rtc_event_log_ = Timestamp::MinusInfinity(); - - rtt_backoff_.OnRouteChange(); } void SendSideBandwidthEstimation::SetBitrates( @@ -276,17 +282,18 @@ void SendSideBandwidthEstimation::SetBitrates( } } +LossEstimatorState SendSideBandwidthEstimation::GetLossEstimatorState() const { + return loss_based_bandwidth_estimator_v2_.GetState(); +} + void SendSideBandwidthEstimation::SetSendBitrate(DataRate bitrate, Timestamp at_time) { MS_DEBUG_DEV("bitrate: %lld", bitrate.bps()); // RTC_DCHECK_GT(bitrate, DataRate::Zero()); // Reset to avoid being capped by the estimate. - delay_based_bitrate_ = DataRate::Zero(); - if (loss_based_bandwidth_estimation_.Enabled()) { - loss_based_bandwidth_estimation_.MaybeReset(bitrate); - } - CapBitrateToThresholds(at_time, bitrate); + delay_based_limit_ = DataRate::PlusInfinity(); + UpdateTargetBitrate(bitrate, at_time); // Clear last sent bitrate history so the new value can be used directly // and not capped. min_bitrate_history_.clear(); @@ -295,31 +302,29 @@ void SendSideBandwidthEstimation::SetSendBitrate(DataRate bitrate, void SendSideBandwidthEstimation::SetMinMaxBitrate(DataRate min_bitrate, DataRate max_bitrate) { min_bitrate_configured_ = - std::max(min_bitrate, congestion_controller::GetMinBitrate()); + std::max(min_bitrate, kCongestionControllerMinBitrate); if (max_bitrate > DataRate::Zero() && max_bitrate.IsFinite()) { max_bitrate_configured_ = std::max(min_bitrate_configured_, max_bitrate); } else { max_bitrate_configured_ = kDefaultMaxBitrate; } + loss_based_bandwidth_estimator_v2_.SetMinMaxBitrate(min_bitrate_configured_, + max_bitrate_configured_); } int SendSideBandwidthEstimation::GetMinBitrate() const { return min_bitrate_configured_.bps(); } -void SendSideBandwidthEstimation::CurrentEstimate(int* bitrate, - uint8_t* loss, - int64_t* rtt) const { - *bitrate = std::max(current_bitrate_.bps(), GetMinBitrate()); - *loss = last_fraction_loss_; - *rtt = last_round_trip_time_.ms(); +DataRate SendSideBandwidthEstimation::target_rate() const { + DataRate target = current_target_; + if (!disable_receiver_limit_caps_only_) + target = std::min(target, receiver_limit_); + return std::max(min_bitrate_configured_, target); +} - MS_DEBUG_DEV("bitrate:%d (current_bitrate_:%" PRIi64 ", GetMinBitrate():%d), loss:%d, rtt:%" PRIi64, - *bitrate, - current_bitrate_.bps(), - GetMinBitrate(), - *loss, - *rtt); +LossBasedState SendSideBandwidthEstimation::loss_based_state() const { + return loss_based_state_; } DataRate SendSideBandwidthEstimation::GetEstimatedLinkCapacity() const { @@ -328,53 +333,58 @@ DataRate SendSideBandwidthEstimation::GetEstimatedLinkCapacity() const { void SendSideBandwidthEstimation::UpdateReceiverEstimate(Timestamp at_time, DataRate bandwidth) { - bwe_incoming_ = bandwidth; - CapBitrateToThresholds(at_time, current_bitrate_); + // TODO(srte): Ensure caller passes PlusInfinity, not zero, to represent no + // limitation. + receiver_limit_ = bandwidth.IsZero() ? DataRate::PlusInfinity() : bandwidth; + ApplyTargetLimits(at_time); } void SendSideBandwidthEstimation::UpdateDelayBasedEstimate(Timestamp at_time, DataRate bitrate) { - if (acknowledged_rate_) { - if (bitrate < delay_based_bitrate_) { - link_capacity_.OnOveruse(*acknowledged_rate_, at_time); - } - } - delay_based_bitrate_ = bitrate; - CapBitrateToThresholds(at_time, current_bitrate_); + link_capacity_.UpdateDelayBasedEstimate(at_time, bitrate); + // TODO(srte): Ensure caller passes PlusInfinity, not zero, to represent no + // limitation. + delay_based_limit_ = bitrate.IsZero() ? DataRate::PlusInfinity() : bitrate; + ApplyTargetLimits(at_time); } void SendSideBandwidthEstimation::SetAcknowledgedRate( absl::optional acknowledged_rate, Timestamp at_time) { acknowledged_rate_ = acknowledged_rate; - if (acknowledged_rate && loss_based_bandwidth_estimation_.Enabled()) { - loss_based_bandwidth_estimation_.UpdateAcknowledgedBitrate( + if (!acknowledged_rate.has_value()) { + return; + } + if (LossBasedBandwidthEstimatorV1Enabled()) { + loss_based_bandwidth_estimator_v1_.UpdateAcknowledgedBitrate( *acknowledged_rate, at_time); } + if (LossBasedBandwidthEstimatorV2Enabled()) { + loss_based_bandwidth_estimator_v2_.SetAcknowledgedBitrate( + *acknowledged_rate); + } } -void SendSideBandwidthEstimation::IncomingPacketFeedbackVector( - const TransportPacketsFeedback& report) { - if (loss_based_bandwidth_estimation_.Enabled()) { - loss_based_bandwidth_estimation_.UpdateLossStatistics( +void SendSideBandwidthEstimation::UpdateLossBasedEstimator( + const TransportPacketsFeedback& report, + BandwidthUsage delay_detector_state, + absl::optional probe_bitrate, + DataRate upper_link_capacity) { + if (LossBasedBandwidthEstimatorV1Enabled()) { + loss_based_bandwidth_estimator_v1_.UpdateLossStatistics( report.packet_feedbacks, report.feedback_time); } -} + if (LossBasedBandwidthEstimatorV2Enabled()) { + loss_based_bandwidth_estimator_v2_.UpdateBandwidthEstimate( + report.packet_feedbacks, delay_based_limit_, delay_detector_state, + probe_bitrate, upper_link_capacity); -void SendSideBandwidthEstimation::UpdateReceiverBlock(uint8_t fraction_loss, - TimeDelta rtt, - int number_of_packets, - Timestamp at_time) { - const int kRoundingConstant = 128; - int packets_lost = (static_cast(fraction_loss) * number_of_packets + - kRoundingConstant) >> - 8; - UpdatePacketsLost(packets_lost, number_of_packets, at_time); - UpdateRtt(rtt, at_time); + UpdateEstimate(report.feedback_time); + } } -void SendSideBandwidthEstimation::UpdatePacketsLost(int packets_lost, - int number_of_packets, +void SendSideBandwidthEstimation::UpdatePacketsLost(int64_t packets_lost, + int64_t number_of_packets, Timestamp at_time) { last_loss_feedback_ = at_time; if (first_report_time_.IsInfinite()) @@ -383,7 +393,7 @@ void SendSideBandwidthEstimation::UpdatePacketsLost(int packets_lost, // Check sequence number diff and weight loss report if (number_of_packets > 0) { int64_t expected = - expected_packets_since_last_loss_update_ + number_of_packets; + expected_packets_since_last_loss_update_ + number_of_packets; // Don't generate a loss rate until it can be based on enough packets. if (expected < kLimitNumPackets) { @@ -410,7 +420,8 @@ void SendSideBandwidthEstimation::UpdatePacketsLost(int packets_lost, void SendSideBandwidthEstimation::UpdateUmaStatsPacketsLost(Timestamp at_time, int packets_lost) { - DataRate bitrate_kbps = DataRate::kbps((current_bitrate_.bps() + 500) / 1000); + DataRate bitrate_kbps = + DataRate::kbps((current_target_.bps() + 500) / 1000); for (size_t i = 0; i < kNumUmaRampupMetrics; ++i) { if (!rampup_uma_stats_updated_[i] && bitrate_kbps.kbps() >= kUmaRampupMetrics[i].bitrate_kbps) { @@ -451,64 +462,83 @@ void SendSideBandwidthEstimation::UpdateRtt(TimeDelta rtt, Timestamp at_time) { } void SendSideBandwidthEstimation::UpdateEstimate(Timestamp at_time) { - DataRate new_bitrate = current_bitrate_; if (rtt_backoff_.CorrectedRtt(at_time) > rtt_backoff_.rtt_limit_) { if (at_time - time_last_decrease_ >= rtt_backoff_.drop_interval_ && - current_bitrate_ > rtt_backoff_.bandwidth_floor_) { + current_target_ > rtt_backoff_.bandwidth_floor_) { time_last_decrease_ = at_time; - new_bitrate = std::max(current_bitrate_ * rtt_backoff_.drop_fraction_, - rtt_backoff_.bandwidth_floor_.Get()); + DataRate new_bitrate = + std::max(current_target_ * rtt_backoff_.drop_fraction_, + rtt_backoff_.bandwidth_floor_.Get()); link_capacity_.OnRttBackoff(new_bitrate, at_time); + UpdateTargetBitrate(new_bitrate, at_time); + return; } - CapBitrateToThresholds(at_time, new_bitrate); + // TODO(srte): This is likely redundant in most cases. + ApplyTargetLimits(at_time); return; } // We trust the REMB and/or delay-based estimate during the first 2 seconds if // we haven't had any packet loss reported, to allow startup bitrate probing. if (last_fraction_loss_ == 0 && IsInStartPhase(at_time)) { - new_bitrate = std::max(bwe_incoming_, new_bitrate); - new_bitrate = std::max(delay_based_bitrate_, new_bitrate); - if (loss_based_bandwidth_estimation_.Enabled()) { - loss_based_bandwidth_estimation_.SetInitialBitrate(new_bitrate); + DataRate new_bitrate = current_target_; + // TODO(srte): We should not allow the new_bitrate to be larger than the + // receiver limit here. + if (receiver_limit_.IsFinite()) + new_bitrate = std::max(receiver_limit_, new_bitrate); + if (delay_based_limit_.IsFinite()) + new_bitrate = std::max(delay_based_limit_, new_bitrate); + if (LossBasedBandwidthEstimatorV1Enabled()) { + loss_based_bandwidth_estimator_v1_.Initialize(new_bitrate); + } + if (LossBasedBandwidthEstimatorV2Enabled()) { + loss_based_bandwidth_estimator_v2_.SetBandwidthEstimate(new_bitrate); } - if (new_bitrate != current_bitrate_) { + if (new_bitrate != current_target_) { min_bitrate_history_.clear(); - if (loss_based_bandwidth_estimation_.Enabled()) { + if (LossBasedBandwidthEstimatorV1Enabled()) { min_bitrate_history_.push_back(std::make_pair(at_time, new_bitrate)); } else { min_bitrate_history_.push_back( - std::make_pair(at_time, current_bitrate_)); + std::make_pair(at_time, current_target_)); } - CapBitrateToThresholds(at_time, new_bitrate); + UpdateTargetBitrate(new_bitrate, at_time); return; } } UpdateMinHistory(at_time); if (last_loss_packet_report_.IsInfinite()) { // No feedback received. - CapBitrateToThresholds(at_time, current_bitrate_); + // TODO(srte): This is likely redundant in most cases. + ApplyTargetLimits(at_time); + return; + } + + if (LossBasedBandwidthEstimatorV1ReadyForUse()) { + DataRate new_bitrate = loss_based_bandwidth_estimator_v1_.Update( + at_time, min_bitrate_history_.front().second, delay_based_limit_, + last_round_trip_time_); + UpdateTargetBitrate(new_bitrate, at_time); return; } - if (loss_based_bandwidth_estimation_.Enabled()) { - loss_based_bandwidth_estimation_.Update( - at_time, min_bitrate_history_.front().second, last_round_trip_time_); - new_bitrate = MaybeRampupOrBackoff(new_bitrate, at_time); - CapBitrateToThresholds(at_time, new_bitrate); + if (LossBasedBandwidthEstimatorV2ReadyForUse()) { + LossBasedBweV2::Result result = + loss_based_bandwidth_estimator_v2_.GetLossBasedResult(); + loss_based_state_ = result.state; + UpdateTargetBitrate(result.bandwidth_estimate, at_time); return; } TimeDelta time_since_loss_packet_report = at_time - last_loss_packet_report_; - TimeDelta time_since_loss_feedback = at_time - last_loss_feedback_; if (time_since_loss_packet_report < 1.2 * kMaxRtcpFeedbackInterval) { // We only care about loss above a given bitrate threshold. float loss = last_fraction_loss_ / 256.0f; // We only make decisions based on loss when the bitrate is above a // threshold. This is a crude way of handling loss which is uncorrelated // to congestion. - if (current_bitrate_ < bitrate_threshold_ || loss <= low_loss_threshold_) { + if (current_target_ < bitrate_threshold_ || loss <= low_loss_threshold_) { // Loss < 2%: Increase rate by 8% of the min bitrate in the last // kBweIncreaseInterval. // Note that by remembering the bitrate over the last second one can @@ -519,14 +549,16 @@ void SendSideBandwidthEstimation::UpdateEstimate(Timestamp at_time) { // If instead one would do: current_bitrate_ *= 1.08^(delta time), // it would take over one second since the lower packet loss to achieve // 108kbps. - new_bitrate = - DataRate::bps(min_bitrate_history_.front().second.bps() * 1.08 + 0.5); + DataRate new_bitrate = DataRate::bps( + min_bitrate_history_.front().second.bps() * 1.08 + 0.5); // Add 1 kbps extra, just to make sure that we do not get stuck // (gives a little extra increase at low rates, negligible at higher // rates). new_bitrate += DataRate::bps(1000); - } else if (current_bitrate_ > bitrate_threshold_) { + UpdateTargetBitrate(new_bitrate, at_time); + return; + } else if (current_target_ > bitrate_threshold_) { if (loss <= high_loss_threshold_) { // Loss between 2% - 10%: Do nothing. } else { @@ -540,31 +572,19 @@ void SendSideBandwidthEstimation::UpdateEstimate(Timestamp at_time) { // Reduce rate: // newRate = rate * (1 - 0.5*lossRate); // where packetLoss = 256*lossRate; - new_bitrate = - DataRate::bps((current_bitrate_.bps() * - static_cast(512 - last_fraction_loss_)) / - 512.0); + DataRate new_bitrate = DataRate::bps( + (current_target_.bps() * + static_cast(512 - last_fraction_loss_)) / + 512.0); has_decreased_since_last_fraction_loss_ = true; + UpdateTargetBitrate(new_bitrate, at_time); + return; } } } - } else if (time_since_loss_feedback > - kFeedbackTimeoutIntervals * kMaxRtcpFeedbackInterval && - (last_timeout_.IsInfinite() || - at_time - last_timeout_ > kTimeoutInterval)) { - if (in_timeout_experiment_) { - MS_WARN_TAG(bwe, "Feedback timed out (%s), reducint bitrate", - ToString(time_since_loss_feedback).c_str()); - new_bitrate = new_bitrate * 0.8; - // Reset accumulators since we've already acted on missing feedback and - // shouldn't to act again on these old lost packets. - lost_packets_since_last_loss_update_ = 0; - expected_packets_since_last_loss_update_ = 0; - last_timeout_ = at_time; - } } - - CapBitrateToThresholds(at_time, new_bitrate); + // TODO(srte): This is likely redundant in most cases. + ApplyTargetLimits(at_time); } void SendSideBandwidthEstimation::UpdatePropagationRtt( @@ -596,86 +616,78 @@ void SendSideBandwidthEstimation::UpdateMinHistory(Timestamp at_time) { // Typical minimum sliding-window algorithm: Pop values higher than current // bitrate before pushing it. while (!min_bitrate_history_.empty() && - current_bitrate_ <= min_bitrate_history_.back().second) { + current_target_ <= min_bitrate_history_.back().second) { min_bitrate_history_.pop_back(); } - min_bitrate_history_.push_back(std::make_pair(at_time, current_bitrate_)); + min_bitrate_history_.push_back(std::make_pair(at_time, current_target_)); } -DataRate SendSideBandwidthEstimation::MaybeRampupOrBackoff(DataRate new_bitrate, - Timestamp at_time) { - // TODO(crodbro): reuse this code in UpdateEstimate instead of current - // inlining of very similar functionality. - const TimeDelta time_since_loss_packet_report = - at_time - last_loss_packet_report_; - const TimeDelta time_since_loss_feedback = at_time - last_loss_feedback_; - if (time_since_loss_packet_report < 1.2 * kMaxRtcpFeedbackInterval) { - new_bitrate = min_bitrate_history_.front().second * 1.08; - new_bitrate += DataRate::bps(1000); - } else if (time_since_loss_feedback > - kFeedbackTimeoutIntervals * kMaxRtcpFeedbackInterval && - (last_timeout_.IsInfinite() || - at_time - last_timeout_ > kTimeoutInterval)) { - if (in_timeout_experiment_) { - MS_WARN_TAG(bwe,"Feedback timed out (%s), reducint bitrate", - ToString(time_since_loss_feedback).c_str()); - new_bitrate = new_bitrate * 0.8; - // Reset accumulators since we've already acted on missing feedback and - // shouldn't to act again on these old lost packets. - lost_packets_since_last_loss_update_ = 0; - expected_packets_since_last_loss_update_ = 0; - last_timeout_ = at_time; - } - } - return new_bitrate; +DataRate SendSideBandwidthEstimation::GetUpperLimit() const { + DataRate upper_limit = delay_based_limit_; + if (disable_receiver_limit_caps_only_) + upper_limit = std::min(upper_limit, receiver_limit_); + return std::min(upper_limit, max_bitrate_configured_); } -void SendSideBandwidthEstimation::CapBitrateToThresholds(Timestamp at_time, - DataRate bitrate) { - if (bwe_incoming_ > DataRate::Zero() && bitrate > bwe_incoming_) { - MS_DEBUG_DEV("bwe_incoming_:%lld", bwe_incoming_.bps()); - bitrate = bwe_incoming_; - } - if (delay_based_bitrate_ > DataRate::Zero() && - bitrate > delay_based_bitrate_) { - MS_DEBUG_DEV("delay_based_bitrate_:%lld", delay_based_bitrate_.bps()); - bitrate = delay_based_bitrate_; - } - if (loss_based_bandwidth_estimation_.Enabled() && - loss_based_bandwidth_estimation_.GetEstimate() > DataRate::Zero()) { - MS_DEBUG_DEV("loss_based_bandwidth_estimation_.GetEstimate():%lld", loss_based_bandwidth_estimation_.GetEstimate().bps()); - bitrate = std::min(bitrate, loss_based_bandwidth_estimation_.GetEstimate()); - } - if (bitrate > max_bitrate_configured_) { - MS_DEBUG_DEV("bitrate > max_bitrate_configured_, setting bitrate to max_bitrate_configured_"); - bitrate = max_bitrate_configured_; - } - if (bitrate < min_bitrate_configured_) { - MS_DEBUG_DEV("bitrate < min_bitrate_configured_"); - if (last_low_bitrate_log_.IsInfinite() || - at_time - last_low_bitrate_log_ > kLowBitrateLogPeriod) { - MS_WARN_TAG(bwe, "Estimated available bandwidth %s" - " is below configured min bitrate %s", - ToString(bitrate).c_str(), - ToString(min_bitrate_configured_).c_str()); - last_low_bitrate_log_ = at_time; - } - bitrate = min_bitrate_configured_; +void SendSideBandwidthEstimation::MaybeLogLowBitrateWarning(DataRate bitrate, + Timestamp at_time) { + if (at_time - last_low_bitrate_log_ > kLowBitrateLogPeriod) { +/* MS_WARN_TAG(bwe, "Estimated available bandwidth %s is below configured min bitrate %s.", + ToString(bitrate), + ToString(min_bitrate_configured_); */ + last_low_bitrate_log_ = at_time; } +} - if (bitrate != current_bitrate_ || +void SendSideBandwidthEstimation::MaybeLogLossBasedEvent(Timestamp at_time) { +/* if (current_target_ != last_logged_target_ || last_fraction_loss_ != last_logged_fraction_loss_ || at_time - last_rtc_event_log_ > kRtcEventLogPeriod) { + event_log_->Log(std::make_unique( + current_target_.bps(), last_fraction_loss_, + expected_packets_since_last_loss_update_)); last_logged_fraction_loss_ = last_fraction_loss_; + last_logged_target_ = current_target_; last_rtc_event_log_ = at_time; - } - MS_DEBUG_DEV("current_bitrate_:%lld", current_bitrate_.bps()); - current_bitrate_ = bitrate; + }*/ +} - if (acknowledged_rate_) { - link_capacity_.OnRateUpdate(std::min(current_bitrate_, *acknowledged_rate_), - at_time); +void SendSideBandwidthEstimation::UpdateTargetBitrate(DataRate new_bitrate, + Timestamp at_time) { + new_bitrate = std::min(new_bitrate, GetUpperLimit()); + if (new_bitrate < min_bitrate_configured_) { + MaybeLogLowBitrateWarning(new_bitrate, at_time); + new_bitrate = min_bitrate_configured_; } + current_target_ = new_bitrate; + MaybeLogLossBasedEvent(at_time); + link_capacity_.OnRateUpdate(acknowledged_rate_, current_target_, at_time); +} + +void SendSideBandwidthEstimation::ApplyTargetLimits(Timestamp at_time) { + UpdateTargetBitrate(current_target_, at_time); +} + +bool SendSideBandwidthEstimation::LossBasedBandwidthEstimatorV1Enabled() const { + return loss_based_bandwidth_estimator_v1_.Enabled() && + !LossBasedBandwidthEstimatorV2Enabled(); } + +bool SendSideBandwidthEstimation::LossBasedBandwidthEstimatorV1ReadyForUse() + const { + return LossBasedBandwidthEstimatorV1Enabled() && + loss_based_bandwidth_estimator_v1_.InUse(); +} + +bool SendSideBandwidthEstimation::LossBasedBandwidthEstimatorV2Enabled() const { + return loss_based_bandwidth_estimator_v2_.IsEnabled(); +} + +bool SendSideBandwidthEstimation::LossBasedBandwidthEstimatorV2ReadyForUse() + const { + return LossBasedBandwidthEstimatorV2Enabled() && + loss_based_bandwidth_estimator_v2_.IsReady(); +} + } // namespace webrtc diff --git a/worker/deps/libwebrtc/libwebrtc/modules/bitrate_controller/send_side_bandwidth_estimation.h b/worker/deps/libwebrtc/libwebrtc/modules/bitrate_controller/send_side_bandwidth_estimation.h index 8c4d217d52..e7a177a1a9 100644 --- a/worker/deps/libwebrtc/libwebrtc/modules/bitrate_controller/send_side_bandwidth_estimation.h +++ b/worker/deps/libwebrtc/libwebrtc/modules/bitrate_controller/send_side_bandwidth_estimation.h @@ -18,6 +18,7 @@ #include "api/units/time_delta.h" #include "api/units/timestamp.h" #include "modules/bitrate_controller/loss_based_bandwidth_estimation.h" +#include "modules/bitrate_controller/loss_based_bwe_v2.h" #include "rtc_base/experiments/field_trial_parser.h" #include @@ -32,9 +33,13 @@ class LinkCapacityTracker { public: LinkCapacityTracker(); ~LinkCapacityTracker(); - void OnOveruse(DataRate acknowledged_rate, Timestamp at_time); + // Call when a new delay-based estimate is available. + void UpdateDelayBasedEstimate(Timestamp at_time, + DataRate delay_based_bitrate); void OnStartingRate(DataRate start_rate); - void OnRateUpdate(DataRate acknowledged, Timestamp at_time); + void OnRateUpdate(absl::optional acknowledged, + DataRate target, + Timestamp at_time); void OnRttBackoff(DataRate backoff_rate, Timestamp at_time); DataRate estimate() const; @@ -42,24 +47,24 @@ class LinkCapacityTracker { FieldTrialParameter tracking_rate; double capacity_estimate_bps_ = 0; Timestamp last_link_capacity_update_ = Timestamp::MinusInfinity(); + DataRate last_delay_based_estimate_ = DataRate::PlusInfinity(); }; class RttBasedBackoff { public: - RttBasedBackoff(); + explicit RttBasedBackoff(const WebRtcKeyValueConfig* key_value_config); ~RttBasedBackoff(); - void OnRouteChange(); void UpdatePropagationRtt(Timestamp at_time, TimeDelta propagation_rtt); TimeDelta CorrectedRtt(Timestamp at_time) const; - FieldTrialParameter rtt_limit_; + FieldTrialFlag disabled_; + FieldTrialParameter configured_limit_; FieldTrialParameter drop_fraction_; FieldTrialParameter drop_interval_; - FieldTrialFlag persist_on_route_change_; - FieldTrialParameter safe_timeout_; FieldTrialParameter bandwidth_floor_; public: + TimeDelta rtt_limit_; Timestamp last_propagation_rtt_update_; TimeDelta last_propagation_rtt_; Timestamp last_packet_sent_; @@ -67,11 +72,17 @@ class RttBasedBackoff { class SendSideBandwidthEstimation { public: - SendSideBandwidthEstimation(); + SendSideBandwidthEstimation() = delete; + SendSideBandwidthEstimation(const WebRtcKeyValueConfig* key_value_config); ~SendSideBandwidthEstimation(); void OnRouteChange(); - void CurrentEstimate(int* bitrate, uint8_t* loss, int64_t* rtt) const; + + DataRate target_rate() const; + LossBasedState loss_based_state() const; + uint8_t fraction_loss() const { return last_fraction_loss_; } + TimeDelta round_trip_time() const { return last_round_trip_time_; } + DataRate GetEstimatedLinkCapacity() const; // Call periodically to update estimate. void UpdateEstimate(Timestamp at_time); @@ -85,14 +96,8 @@ class SendSideBandwidthEstimation { void UpdateDelayBasedEstimate(Timestamp at_time, DataRate bitrate); // Call when we receive a RTCP message with a ReceiveBlock. - void UpdateReceiverBlock(uint8_t fraction_loss, - TimeDelta rtt_ms, - int number_of_packets, - Timestamp at_time); - - // Call when we receive a RTCP message with a ReceiveBlock. - void UpdatePacketsLost(int packets_lost, - int number_of_packets, + void UpdatePacketsLost(int64_t packets_lost, + int64_t number_of_packets, Timestamp at_time); // Call when we receive a RTCP message with a ReceiveBlock. @@ -107,7 +112,11 @@ class SendSideBandwidthEstimation { int GetMinBitrate() const; void SetAcknowledgedRate(absl::optional acknowledged_rate, Timestamp at_time); - void IncomingPacketFeedbackVector(const TransportPacketsFeedback& report); + void UpdateLossBasedEstimator(const TransportPacketsFeedback& report, + BandwidthUsage delay_detector_state, + absl::optional probe_bitrate, + DataRate upper_link_capacity); + LossEstimatorState GetLossEstimatorState() const; private: friend class GoogCcStatePrinter; @@ -123,11 +132,29 @@ class SendSideBandwidthEstimation { // min bitrate used during last kBweIncreaseIntervalMs. void UpdateMinHistory(Timestamp at_time); - DataRate MaybeRampupOrBackoff(DataRate new_bitrate, Timestamp at_time); - - // Cap |bitrate| to [min_bitrate_configured_, max_bitrate_configured_] and - // set |current_bitrate_| to the capped value and updates the event log. - void CapBitrateToThresholds(Timestamp at_time, DataRate bitrate); + // Gets the upper limit for the target bitrate. This is the minimum of the + // delay based limit, the receiver limit and the loss based controller limit. + DataRate GetUpperLimit() const; + // Prints a warning if `bitrate` if sufficiently long time has past since last + // warning. + void MaybeLogLowBitrateWarning(DataRate bitrate, Timestamp at_time); + // Stores an update to the event log if the loss rate has changed, the target + // has changed, or sufficient time has passed since last stored event. + void MaybeLogLossBasedEvent(Timestamp at_time); + + // Cap `bitrate` to [min_bitrate_configured_, max_bitrate_configured_] and + // set `current_bitrate_` to the capped value and updates the event log. + void UpdateTargetBitrate(DataRate bitrate, Timestamp at_time); + // Applies lower and upper bounds to the current target rate. + // TODO(srte): This seems to be called even when limits haven't changed, that + // should be cleaned up. + void ApplyTargetLimits(Timestamp at_time); + + bool LossBasedBandwidthEstimatorV1Enabled() const; + bool LossBasedBandwidthEstimatorV2Enabled() const; + + bool LossBasedBandwidthEstimatorV1ReadyForUse() const; + bool LossBasedBandwidthEstimatorV2ReadyForUse() const; RttBasedBackoff rtt_backoff_; LinkCapacityTracker link_capacity_; @@ -139,7 +166,8 @@ class SendSideBandwidthEstimation { int expected_packets_since_last_loss_update_; absl::optional acknowledged_rate_; - DataRate current_bitrate_; + DataRate current_target_; + DataRate last_logged_target_; DataRate min_bitrate_configured_; DataRate max_bitrate_configured_; Timestamp last_low_bitrate_log_; @@ -147,13 +175,15 @@ class SendSideBandwidthEstimation { bool has_decreased_since_last_fraction_loss_; Timestamp last_loss_feedback_; Timestamp last_loss_packet_report_; - Timestamp last_timeout_; uint8_t last_fraction_loss_; uint8_t last_logged_fraction_loss_; TimeDelta last_round_trip_time_; - DataRate bwe_incoming_; - DataRate delay_based_bitrate_; + // The max bitrate as set by the receiver in the call. This is typically + // signalled using the REMB RTCP message and is used when we don't have any + // send side delay based estimate. + DataRate receiver_limit_; + DataRate delay_based_limit_; Timestamp time_last_decrease_; Timestamp first_report_time_; int initially_lost_packets_; @@ -162,11 +192,13 @@ class SendSideBandwidthEstimation { UmaState uma_rtt_state_; std::vector rampup_uma_stats_updated_; Timestamp last_rtc_event_log_; - bool in_timeout_experiment_; float low_loss_threshold_; float high_loss_threshold_; DataRate bitrate_threshold_; - LossBasedBandwidthEstimation loss_based_bandwidth_estimation_; + LossBasedBandwidthEstimation loss_based_bandwidth_estimator_v1_; + LossBasedBweV2 loss_based_bandwidth_estimator_v2_; + LossBasedState loss_based_state_; + FieldTrialFlag disable_receiver_limit_caps_only_; }; } // namespace webrtc #endif // MODULES_BITRATE_CONTROLLER_SEND_SIDE_BANDWIDTH_ESTIMATION_H_ diff --git a/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator.h b/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator.h index dcfebf2649..95755697ef 100644 --- a/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator.h +++ b/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator.h @@ -14,6 +14,7 @@ #include "api/transport/network_types.h" #include "api/transport/webrtc_key_value_config.h" #include "api/units/data_rate.h" +#include "modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator_interface.h" #include "modules/congestion_controller/goog_cc/bitrate_estimator.h" #include @@ -22,7 +23,8 @@ namespace webrtc { -class AcknowledgedBitrateEstimator { +class AcknowledgedBitrateEstimator + : public AcknowledgedBitrateEstimatorInterface { public: AcknowledgedBitrateEstimator( const WebRtcKeyValueConfig* key_value_config, @@ -30,14 +32,14 @@ class AcknowledgedBitrateEstimator { explicit AcknowledgedBitrateEstimator( const WebRtcKeyValueConfig* key_value_config); - ~AcknowledgedBitrateEstimator(); + ~AcknowledgedBitrateEstimator() override; void IncomingPacketFeedbackVector( - const std::vector& packet_feedback_vector); - absl::optional bitrate() const; - absl::optional PeekRate() const; - void SetAlr(bool in_alr); - void SetAlrEndedTime(Timestamp alr_ended_time); + const std::vector& packet_feedback_vector) override; + absl::optional bitrate() const override; + absl::optional PeekRate() const override; + void SetAlr(bool in_alr) override; + void SetAlrEndedTime(Timestamp alr_ended_time) override; private: absl::optional alr_ended_time_; diff --git a/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator_interface.cc b/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator_interface.cc new file mode 100644 index 0000000000..be4020f3e8 --- /dev/null +++ b/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator_interface.cc @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2019 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. + */ +#define MS_CLASS "webrtc::AcknowledgedBitrateEstimator" + +#include "modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator_interface.h" + +#include + +#include "api/units/time_delta.h" +#include "modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator.h" +#include "modules/congestion_controller/goog_cc/robust_throughput_estimator.h" +#include "api/transport/webrtc_key_value_config.h" +#include "Logger.hpp" +// #include "rtc_base/logging.h" + +namespace webrtc { + +constexpr char RobustThroughputEstimatorSettings::kKey[]; + +RobustThroughputEstimatorSettings::RobustThroughputEstimatorSettings( + const WebRtcKeyValueConfig* key_value_config) { + Parser()->Parse( + key_value_config->Lookup(RobustThroughputEstimatorSettings::kKey)); + if (window_packets < 10 || 1000 < window_packets) { + MS_WARN_TAG(bwe, "window size must be between 10 and 1000 packets"); + window_packets = 20; + } + if (max_window_packets < 10 || 1000 < max_window_packets) { + MS_WARN_TAG(bwe, "max window size must be between 10 and 1000 packets"); + max_window_packets = 500; + } + max_window_packets = std::max(max_window_packets, window_packets); + + if (required_packets < 10 || 1000 < required_packets) { + MS_WARN_TAG(bwe, "required number of initial packets must be between " + "10 and 1000 packets"); + required_packets = 10; + } + required_packets = std::min(required_packets, window_packets); + + if (min_window_duration < TimeDelta::Millis<100>() || + TimeDelta::Millis<3000>() < min_window_duration) { + MS_WARN_TAG(bwe, "window duration must be between 100 and 3000 ms"); + min_window_duration = TimeDelta::Millis<750>(); + } + if (max_window_duration < TimeDelta::Seconds<1>() || + TimeDelta::Seconds<15>() < max_window_duration) { + MS_WARN_TAG(bwe, "max window duration must be between 1 and 15 seconds"); + max_window_duration = TimeDelta::Seconds<5>(); + } + min_window_duration = std::min(min_window_duration, max_window_duration); + + if (unacked_weight < 0.0 || 1.0 < unacked_weight) { + MS_WARN_TAG(bwe, "weight for prior unacked size must be between 0 and 1"); + unacked_weight = 1.0; + } +} + +std::unique_ptr +RobustThroughputEstimatorSettings::Parser() { + return StructParametersParser::Create( + "enabled", &enabled, // + "window_packets", &window_packets, // + "max_window_packets", &max_window_packets, // + "window_duration", &min_window_duration, // + "max_window_duration", &max_window_duration, // + "required_packets", &required_packets, // + "unacked_weight", &unacked_weight); +} + +AcknowledgedBitrateEstimatorInterface:: + ~AcknowledgedBitrateEstimatorInterface() {} + +std::unique_ptr +AcknowledgedBitrateEstimatorInterface::Create( + const WebRtcKeyValueConfig* key_value_config) { + RobustThroughputEstimatorSettings simplified_estimator_settings( + key_value_config); + if (simplified_estimator_settings.enabled) { + return absl::make_unique( + simplified_estimator_settings); + } + return absl::make_unique(key_value_config); +} + +} // namespace webrtc diff --git a/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator_interface.h b/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator_interface.h new file mode 100644 index 0000000000..a8c1330190 --- /dev/null +++ b/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator_interface.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2019 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_GOOG_CC_ACKNOWLEDGED_BITRATE_ESTIMATOR_INTERFACE_H_ +#define MODULES_CONGESTION_CONTROLLER_GOOG_CC_ACKNOWLEDGED_BITRATE_ESTIMATOR_INTERFACE_H_ + +#include + +#include +#include + +#include "absl/types/optional.h" +// #include "api/field_trials_view.h" +#include "api/transport/network_types.h" +#include "api/units/data_rate.h" +#include "api/units/time_delta.h" +#include "api/units/timestamp.h" +#include "rtc_base/experiments/struct_parameters_parser.h" +#include "api/transport/webrtc_key_value_config.h" + + +namespace webrtc { + +struct RobustThroughputEstimatorSettings { + static constexpr char kKey[] = "WebRTC-Bwe-RobustThroughputEstimatorSettings"; + + RobustThroughputEstimatorSettings() = delete; + explicit RobustThroughputEstimatorSettings( + const WebRtcKeyValueConfig* key_value_config); + + bool enabled = false; // Set to true to use RobustThroughputEstimator. + + // The estimator keeps the smallest window containing at least + // `window_packets` and at least the packets received during the last + // `min_window_duration` milliseconds. + // (This means that it may store more than `window_packets` at high bitrates, + // and a longer duration than `min_window_duration` at low bitrates.) + // However, if will never store more than kMaxPackets (for performance + // reasons), and never longer than max_window_duration (to avoid very old + // packets influencing the estimate for example when sending is paused). + unsigned window_packets = 20; + unsigned max_window_packets = 50; + TimeDelta min_window_duration = TimeDelta::Seconds<1>(); + TimeDelta max_window_duration = TimeDelta::Seconds<3>(); + + // The estimator window requires at least `required_packets` packets + // to produce an estimate. + unsigned required_packets = 10; + + // If audio packets aren't included in allocation (i.e. the + // estimated available bandwidth is divided only among the video + // streams), then `unacked_weight` should be set to 0. + // If audio packets are included in allocation, but not in bandwidth + // estimation (i.e. they don't have transport-wide sequence numbers, + // but we nevertheless divide the estimated available bandwidth among + // both audio and video streams), then `unacked_weight` should be set to 1. + // If all packets have transport-wide sequence numbers, then the value + // of `unacked_weight` doesn't matter. + double unacked_weight = 1.0; + + std::unique_ptr Parser(); +}; + +class AcknowledgedBitrateEstimatorInterface { + public: + static std::unique_ptr Create( + const WebRtcKeyValueConfig* key_value_config); + virtual ~AcknowledgedBitrateEstimatorInterface(); + + virtual void IncomingPacketFeedbackVector( + const std::vector& packet_feedback_vector) = 0; + virtual absl::optional bitrate() const = 0; + virtual absl::optional PeekRate() const = 0; + virtual void SetAlr(bool in_alr) = 0; + virtual void SetAlrEndedTime(Timestamp alr_ended_time) = 0; +}; + +} // namespace webrtc + +#endif // MODULES_CONGESTION_CONTROLLER_GOOG_CC_ACKNOWLEDGED_BITRATE_ESTIMATOR_INTERFACE_H_ diff --git a/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/alr_detector.cc b/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/alr_detector.cc index 95a000d346..3b12676c99 100644 --- a/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/alr_detector.cc +++ b/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/alr_detector.cc @@ -24,7 +24,7 @@ namespace webrtc { namespace { -absl::optional GetExperimentSettings( +AlrDetectorConfig GetExperimentSettings( const WebRtcKeyValueConfig* key_value_config) { // RTC_CHECK(AlrExperimentSettings::MaxOneFieldTrialEnabled(*key_value_config)); absl::optional experiment_settings = @@ -36,40 +36,47 @@ absl::optional GetExperimentSettings( *key_value_config, AlrExperimentSettings::kStrictPacingAndProbingExperimentName); } - return experiment_settings; + AlrDetectorConfig conf; + if (experiment_settings) { + conf.bandwidth_usage_ratio = + experiment_settings->alr_bandwidth_usage_percent / 100.0; + conf.start_budget_level_ratio = + experiment_settings->alr_start_budget_level_percent / 100.0; + conf.stop_budget_level_ratio = + experiment_settings->alr_stop_budget_level_percent / 100.0; + } + conf.Parser()->Parse( + key_value_config->Lookup("WebRTC-AlrDetectorParameters")); + return conf; } } // namespace -AlrDetector::AlrDetector(const WebRtcKeyValueConfig* key_value_config) - : AlrDetector(key_value_config, - GetExperimentSettings(key_value_config)) {} - -AlrDetector::AlrDetector( - const WebRtcKeyValueConfig* key_value_config, - absl::optional experiment_settings) - : bandwidth_usage_ratio_( - "bw_usage", - experiment_settings - ? experiment_settings->alr_bandwidth_usage_percent / 100.0 - : kDefaultBandwidthUsageRatio), - start_budget_level_ratio_( - "start", - experiment_settings - ? experiment_settings->alr_start_budget_level_percent / 100.0 - : kDefaultStartBudgetLevelRatio), - stop_budget_level_ratio_( - "stop", - experiment_settings - ? experiment_settings->alr_stop_budget_level_percent / 100.0 - : kDefaultStopBudgetLevelRatio), - alr_budget_(0, true) { - ParseFieldTrial({&bandwidth_usage_ratio_, &start_budget_level_ratio_, - &stop_budget_level_ratio_}, - key_value_config->Lookup("WebRTC-AlrDetectorParameters")); +std::unique_ptr AlrDetectorConfig::Parser() { + return StructParametersParser::Create( // + "bw_usage", &bandwidth_usage_ratio, // + "start", &start_budget_level_ratio, // + "stop", &stop_budget_level_ratio); } +AlrDetector::AlrDetector(AlrDetectorConfig config) + : conf_(config), alr_budget_(0, true) {} + +AlrDetector::AlrDetector(const WebRtcKeyValueConfig* key_value_config) + : AlrDetector(GetExperimentSettings(key_value_config)) {} + AlrDetector::~AlrDetector() {} +// This is used to trigger ALR start state if we had sudden stop in traffic (all consumers paused due to low bw report). +// if no traffic in 1 second, trigger on OnBytesSent with 0 bitrate to update budgets. +void AlrDetector::Process() { + int64_t now = DepLibUV::GetTimeMsInt64(); + if (!alr_started_time_ms_.has_value() && last_send_time_ms_.has_value()) { + if ((now - last_send_time_ms_.value()) > 1000) { + OnBytesSent(0, now); + } + } +} + void AlrDetector::OnBytesSent(size_t bytes_sent, int64_t send_time_ms) { if (!last_send_time_ms_.has_value()) { last_send_time_ms_ = send_time_ms; @@ -83,25 +90,30 @@ void AlrDetector::OnBytesSent(size_t bytes_sent, int64_t send_time_ms) { alr_budget_.UseBudget(bytes_sent); alr_budget_.IncreaseBudget(delta_time_ms); bool state_changed = false; - if (alr_budget_.budget_ratio() > start_budget_level_ratio_ && + if (alr_budget_.budget_ratio() > conf_.start_budget_level_ratio && !alr_started_time_ms_) { alr_started_time_ms_.emplace(DepLibUV::GetTimeMsInt64()); state_changed = true; - } else if (alr_budget_.budget_ratio() < stop_budget_level_ratio_ && + } else if (alr_budget_.budget_ratio() < conf_.stop_budget_level_ratio && alr_started_time_ms_) { state_changed = true; alr_started_time_ms_.reset(); } - - if (state_changed) - MS_DEBUG_DEV("state changed"); + if (state_changed) { + MS_DEBUG_TAG(bwe, "ALR state change"); + } } void AlrDetector::SetEstimatedBitrate(int bitrate_bps) { //RTC_DCHECK(bitrate_bps); - int target_rate_kbps = - static_cast(bitrate_bps) * bandwidth_usage_ratio_ / 1000; - alr_budget_.set_target_rate_kbps(target_rate_kbps); + + if (last_estimated_bitrate_ != bitrate_bps) { + last_estimated_bitrate_ = bitrate_bps; + MS_DEBUG_TAG(bwe, "setting ALR bitrate to %d bps", bitrate_bps); + int target_rate_kbps = + static_cast(bitrate_bps) * conf_.bandwidth_usage_ratio / 1000; + alr_budget_.set_target_rate_kbps(target_rate_kbps); + } } absl::optional AlrDetector::GetApplicationLimitedRegionStartTime() diff --git a/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/alr_detector.h b/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/alr_detector.h index e1fbb74525..2b3561a50a 100644 --- a/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/alr_detector.h +++ b/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/alr_detector.h @@ -15,6 +15,7 @@ #include "modules/pacing/interval_budget.h" #include "rtc_base/experiments/alr_experiment.h" #include "rtc_base/experiments/field_trial_units.h" +#include "rtc_base/experiments/struct_parameters_parser.h" #include #include @@ -23,6 +24,19 @@ namespace webrtc { +class RtcEventLog; + +struct AlrDetectorConfig { + // Sent traffic ratio as a function of network capacity used to determine + // application-limited region. ALR region start when bandwidth usage drops + // below kAlrStartUsageRatio and ends when it raises above + // kAlrEndUsageRatio. NOTE: This is intentionally conservative at the moment + // until BW adjustments of application limited region is fine tuned. + double bandwidth_usage_ratio = 0.65; + double start_budget_level_ratio = 0.80; + double stop_budget_level_ratio = 0.50; + std::unique_ptr Parser(); +}; // Application limited region detector is a class that utilizes signals of // elapsed time and bytes sent to estimate whether network traffic is // currently limited by the application's ability to generate traffic. @@ -32,6 +46,7 @@ namespace webrtc { // Note: This class is not thread-safe. class AlrDetector { public: + AlrDetector(AlrDetectorConfig config); explicit AlrDetector(const WebRtcKeyValueConfig* key_value_config); ~AlrDetector(); @@ -43,30 +58,14 @@ class AlrDetector { // Returns time in milliseconds when the current application-limited region // started or empty result if the sender is currently not application-limited. absl::optional GetApplicationLimitedRegionStartTime() const; - - void UpdateBudgetWithElapsedTime(int64_t delta_time_ms); - void UpdateBudgetWithBytesSent(size_t bytes_sent); + void Process(); private: - // Sent traffic ratio as a function of network capacity used to determine - // application-limited region. ALR region start when bandwidth usage drops - // below kAlrStartUsageRatio and ends when it raises above - // kAlrEndUsageRatio. NOTE: This is intentionally conservative at the moment - // until BW adjustments of application limited region is fine tuned. - static constexpr double kDefaultBandwidthUsageRatio = 0.65; - static constexpr double kDefaultStartBudgetLevelRatio = 0.80; - static constexpr double kDefaultStopBudgetLevelRatio = 0.50; - - AlrDetector(const WebRtcKeyValueConfig* key_value_config, - absl::optional experiment_settings); - friend class GoogCcStatePrinter; - FieldTrialParameter bandwidth_usage_ratio_; - FieldTrialParameter start_budget_level_ratio_; - FieldTrialParameter stop_budget_level_ratio_; + const AlrDetectorConfig conf_; absl::optional last_send_time_ms_; - + int last_estimated_bitrate_; IntervalBudget alr_budget_; absl::optional alr_started_time_ms_; }; diff --git a/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/bitrate_estimator.cc b/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/bitrate_estimator.cc index d0e2cb056b..6764eba95c 100644 --- a/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/bitrate_estimator.cc +++ b/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/bitrate_estimator.cc @@ -44,7 +44,9 @@ BitrateEstimator::BitrateEstimator(const WebRtcKeyValueConfig* key_value_config) kMinRateWindowMs, kMaxRateWindowMs), uncertainty_scale_("scale", 10.0), - uncertainty_scale_in_alr_("scale_alr", 10.0), + uncertainty_scale_in_alr_("scale_alr", uncertainty_scale_), + small_sample_uncertainty_scale_("scale_small", uncertainty_scale_), + small_sample_threshold_("small_thresh", DataSize::Zero()), uncertainty_symmetry_cap_("symmetry_cap", DataRate::Zero()), estimate_floor_("floor", DataRate::Zero()), current_window_ms_(0), @@ -52,22 +54,24 @@ BitrateEstimator::BitrateEstimator(const WebRtcKeyValueConfig* key_value_config) bitrate_estimate_kbps_(-1.0f), bitrate_estimate_var_(50.0f) { // E.g WebRTC-BweThroughputWindowConfig/initial_window_ms:350,window_ms:250/ - ParseFieldTrial({&initial_window_ms_, &noninitial_window_ms_, - &uncertainty_scale_, &uncertainty_scale_in_alr_, - &uncertainty_symmetry_cap_, &estimate_floor_}, - key_value_config->Lookup(kBweThroughputWindowConfig)); + ParseFieldTrial( + {&initial_window_ms_, &noninitial_window_ms_, &uncertainty_scale_, + &uncertainty_scale_in_alr_, &small_sample_uncertainty_scale_, + &small_sample_threshold_, &uncertainty_symmetry_cap_, &estimate_floor_}, + key_value_config->Lookup(kBweThroughputWindowConfig)); } BitrateEstimator::~BitrateEstimator() = default; void BitrateEstimator::Update(Timestamp at_time, DataSize amount, bool in_alr) { - int rate_window_ms = noninitial_window_ms_; + int rate_window_ms = noninitial_window_ms_.Get(); // We use a larger window at the beginning to get a more stable sample that // we can use to initialize the estimate. if (bitrate_estimate_kbps_ < 0.f) - rate_window_ms = initial_window_ms_; - float bitrate_sample_kbps = - UpdateWindow(at_time.ms(), amount.bytes(), rate_window_ms); + rate_window_ms = initial_window_ms_.Get(); + bool is_small_sample = false; + float bitrate_sample_kbps = UpdateWindow(at_time.ms(), amount.bytes(), + rate_window_ms, &is_small_sample); if (bitrate_sample_kbps < 0.0f) return; if (bitrate_estimate_kbps_ < 0.0f) { @@ -75,15 +79,19 @@ void BitrateEstimator::Update(Timestamp at_time, DataSize amount, bool in_alr) { bitrate_estimate_kbps_ = bitrate_sample_kbps; return; } - // Define the sample uncertainty as a function of how far away it is from the - // current estimate. With low values of uncertainty_symmetry_cap_ we add more - // uncertainty to increases than to decreases. For higher values we approach - // symmetry. + // Optionally use higher uncertainty for very small samples to avoid dropping + // estimate and for samples obtained in ALR. float scale = uncertainty_scale_; - if (in_alr && bitrate_sample_kbps < bitrate_estimate_kbps_) { + if (is_small_sample && bitrate_sample_kbps < bitrate_estimate_kbps_) { + scale = small_sample_uncertainty_scale_; + } else if (in_alr && bitrate_sample_kbps < bitrate_estimate_kbps_) { // Optionally use higher uncertainty for samples obtained during ALR. scale = uncertainty_scale_in_alr_; } + // Define the sample uncertainty as a function of how far away it is from the + // current estimate. With low values of uncertainty_symmetry_cap_ we add more + // uncertainty to increases than to decreases. For higher values we approach + // symmetry. float sample_uncertainty = scale * std::abs(bitrate_estimate_kbps_ - bitrate_sample_kbps) / (bitrate_estimate_kbps_ + @@ -110,7 +118,8 @@ void BitrateEstimator::Update(Timestamp at_time, DataSize amount, bool in_alr) { float BitrateEstimator::UpdateWindow(int64_t now_ms, int bytes, - int rate_window_ms) { + int rate_window_ms, + bool* is_small_sample) { // Reset if time moves backwards. if (now_ms < prev_time_ms_) { prev_time_ms_ = -1; @@ -128,6 +137,7 @@ float BitrateEstimator::UpdateWindow(int64_t now_ms, prev_time_ms_ = now_ms; float bitrate_sample = -1.0f; if (current_window_ms_ >= rate_window_ms) { + *is_small_sample = sum_ < small_sample_threshold_->bytes(); bitrate_sample = 8.0f * sum_ / static_cast(rate_window_ms); current_window_ms_ -= rate_window_ms; sum_ = 0; diff --git a/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/bitrate_estimator.h b/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/bitrate_estimator.h index 324eac53eb..d1fd754997 100644 --- a/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/bitrate_estimator.h +++ b/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/bitrate_estimator.h @@ -38,12 +38,17 @@ class BitrateEstimator { virtual void ExpectFastRateChange(); private: - float UpdateWindow(int64_t now_ms, int bytes, int rate_window_ms); + float UpdateWindow(int64_t now_ms, + int bytes, + int rate_window_ms, + bool* is_small_sample); int sum_; FieldTrialConstrained initial_window_ms_; FieldTrialConstrained noninitial_window_ms_; FieldTrialParameter uncertainty_scale_; FieldTrialParameter uncertainty_scale_in_alr_; + FieldTrialParameter small_sample_uncertainty_scale_; + FieldTrialParameter small_sample_threshold_; FieldTrialParameter uncertainty_symmetry_cap_; FieldTrialParameter estimate_floor_; int64_t current_window_ms_; diff --git a/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/congestion_window_pushback_controller.cc b/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/congestion_window_pushback_controller.cc index 53b9bd4c96..fdfc4a16c7 100644 --- a/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/congestion_window_pushback_controller.cc +++ b/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/congestion_window_pushback_controller.cc @@ -44,15 +44,6 @@ void CongestionWindowPushbackController::UpdatePacingQueue( pacing_bytes_ = pacing_bytes; } -void CongestionWindowPushbackController::UpdateMaxOutstandingData( - size_t max_outstanding_bytes) { - DataSize data_window = DataSize::bytes(max_outstanding_bytes); - if (current_data_window_) { - data_window = (data_window + current_data_window_.value()) / 2; - } - current_data_window_ = data_window; -} - void CongestionWindowPushbackController::SetDataWindow(DataSize data_window) { current_data_window_ = data_window; } diff --git a/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/congestion_window_pushback_controller.h b/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/congestion_window_pushback_controller.h index 38d817c9fd..479334182c 100644 --- a/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/congestion_window_pushback_controller.h +++ b/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/congestion_window_pushback_controller.h @@ -34,7 +34,6 @@ class CongestionWindowPushbackController { uint32_t min_pushback_target_bitrate_bps); void UpdateOutstandingData(int64_t outstanding_bytes); void UpdatePacingQueue(int64_t pacing_bytes); - void UpdateMaxOutstandingData(size_t max_outstanding_bytes); uint32_t UpdateTargetBitrate(uint32_t bitrate_bps); void SetDataWindow(DataSize data_window); diff --git a/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/delay_based_bwe.cc b/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/delay_based_bwe.cc index 57f4afa146..2ac627de5a 100644 --- a/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/delay_based_bwe.cc +++ b/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/delay_based_bwe.cc @@ -26,50 +26,53 @@ namespace webrtc { namespace { constexpr TimeDelta kStreamTimeOut = TimeDelta::Seconds<2>(); -constexpr int kTimestampGroupLengthMs = 5; -constexpr int kAbsSendTimeFraction = 18; -constexpr int kAbsSendTimeInterArrivalUpshift = 8; -constexpr int kInterArrivalShift = - kAbsSendTimeFraction + kAbsSendTimeInterArrivalUpshift; -constexpr double kTimestampToMs = - 1000.0 / static_cast(1 << kInterArrivalShift); +constexpr TimeDelta kSendTimeGroupLength = TimeDelta::Millis<5>(); + // This ssrc is used to fulfill the current API but will be removed // after the API has been changed. constexpr uint32_t kFixedSsrc = 0; - } // namespace +constexpr char BweSeparateAudioPacketsSettings::kKey[]; + +BweSeparateAudioPacketsSettings::BweSeparateAudioPacketsSettings( + const WebRtcKeyValueConfig* key_value_config) { + Parser()->Parse( + key_value_config->Lookup(BweSeparateAudioPacketsSettings::kKey)); +} + +std::unique_ptr +BweSeparateAudioPacketsSettings::Parser() { + return StructParametersParser::Create( // + "enabled", &enabled, // + "packet_threshold", &packet_threshold, // + "time_threshold", &time_threshold); +} + DelayBasedBwe::Result::Result() : updated(false), probe(false), target_bitrate(DataRate::Zero()), - recovered_from_overuse(false), - backoff_in_alr(false) {} - -DelayBasedBwe::Result::Result(bool probe, DataRate target_bitrate) - : updated(true), - probe(probe), - target_bitrate(target_bitrate), - recovered_from_overuse(false), - backoff_in_alr(false) {} - -DelayBasedBwe::Result::~Result() {} + recovered_from_overuse(false) {} DelayBasedBwe::DelayBasedBwe(const WebRtcKeyValueConfig* key_value_config, NetworkStatePredictor* network_state_predictor) : key_value_config_(key_value_config), + separate_audio_(key_value_config), + audio_packets_since_last_video_(0), + last_video_packet_recv_time_(Timestamp::MinusInfinity()), network_state_predictor_(network_state_predictor), - inter_arrival_(), - delay_detector_( + video_delay_detector_( new TrendlineEstimator(key_value_config_, network_state_predictor_)), + audio_delay_detector_( + new TrendlineEstimator(key_value_config_, network_state_predictor_)), + active_delay_detector_(video_delay_detector_.get()), last_seen_packet_(Timestamp::MinusInfinity()), uma_recorded_(false), rate_control_(key_value_config, /*send_side=*/true), prev_bitrate_(DataRate::Zero()), - prev_state_(BandwidthUsage::kBwNormal), - alr_limited_backoff_enabled_( - key_value_config->Lookup("WebRTC-Bwe-AlrLimitedBackoff") - .find("Enabled") == 0) {} + prev_state_(BandwidthUsage::kBwNormal) { +} DelayBasedBwe::~DelayBasedBwe() {} @@ -95,15 +98,15 @@ DelayBasedBwe::Result DelayBasedBwe::IncomingPacketFeedbackVector( } bool delayed_feedback = true; bool recovered_from_overuse = false; - BandwidthUsage prev_detector_state = delay_detector_->State(); + BandwidthUsage prev_detector_state = active_delay_detector_->State(); for (const auto& packet_feedback : packet_feedback_vector) { delayed_feedback = false; IncomingPacketFeedback(packet_feedback, msg.feedback_time); if (prev_detector_state == BandwidthUsage::kBwUnderusing && - delay_detector_->State() == BandwidthUsage::kBwNormal) { + active_delay_detector_->State() == BandwidthUsage::kBwNormal) { recovered_from_overuse = true; } - prev_detector_state = delay_detector_->State(); + prev_detector_state = active_delay_detector_->State(); } if (delayed_feedback) { @@ -123,36 +126,58 @@ void DelayBasedBwe::IncomingPacketFeedback(const PacketResult& packet_feedback, // Reset if the stream has timed out. if (last_seen_packet_.IsInfinite() || at_time - last_seen_packet_ > kStreamTimeOut) { - inter_arrival_.reset( - new InterArrival((kTimestampGroupLengthMs << kInterArrivalShift) / 1000, - kTimestampToMs, true)); - delay_detector_.reset( + video_inter_arrival_delta_ = + absl::make_unique(kSendTimeGroupLength); + audio_inter_arrival_delta_ = + absl::make_unique(kSendTimeGroupLength); + + video_delay_detector_.reset( new TrendlineEstimator(key_value_config_, network_state_predictor_)); + audio_delay_detector_.reset( + new TrendlineEstimator(key_value_config_, network_state_predictor_)); + active_delay_detector_ = video_delay_detector_.get(); } last_seen_packet_ = at_time; - uint32_t send_time_24bits = - static_cast( - ((static_cast(packet_feedback.sent_packet.send_time.ms()) - << kAbsSendTimeFraction) + - 500) / - 1000) & - 0x00FFFFFF; - // Shift up send time to use the full 32 bits that inter_arrival works with, - // so wrapping works properly. - uint32_t timestamp = send_time_24bits << kAbsSendTimeInterArrivalUpshift; - - uint32_t ts_delta = 0; - int64_t t_delta = 0; + // As an alternative to ignoring small packets, we can separate audio and + // video packets for overuse detection. + DelayIncreaseDetectorInterface* delay_detector_for_packet = + video_delay_detector_.get(); + if (separate_audio_.enabled) { + if (packet_feedback.sent_packet.audio) { + delay_detector_for_packet = audio_delay_detector_.get(); + audio_packets_since_last_video_++; + if (audio_packets_since_last_video_ > separate_audio_.packet_threshold && + packet_feedback.receive_time - last_video_packet_recv_time_ > + separate_audio_.time_threshold) { + active_delay_detector_ = audio_delay_detector_.get(); + } + } else { + audio_packets_since_last_video_ = 0; + last_video_packet_recv_time_ = + std::max(last_video_packet_recv_time_, packet_feedback.receive_time); + active_delay_detector_ = video_delay_detector_.get(); + } + } + DataSize packet_size = packet_feedback.sent_packet.size; + + TimeDelta send_delta = TimeDelta::Zero(); + TimeDelta recv_delta = TimeDelta::Zero(); int size_delta = 0; - bool calculated_deltas = inter_arrival_->ComputeDeltas( - timestamp, packet_feedback.receive_time.ms(), at_time.ms(), - packet_feedback.sent_packet.size.bytes(), &ts_delta, &t_delta, - &size_delta); - double ts_delta_ms = (1000.0 * ts_delta) / (1 << kInterArrivalShift); - delay_detector_->Update(t_delta, ts_delta_ms, - packet_feedback.sent_packet.send_time.ms(), - packet_feedback.receive_time.ms(), calculated_deltas); + + InterArrivalDelta* inter_arrival_for_packet = + (separate_audio_.enabled && packet_feedback.sent_packet.audio) + ? audio_inter_arrival_delta_.get() + : video_inter_arrival_delta_.get(); + bool calculated_deltas = inter_arrival_for_packet->ComputeDeltas( + packet_feedback.sent_packet.send_time, packet_feedback.receive_time, + at_time, packet_size.bytes(), &send_delta, &recv_delta, &size_delta); + + delay_detector_for_packet->Update(recv_delta.ms(), + send_delta.ms(), + packet_feedback.sent_packet.send_time.ms(), + packet_feedback.receive_time.ms(), + packet_size.bytes(), calculated_deltas); } DataRate DelayBasedBwe::TriggerOveruse(Timestamp at_time, @@ -171,27 +196,14 @@ DelayBasedBwe::Result DelayBasedBwe::MaybeUpdateEstimate( Result result; // Currently overusing the bandwidth. - if (delay_detector_->State() == BandwidthUsage::kBwOverusing) { - MS_DEBUG_DEV("delay_detector_->State() == BandwidthUsage::kBwOverusing"); - MS_DEBUG_DEV("in_alr: %s", in_alr ? "true" : "false"); - if (in_alr && alr_limited_backoff_enabled_) { - if (rate_control_.TimeToReduceFurther(at_time, prev_bitrate_)) { - MS_DEBUG_DEV("alr_limited_backoff_enabled_ is true, prev_bitrate:%lld, result.target_bitrate:%lld", - prev_bitrate_.bps(), - result.target_bitrate.bps()); - - result.updated = - UpdateEstimate(at_time, prev_bitrate_, &result.target_bitrate); - result.backoff_in_alr = true; - } - } else if (acked_bitrate && - rate_control_.TimeToReduceFurther(at_time, *acked_bitrate)) { - MS_DEBUG_DEV("acked_bitrate:%lld, result.target_bitrate:%lld", - acked_bitrate.value().bps(), - result.target_bitrate.bps()); + if (active_delay_detector_->State() == BandwidthUsage::kBwOverusing) { + if (acked_bitrate && + rate_control_.TimeToReduceFurther(at_time, *acked_bitrate)) { result.updated = UpdateEstimate(at_time, acked_bitrate, &result.target_bitrate); - } else if (!acked_bitrate && rate_control_.ValidEstimate() && + } + // MS_NOTE: This is the job of loss estimator + /*else if (!acked_bitrate && rate_control_.ValidEstimate() && rate_control_.InitialTimeToReduceFurther(at_time)) { // Overusing before we have a measured acknowledged bitrate. Reduce send // rate by 50% every 200 ms. @@ -202,21 +214,21 @@ DelayBasedBwe::Result DelayBasedBwe::MaybeUpdateEstimate( result.updated = true; result.probe = false; result.target_bitrate = rate_control_.LatestEstimate(); - } + }*/ } else { if (probe_bitrate) { MS_DEBUG_DEV("probe bitrate: %lld", probe_bitrate.value().bps()); result.probe = true; result.updated = true; - result.target_bitrate = *probe_bitrate; rate_control_.SetEstimate(*probe_bitrate, at_time); + result.target_bitrate = rate_control_.LatestEstimate(); } else { result.updated = UpdateEstimate(at_time, acked_bitrate, &result.target_bitrate); result.recovered_from_overuse = recovered_from_overuse; } } - BandwidthUsage detector_state = delay_detector_->State(); + BandwidthUsage detector_state = active_delay_detector_->State(); if ((result.updated && prev_bitrate_ != result.target_bitrate) || detector_state != prev_state_) { DataRate bitrate = result.updated ? result.target_bitrate : prev_bitrate_; @@ -229,13 +241,15 @@ DelayBasedBwe::Result DelayBasedBwe::MaybeUpdateEstimate( prev_state_ = detector_state; } + + result.delay_detector_state = detector_state; return result; } bool DelayBasedBwe::UpdateEstimate(Timestamp at_time, absl::optional acked_bitrate, DataRate* target_rate) { - const RateControlInput input(delay_detector_->State(), acked_bitrate); + const RateControlInput input(active_delay_detector_->State(), acked_bitrate); *target_rate = rate_control_.Update(&input, at_time); return rate_control_.ValidEstimate(); } @@ -285,8 +299,14 @@ TimeDelta DelayBasedBwe::GetExpectedBwePeriod() const { return rate_control_.GetExpectedBandwidthPeriod(); } -void DelayBasedBwe::SetAlrLimitedBackoffExperiment(bool enabled) { - alr_limited_backoff_enabled_ = enabled; +DelayBasedBweState DelayBasedBwe::GetState() const +{ + DelayBasedBweState state; + state.rate_control_state = rate_control_.GetRateControlState(); + state.delay_detector_state = prev_state_; + state.trend = active_delay_detector_->GetTrend(); + state.threshold = active_delay_detector_->GetThreshold(); + return state; } } // namespace webrtc diff --git a/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/delay_based_bwe.h b/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/delay_based_bwe.h index e29340ec65..3d5c28a261 100644 --- a/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/delay_based_bwe.h +++ b/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/delay_based_bwe.h @@ -19,7 +19,10 @@ #include "modules/remote_bitrate_estimator/aimd_rate_control.h" #include "modules/remote_bitrate_estimator/include/bwe_defines.h" #include "modules/remote_bitrate_estimator/inter_arrival.h" +#include "modules/congestion_controller/goog_cc/inter_arrival_delta.h" #include "rtc_base/constructor_magic.h" +#include "rtc_base/experiments/struct_parameters_parser.h" +// #include "rtc_base/race_checker.h" #include #include @@ -31,21 +34,39 @@ namespace webrtc { class RtcEventLog; +struct BweSeparateAudioPacketsSettings { + static constexpr char kKey[] = "WebRTC-Bwe-SeparateAudioPackets"; + + BweSeparateAudioPacketsSettings() = default; + explicit BweSeparateAudioPacketsSettings( + const WebRtcKeyValueConfig* key_value_config); + + bool enabled = false; + int packet_threshold = 10; + TimeDelta time_threshold = TimeDelta::Seconds<1>(); + + std::unique_ptr Parser(); +}; + class DelayBasedBwe { public: struct Result { Result(); - Result(bool probe, DataRate target_bitrate); - ~Result(); + ~Result() = default; bool updated; bool probe; DataRate target_bitrate = DataRate::Zero(); bool recovered_from_overuse; - bool backoff_in_alr; + BandwidthUsage delay_detector_state; }; explicit DelayBasedBwe(const WebRtcKeyValueConfig* key_value_config, NetworkStatePredictor* network_state_predictor); + + DelayBasedBwe() = delete; + DelayBasedBwe(const DelayBasedBwe&) = delete; + DelayBasedBwe& operator=(const DelayBasedBwe&) = delete; + virtual ~DelayBasedBwe(); Result IncomingPacketFeedbackVector( @@ -59,11 +80,11 @@ class DelayBasedBwe { void SetStartBitrate(DataRate start_bitrate); void SetMinBitrate(DataRate min_bitrate); TimeDelta GetExpectedBwePeriod() const; - void SetAlrLimitedBackoffExperiment(bool enabled); - DataRate TriggerOveruse(Timestamp at_time, absl::optional link_capacity); - + DataRate last_estimate() const { return prev_bitrate_; } + BandwidthUsage last_state() const { return prev_state_; } + DelayBasedBweState GetState() const; private: friend class GoogCcStatePrinter; void IncomingPacketFeedback(const PacketResult& packet_feedback, @@ -77,22 +98,35 @@ class DelayBasedBwe { Timestamp at_time); // Updates the current remote rate estimate and returns true if a valid // estimate exists. - bool UpdateEstimate(Timestamp now, + bool UpdateEstimate(Timestamp at_time, absl::optional acked_bitrate, - DataRate* target_bitrate); + DataRate* target_rate); + // rtc::RaceChecker network_race_; + // RtcEventLog* const event_log_; const WebRtcKeyValueConfig* const key_value_config_; + + // Alternatively, run two separate overuse detectors for audio and video, + // and fall back to the audio one if we haven't seen a video packet in a + // while. + BweSeparateAudioPacketsSettings separate_audio_; + int64_t audio_packets_since_last_video_; + Timestamp last_video_packet_recv_time_; + NetworkStatePredictor* network_state_predictor_; - std::unique_ptr inter_arrival_; - std::unique_ptr delay_detector_; + std::unique_ptr video_inter_arrival_; + std::unique_ptr video_inter_arrival_delta_; + std::unique_ptr video_delay_detector_; + std::unique_ptr audio_inter_arrival_; + std::unique_ptr audio_inter_arrival_delta_; + std::unique_ptr audio_delay_detector_; + DelayIncreaseDetectorInterface* active_delay_detector_; + Timestamp last_seen_packet_; bool uma_recorded_; AimdRateControl rate_control_; DataRate prev_bitrate_; BandwidthUsage prev_state_; - bool alr_limited_backoff_enabled_; - - RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(DelayBasedBwe); }; } // namespace webrtc diff --git a/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/delay_increase_detector_interface.h b/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/delay_increase_detector_interface.h index f730181ad3..a3bdbf81d5 100644 --- a/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/delay_increase_detector_interface.h +++ b/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/delay_increase_detector_interface.h @@ -11,7 +11,6 @@ #define MODULES_CONGESTION_CONTROLLER_GOOG_CC_DELAY_INCREASE_DETECTOR_INTERFACE_H_ #include "modules/remote_bitrate_estimator/include/bwe_defines.h" -#include "rtc_base/constructor_magic.h" #include @@ -22,17 +21,35 @@ class DelayIncreaseDetectorInterface { DelayIncreaseDetectorInterface() {} virtual ~DelayIncreaseDetectorInterface() {} + DelayIncreaseDetectorInterface(const DelayIncreaseDetectorInterface&) = + delete; + DelayIncreaseDetectorInterface& operator=( + const DelayIncreaseDetectorInterface&) = delete; + // Update the detector with a new sample. The deltas should represent deltas // between timestamp groups as defined by the InterArrival class. virtual void Update(double recv_delta_ms, double send_delta_ms, int64_t send_time_ms, int64_t arrival_time_ms, + size_t packet_size, bool calculated_deltas) = 0; virtual BandwidthUsage State() const = 0; - - RTC_DISALLOW_COPY_AND_ASSIGN(DelayIncreaseDetectorInterface); + struct RegressionResult { + RegressionResult(double slope, + double r_squared) + : slope(slope), + r_squared(r_squared) {} + RegressionResult() + : slope(0.0), + r_squared(0.0) {} + double slope; + double r_squared; + }; + + virtual RegressionResult GetTrend() = 0; + virtual double GetThreshold() = 0; }; } // namespace webrtc diff --git a/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/goog_cc_network_control.cc b/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/goog_cc_network_control.cc index aced2db317..36b9b6ab6e 100644 --- a/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/goog_cc_network_control.cc +++ b/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/goog_cc_network_control.cc @@ -18,15 +18,16 @@ #include "modules/congestion_controller/goog_cc/probe_controller.h" #include "modules/remote_bitrate_estimator/include/bwe_defines.h" +#include "DepLibUV.hpp" #include "Logger.hpp" #include -#include -#include #include #include +#include #include #include +#include #include #include #include @@ -41,42 +42,60 @@ constexpr TimeDelta kLossUpdateInterval = TimeDelta::Millis<1000>(); // the number of bytes that can be transmitted per interval. // Increasing this factor will result in lower delays in cases of bitrate // overshoots from the encoder. -const float kDefaultPaceMultiplier = 2.5f; +constexpr float kDefaultPaceMultiplier = 2.5f; + +// If the probe result is far below the current throughput estimate +// it's unlikely that the probe is accurate, so we don't want to drop too far. +// However, if we actually are overusing, we want to drop to something slightly +// below the current throughput estimate to drain the network queues. +constexpr double kProbeDropThroughputFraction = 0.85; -int64_t GetBpsOrDefault(const absl::optional& rate, - int64_t fallback_bps) { - if (rate && rate->IsFinite()) { - return rate->bps(); - } else { - return fallback_bps; - } -} bool IsEnabled(const WebRtcKeyValueConfig* config, absl::string_view key) { return config->Lookup(key).find("Enabled") == 0; } bool IsNotDisabled(const WebRtcKeyValueConfig* config, absl::string_view key) { return config->Lookup(key).find("Disabled") != 0; } +BandwidthLimitedCause GetBandwidthLimitedCause( + LossBasedState loss_based_state, + BandwidthUsage bandwidth_usage, + bool not_probe_if_delay_increased) { + if (not_probe_if_delay_increased && + (bandwidth_usage == BandwidthUsage::kBwOverusing || + bandwidth_usage == BandwidthUsage::kBwUnderusing)) { + return BandwidthLimitedCause::kDelayBasedLimitedDelayIncreased; + } + switch (loss_based_state) { + case LossBasedState::kDecreasing: + return BandwidthLimitedCause::kLossLimitedBweDecreasing; + case LossBasedState::kIncreasing: + return BandwidthLimitedCause::kLossLimitedBweIncreasing; + default: + return BandwidthLimitedCause::kDelayBasedLimited; + } +} } // namespace GoogCcNetworkController::GoogCcNetworkController(NetworkControllerConfig config, - GoogCcConfig congestion_controller_config) + GoogCcConfig goog_cc_config) : key_value_config_(config.key_value_config ? config.key_value_config : &trial_based_config_), - packet_feedback_only_(congestion_controller_config.feedback_only), + packet_feedback_only_(goog_cc_config.feedback_only), safe_reset_on_route_change_("Enabled"), safe_reset_acknowledged_rate_("ack"), - use_stable_bandwidth_estimate_( - IsEnabled(key_value_config_, "WebRTC-Bwe-StableBandwidthEstimate")), - use_downlink_delay_for_congestion_window_( - IsEnabled(key_value_config_, - "WebRTC-Bwe-CongestionWindowDownlinkDelay")), - fall_back_to_probe_rate_( - IsEnabled(key_value_config_, "WebRTC-Bwe-ProbeRateFallback")), use_min_allocatable_as_lower_bound_( IsNotDisabled(key_value_config_, "WebRTC-Bwe-MinAllocAsLowerBound")), + ignore_probes_lower_than_network_estimate_(IsNotDisabled( + key_value_config_, + "WebRTC-Bwe-IgnoreProbesLowerThanNetworkStateEstimate")), + limit_probes_lower_than_throughput_estimate_( + IsEnabled(key_value_config_, + "WebRTC-Bwe-LimitProbesLowerThanThroughputEstimate")), rate_control_settings_( RateControlSettings::ParseFromKeyValueConfig(key_value_config_)), + pace_at_max_of_bwe_and_lower_link_capacity_( + IsEnabled(key_value_config_, + "WebRTC-Bwe-PaceAtMaxOfBweAndLowerLinkCapacity")), probe_controller_( new ProbeController(key_value_config_)), congestion_window_pushback_controller_( @@ -85,28 +104,28 @@ GoogCcNetworkController::GoogCcNetworkController(NetworkControllerConfig config, key_value_config_) : nullptr), bandwidth_estimation_( - absl::make_unique()), + absl::make_unique(key_value_config_)), alr_detector_( absl::make_unique(key_value_config_)), probe_bitrate_estimator_(new ProbeBitrateEstimator()), - network_estimator_(std::move(congestion_controller_config.network_state_estimator)), + network_estimator_(std::move(goog_cc_config.network_state_estimator)), network_state_predictor_( - std::move(congestion_controller_config.network_state_predictor)), + std::move(goog_cc_config.network_state_predictor)), delay_based_bwe_(new DelayBasedBwe(key_value_config_, network_state_predictor_.get())), acknowledged_bitrate_estimator_( - absl::make_unique(key_value_config_)), + AcknowledgedBitrateEstimatorInterface::Create(key_value_config_)), initial_config_(config), - last_raw_target_rate_(*config.constraints.starting_rate), - last_pushback_target_rate_(last_raw_target_rate_), + last_loss_based_target_rate_(*config.constraints.starting_rate), + last_pushback_target_rate_(last_loss_based_target_rate_), + last_stable_target_rate_(last_loss_based_target_rate_), pacing_factor_(config.stream_based_config.pacing_factor.value_or( kDefaultPaceMultiplier)), min_total_allocated_bitrate_( config.stream_based_config.min_total_allocated_bitrate.value_or( DataRate::Zero())), max_padding_rate_(config.stream_based_config.max_padding_rate.value_or( - DataRate::Zero())), - max_total_allocated_bitrate_(DataRate::Zero()) { + DataRate::Zero())) { //RTC_DCHECK(config.constraints.at_time.IsFinite()); ParseFieldTrial( {&safe_reset_on_route_change_, &safe_reset_acknowledged_rate_}, @@ -124,6 +143,20 @@ NetworkControlUpdate GoogCcNetworkController::OnNetworkAvailability( return update; } +BweStats GoogCcNetworkController::GetBweStats() +{ + BweStats stats; + stats.time = Timestamp::ms(DepLibUV::GetTimeMsInt64()); + stats.estimated_bitrate = bandwidth_estimation_->target_rate(); + stats.acknowledged_bitrate = acknowledged_bitrate_estimator_->bitrate(); + stats.delay = delay_based_bwe_->GetState(); + stats.rtt = bandwidth_estimation_->round_trip_time(); + stats.loss_estimator_state = bandwidth_estimation_->GetLossEstimatorState(); + stats.in_alr = alr_detector_->GetApplicationLimitedRegionStartTime().has_value(); + stats.probe_bitrate = probe_bitrate_estimator_->last_estimate(); + return stats; +} + NetworkControlUpdate GoogCcNetworkController::OnNetworkRouteChange( NetworkRouteChange msg) { if (safe_reset_on_route_change_) { @@ -133,12 +166,7 @@ NetworkControlUpdate GoogCcNetworkController::OnNetworkRouteChange( if (!estimated_bitrate) estimated_bitrate = acknowledged_bitrate_estimator_->PeekRate(); } else { - int32_t target_bitrate_bps; - uint8_t fraction_loss; - int64_t rtt_ms; - bandwidth_estimation_->CurrentEstimate(&target_bitrate_bps, - &fraction_loss, &rtt_ms); - estimated_bitrate = DataRate::bps(target_bitrate_bps); + estimated_bitrate = bandwidth_estimation_->target_rate(); } if (estimated_bitrate) { if (msg.constraints.starting_rate) { @@ -150,15 +178,15 @@ NetworkControlUpdate GoogCcNetworkController::OnNetworkRouteChange( } } - acknowledged_bitrate_estimator_.reset( - new AcknowledgedBitrateEstimator(key_value_config_)); + acknowledged_bitrate_estimator_ = + AcknowledgedBitrateEstimatorInterface::Create(key_value_config_); probe_bitrate_estimator_.reset(new ProbeBitrateEstimator()); if (network_estimator_) network_estimator_->OnRouteChange(msg); delay_based_bwe_.reset(new DelayBasedBwe(key_value_config_, network_state_predictor_.get())); bandwidth_estimation_->OnRouteChange(); - probe_controller_->Reset(msg.at_time.ms()); + probe_controller_->Reset(msg.at_time); NetworkControlUpdate update; update.probe_cluster_configs = ResetConstraints(msg.constraints); MaybeTriggerOnNetworkChanged(&update, msg.at_time); @@ -181,11 +209,9 @@ NetworkControlUpdate GoogCcNetworkController::OnProcessInterval( initial_config_->stream_based_config.max_total_allocated_bitrate; if (total_bitrate) { auto probes = probe_controller_->OnMaxTotalAllocatedBitrate( - total_bitrate->bps(), msg.at_time.ms()); + *total_bitrate, msg.at_time); update.probe_cluster_configs.insert(update.probe_cluster_configs.end(), probes.begin(), probes.end()); - - max_total_allocated_bitrate_ = *total_bitrate; } initial_config_.reset(); } @@ -194,14 +220,19 @@ NetworkControlUpdate GoogCcNetworkController::OnProcessInterval( msg.pacer_queue->bytes()); } bandwidth_estimation_->UpdateEstimate(msg.at_time); + alr_detector_->Process(); absl::optional start_time_ms = alr_detector_->GetApplicationLimitedRegionStartTime(); probe_controller_->SetAlrStartTimeMs(start_time_ms); - auto probes = probe_controller_->Process(msg.at_time.ms()); + auto probes = probe_controller_->Process(msg.at_time); update.probe_cluster_configs.insert(update.probe_cluster_configs.end(), probes.begin(), probes.end()); + if (rate_control_settings_.UseCongestionWindow() && + last_packet_received_time_.IsFinite() && !feedback_max_rtts_.empty()) { + UpdateCongestionWindowSize(); + } if (congestion_window_pushback_controller_ && current_data_window_) { congestion_window_pushback_controller_->SetDataWindow( *current_data_window_); @@ -251,14 +282,10 @@ NetworkControlUpdate GoogCcNetworkController::OnSentPacket( TimeDelta::Zero()); } bandwidth_estimation_->OnSentPacket(sent_packet); - bool network_changed = false; if (congestion_window_pushback_controller_) { congestion_window_pushback_controller_->UpdateOutstandingData( sent_packet.data_in_flight.bytes()); - network_changed = true; - } - if (network_changed) { NetworkControlUpdate update; MaybeTriggerOnNetworkChanged(&update, sent_packet.send_time); return update; @@ -267,23 +294,24 @@ NetworkControlUpdate GoogCcNetworkController::OnSentPacket( } } +NetworkControlUpdate GoogCcNetworkController::OnReceivedPacket( + ReceivedPacket received_packet) { + last_packet_received_time_ = received_packet.receive_time; + return NetworkControlUpdate(); +} + NetworkControlUpdate GoogCcNetworkController::OnStreamsConfig( StreamsConfig msg) { NetworkControlUpdate update; if (msg.requests_alr_probing) { probe_controller_->EnablePeriodicAlrProbing(*msg.requests_alr_probing); } - if (msg.max_total_allocated_bitrate && - *msg.max_total_allocated_bitrate != max_total_allocated_bitrate_) { - if (rate_control_settings_.TriggerProbeOnMaxAllocatedBitrateChange()) { - update.probe_cluster_configs = - probe_controller_->OnMaxTotalAllocatedBitrate( - msg.max_total_allocated_bitrate->bps(), msg.at_time.ms()); - } else { - probe_controller_->SetMaxBitrate(msg.max_total_allocated_bitrate->bps()); - } - max_total_allocated_bitrate_ = *msg.max_total_allocated_bitrate; + if (msg.max_total_allocated_bitrate) { + update.probe_cluster_configs = + probe_controller_->OnMaxTotalAllocatedBitrate( + *msg.max_total_allocated_bitrate, msg.at_time); } + bool pacing_changed = false; if (msg.pacing_factor && *msg.pacing_factor != pacing_factor_) { pacing_factor_ = *msg.pacing_factor; @@ -350,7 +378,7 @@ void GoogCcNetworkController::ClampConstraints() { std::vector GoogCcNetworkController::ResetConstraints( TargetRateConstraints new_constraints) { - min_data_rate_ = new_constraints.min_data_rate.value_or(DataRate::Zero()); + min_target_rate_ = new_constraints.min_data_rate.value_or(DataRate::Zero()); max_data_rate_ = new_constraints.max_data_rate.value_or(DataRate::PlusInfinity()); starting_rate_ = new_constraints.starting_rate; @@ -368,8 +396,8 @@ std::vector GoogCcNetworkController::ResetConstraints( delay_based_bwe_->SetMinBitrate(min_data_rate_); return probe_controller_->SetBitrates( - min_data_rate_.bps(), GetBpsOrDefault(starting_rate_, -1), - max_data_rate_.bps_or(-1), new_constraints.at_time.ms()); + min_data_rate_, starting_rate_.value_or(DataRate::Zero()), max_data_rate_, + new_constraints.at_time); } NetworkControlUpdate GoogCcNetworkController::OnTransportLossReport( @@ -383,8 +411,7 @@ NetworkControlUpdate GoogCcNetworkController::OnTransportLossReport( return NetworkControlUpdate(); } -void GoogCcNetworkController::UpdateCongestionWindowSize( - TimeDelta time_since_last_packet) { +void GoogCcNetworkController::UpdateCongestionWindowSize() { TimeDelta min_feedback_max_rtt = TimeDelta::ms( *std::min_element(feedback_max_rtts_.begin(), feedback_max_rtts_.end())); @@ -394,11 +421,7 @@ void GoogCcNetworkController::UpdateCongestionWindowSize( TimeDelta::ms( rate_control_settings_.GetCongestionWindowAdditionalTimeMs()); - if (use_downlink_delay_for_congestion_window_) { - time_window += time_since_last_packet; - } - - DataSize data_window = last_raw_target_rate_ * time_window; + DataSize data_window = last_loss_based_target_rate_ * time_window; if (current_data_window_) { data_window = std::max(kMinCwnd, (data_window + current_data_window_.value()) / 2); @@ -448,8 +471,9 @@ NetworkControlUpdate GoogCcNetworkController::OnTransportPacketsFeedback( } if (packet_feedback_only_) { if (!feedback_max_rtts_.empty()) { - int64_t sum_rtt_ms = std::accumulate(feedback_max_rtts_.begin(), - feedback_max_rtts_.end(), 0); + int64_t sum_rtt_ms = + std::accumulate(feedback_max_rtts_.begin(), feedback_max_rtts_.end(), + static_cast(0)); int64_t mean_rtt_ms = sum_rtt_ms / feedback_max_rtts_.size(); if (delay_based_bwe_) delay_based_bwe_->OnRttUpdate(TimeDelta::ms(mean_rtt_ms)); @@ -470,7 +494,7 @@ NetworkControlUpdate GoogCcNetworkController::OnTransportPacketsFeedback( expected_packets_since_last_loss_update_ += report.PacketsWithFeedback().size(); for (const auto& packet_feedback : report.PacketsWithFeedback()) { - if (packet_feedback.receive_time.IsInfinite()) + if (!packet_feedback.IsReceived()) lost_packets_since_last_loss_update_ += 1; } if (report.feedback_time > next_loss_update_) { @@ -494,6 +518,8 @@ NetworkControlUpdate GoogCcNetworkController::OnTransportPacketsFeedback( acknowledged_bitrate_estimator_->IncomingPacketFeedbackVector( report.SortedByReceiveTime()); auto acknowledged_bitrate = acknowledged_bitrate_estimator_->bitrate(); + bandwidth_estimation_->SetAcknowledgedRate(acknowledged_bitrate, + report.feedback_time); for (const auto& feedback : report.SortedByReceiveTime()) { if (feedback.sent_packet.pacing_info.probe_cluster_id != PacedPacketInfo::kNotAProbe) { @@ -501,26 +527,52 @@ NetworkControlUpdate GoogCcNetworkController::OnTransportPacketsFeedback( } } - absl::optional probe_bitrate = - probe_bitrate_estimator_->FetchAndResetLastEstimatedBitrate(); - if (fall_back_to_probe_rate_ && !acknowledged_bitrate) - acknowledged_bitrate = probe_bitrate_estimator_->last_estimate(); - bandwidth_estimation_->SetAcknowledgedRate(acknowledged_bitrate, - report.feedback_time); - bandwidth_estimation_->IncomingPacketFeedbackVector(report); - if (network_estimator_) { network_estimator_->OnTransportPacketsFeedback(report); + auto prev_estimate = estimate_; estimate_ = network_estimator_->GetCurrentEstimate(); + // TODO(srte): Make OnTransportPacketsFeedback signal whether the state + // changed to avoid the need for this check. + if (estimate_ && (!prev_estimate || estimate_->last_feed_time != + prev_estimate->last_feed_time)) { +/* event_log_->Log(std::make_unique( + estimate_->link_capacity_lower, estimate_->link_capacity_upper));*/ + probe_controller_->SetNetworkStateEstimate(*estimate_); + } + } + absl::optional probe_bitrate = + probe_bitrate_estimator_->FetchAndResetLastEstimatedBitrate(); + if (ignore_probes_lower_than_network_estimate_ && probe_bitrate && + estimate_ && *probe_bitrate < delay_based_bwe_->last_estimate() && + *probe_bitrate < estimate_->link_capacity_lower) { + probe_bitrate.reset(); + } + if (limit_probes_lower_than_throughput_estimate_ && probe_bitrate && + acknowledged_bitrate) { + // Limit the backoff to something slightly below the acknowledged + // bitrate. ("Slightly below" because we want to drain the queues + // if we are actually overusing.) + // The acknowledged bitrate shouldn't normally be higher than the delay + // based estimate, but it could happen e.g. due to packet bursts or + // encoder overshoot. We use std::min to ensure that a probe result + // below the current BWE never causes an increase. + DataRate limit = + std::min(delay_based_bwe_->last_estimate(), + *acknowledged_bitrate * kProbeDropThroughputFraction); + probe_bitrate = std::max(*probe_bitrate, limit); } NetworkControlUpdate update; bool recovered_from_overuse = false; - bool backoff_in_alr = false; DelayBasedBwe::Result result; + // MS_NOTE: I am not sure why we are passing here acknowledged_bitrate + // instead of bandwidth_estimation_->target_rate(), because, when we are + // backing off we in AIMD we should backoff from target rate rather than + // acknowledged_bitrate, otherwise we get big BW drops, bigger that default + // AIMD 0.85 backof factor result = delay_based_bwe_->IncomingPacketFeedbackVector( - report, acknowledged_bitrate, probe_bitrate, estimate_, + report, bandwidth_estimation_->target_rate(), probe_bitrate, estimate_, alr_start_time.has_value()); if (result.updated) { @@ -532,20 +584,20 @@ NetworkControlUpdate GoogCcNetworkController::OnTransportPacketsFeedback( // call UpdateDelayBasedEstimate after SetSendBitrate. bandwidth_estimation_->UpdateDelayBasedEstimate(report.feedback_time, result.target_bitrate); + } + bandwidth_estimation_->UpdateLossBasedEstimator( + report, result.delay_detector_state, probe_bitrate, + estimate_ ? estimate_->link_capacity_upper : DataRate::PlusInfinity()); + if (result.updated) { // Update the estimate in the ProbeController, in case we want to probe. MaybeTriggerOnNetworkChanged(&update, report.feedback_time); } + recovered_from_overuse = result.recovered_from_overuse; - backoff_in_alr = result.backoff_in_alr; if (recovered_from_overuse) { probe_controller_->SetAlrStartTimeMs(alr_start_time); - auto probes = probe_controller_->RequestProbe(report.feedback_time.ms()); - update.probe_cluster_configs.insert(update.probe_cluster_configs.end(), - probes.begin(), probes.end()); - } else if (backoff_in_alr) { - // If we just backed off during ALR, request a new probe. - auto probes = probe_controller_->RequestProbe(report.feedback_time.ms()); + auto probes = probe_controller_->RequestProbe(report.feedback_time); update.probe_cluster_configs.insert(update.probe_cluster_configs.end(), probes.begin(), probes.end()); } @@ -554,7 +606,7 @@ NetworkControlUpdate GoogCcNetworkController::OnTransportPacketsFeedback( // we don't try to limit the outstanding packets. if (rate_control_settings_.UseCongestionWindow() && max_feedback_rtt.IsFinite()) { - UpdateCongestionWindowSize(/*time_since_last_packet*/ TimeDelta::Zero()); + UpdateCongestionWindowSize(); } if (congestion_window_pushback_controller_ && current_data_window_) { congestion_window_pushback_controller_->SetDataWindow( @@ -574,22 +626,20 @@ NetworkControlUpdate GoogCcNetworkController::OnNetworkStateEstimate( NetworkControlUpdate GoogCcNetworkController::GetNetworkState( Timestamp at_time) const { - DataRate bandwidth = use_stable_bandwidth_estimate_ - ? bandwidth_estimation_->GetEstimatedLinkCapacity() - : last_raw_target_rate_; - TimeDelta rtt = TimeDelta::ms(last_estimated_rtt_ms_); NetworkControlUpdate update; update.target_rate = TargetTransferRate(); update.target_rate->network_estimate.at_time = at_time; - update.target_rate->network_estimate.bandwidth = bandwidth; update.target_rate->network_estimate.loss_rate_ratio = - last_estimated_fraction_loss_ / 255.0; - update.target_rate->network_estimate.round_trip_time = rtt; + last_estimated_fraction_loss_.value_or(0) / 255.0; + update.target_rate->network_estimate.round_trip_time = + last_estimated_round_trip_time_; update.target_rate->network_estimate.bwe_period = delay_based_bwe_->GetExpectedBwePeriod(); update.target_rate->at_time = at_time; - update.target_rate->target_rate = bandwidth; + update.target_rate->target_rate = last_pushback_target_rate_; + update.target_rate->stable_target_rate = + bandwidth_estimation_->GetEstimatedLinkCapacity(); update.pacer_config = GetPacingRates(at_time); update.congestion_window = current_data_window_; return update; @@ -598,11 +648,10 @@ NetworkControlUpdate GoogCcNetworkController::GetNetworkState( void GoogCcNetworkController::MaybeTriggerOnNetworkChanged( NetworkControlUpdate* update, Timestamp at_time) { - int32_t estimated_bitrate_bps; - uint8_t fraction_loss; - int64_t rtt_ms; - bandwidth_estimation_->CurrentEstimate(&estimated_bitrate_bps, &fraction_loss, - &rtt_ms); + uint8_t fraction_loss = bandwidth_estimation_->fraction_loss(); + TimeDelta round_trip_time = bandwidth_estimation_->round_trip_time(); + DataRate loss_based_target_rate = bandwidth_estimation_->target_rate(); + DataRate pushback_target_rate = loss_based_target_rate; // BWE_TEST_LOGGING_PLOT(1, "fraction_loss_%", at_time.ms(), // (fraction_loss * 100) / 256); @@ -610,64 +659,87 @@ void GoogCcNetworkController::MaybeTriggerOnNetworkChanged( // BWE_TEST_LOGGING_PLOT(1, "Target_bitrate_kbps", at_time.ms(), // estimated_bitrate_bps / 1000); - DataRate target_rate = DataRate::bps(estimated_bitrate_bps); + double cwnd_reduce_ratio = 0.0; if (congestion_window_pushback_controller_) { int64_t pushback_rate = congestion_window_pushback_controller_->UpdateTargetBitrate( - target_rate.bps()); + loss_based_target_rate.bps()); pushback_rate = std::max(bandwidth_estimation_->GetMinBitrate(), pushback_rate); - target_rate = DataRate::bps(pushback_rate); + pushback_target_rate = DataRate::bps(pushback_rate); + if (rate_control_settings_.UseCongestionWindowDropFrameOnly()) { + cwnd_reduce_ratio = static_cast(loss_based_target_rate.bps() - + pushback_target_rate.bps()) / + loss_based_target_rate.bps(); + } } + DataRate stable_target_rate = + bandwidth_estimation_->GetEstimatedLinkCapacity(); + stable_target_rate = std::min(stable_target_rate, pushback_target_rate); - if ((estimated_bitrate_bps != last_estimated_bitrate_bps_) || + if ((loss_based_target_rate != last_loss_based_target_rate_) || (fraction_loss != last_estimated_fraction_loss_) || - (rtt_ms != last_estimated_rtt_ms_) || - (target_rate != last_pushback_target_rate_)) { - last_pushback_target_rate_ = target_rate; - last_estimated_bitrate_bps_ = estimated_bitrate_bps; + (round_trip_time != last_estimated_round_trip_time_) || + (pushback_target_rate != last_pushback_target_rate_) || + (stable_target_rate != last_stable_target_rate_)) { + last_loss_based_target_rate_ = loss_based_target_rate; + last_pushback_target_rate_ = pushback_target_rate; last_estimated_fraction_loss_ = fraction_loss; - last_estimated_rtt_ms_ = rtt_ms; - - alr_detector_->SetEstimatedBitrate(estimated_bitrate_bps); + last_estimated_round_trip_time_ = round_trip_time; + last_stable_target_rate_ = stable_target_rate; - last_raw_target_rate_ = DataRate::bps(estimated_bitrate_bps); - DataRate bandwidth = use_stable_bandwidth_estimate_ - ? bandwidth_estimation_->GetEstimatedLinkCapacity() - : last_raw_target_rate_; + alr_detector_->SetEstimatedBitrate(loss_based_target_rate.bps()); TimeDelta bwe_period = delay_based_bwe_->GetExpectedBwePeriod(); TargetTransferRate target_rate_msg; target_rate_msg.at_time = at_time; - target_rate_msg.target_rate = target_rate; + if (rate_control_settings_.UseCongestionWindowDropFrameOnly()) { + target_rate_msg.target_rate = loss_based_target_rate; + target_rate_msg.cwnd_reduce_ratio = cwnd_reduce_ratio; + } else { + target_rate_msg.target_rate = pushback_target_rate; + } + target_rate_msg.stable_target_rate = stable_target_rate; target_rate_msg.network_estimate.at_time = at_time; - target_rate_msg.network_estimate.round_trip_time = TimeDelta::ms(rtt_ms); - target_rate_msg.network_estimate.bandwidth = bandwidth; + target_rate_msg.network_estimate.round_trip_time = round_trip_time; target_rate_msg.network_estimate.loss_rate_ratio = fraction_loss / 255.0f; target_rate_msg.network_estimate.bwe_period = bwe_period; update->target_rate = target_rate_msg; auto probes = probe_controller_->SetEstimatedBitrate( - last_raw_target_rate_.bps(), at_time.ms()); + loss_based_target_rate, + GetBandwidthLimitedCause( + bandwidth_estimation_->loss_based_state(), + delay_based_bwe_->last_state(), + probe_controller_->DontProbeIfDelayIncreased()), + at_time); update->probe_cluster_configs.insert(update->probe_cluster_configs.end(), probes.begin(), probes.end()); update->pacer_config = GetPacingRates(at_time); - MS_DEBUG_DEV("bwe [at_time:%" PRIu64", pushback_target_bps:%lld, estimate_bps:%lld]", +/* MS_DEBUG_DEV("bwe [at_time:%" PRIu64", pushback_target_bps:%lld, estimate_bps:%lld]", at_time.ms(), last_pushback_target_rate_.bps(), - last_raw_target_rate_.bps()); + last_raw_target_rate_.bps());*/ } } PacerConfig GoogCcNetworkController::GetPacingRates(Timestamp at_time) const { // Pacing rate is based on target rate before congestion window pushback, // because we don't want to build queues in the pacer when pushback occurs. - DataRate pacing_rate = - std::max(min_total_allocated_bitrate_, last_raw_target_rate_) * - pacing_factor_; + DataRate pacing_rate = DataRate::Zero(); + if (pace_at_max_of_bwe_and_lower_link_capacity_ && estimate_) { + pacing_rate = + std::max({min_total_allocated_bitrate_, estimate_->link_capacity_lower, + last_loss_based_target_rate_}) * + pacing_factor_; + } else { + pacing_rate = + std::max(min_total_allocated_bitrate_, last_loss_based_target_rate_) * + pacing_factor_; + } DataRate padding_rate = std::min(max_padding_rate_, last_pushback_target_rate_); PacerConfig msg; diff --git a/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/goog_cc_network_control.h b/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/goog_cc_network_control.h index 200572a67b..e1429dda01 100644 --- a/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/goog_cc_network_control.h +++ b/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/goog_cc_network_control.h @@ -19,13 +19,12 @@ #include "api/units/data_rate.h" #include "api/units/data_size.h" #include "api/units/timestamp.h" -#include "modules/bitrate_controller/send_side_bandwidth_estimation.h" -#include "modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator.h" +#include "modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator_interface.h" #include "modules/congestion_controller/goog_cc/alr_detector.h" #include "modules/congestion_controller/goog_cc/congestion_window_pushback_controller.h" #include "modules/congestion_controller/goog_cc/delay_based_bwe.h" #include "modules/congestion_controller/goog_cc/probe_controller.h" -#include "rtc_base/constructor_magic.h" +#include "modules/bitrate_controller/send_side_bandwidth_estimation.h" #include "rtc_base/experiments/field_trial_parser.h" #include "rtc_base/experiments/rate_control_settings.h" @@ -45,7 +44,12 @@ struct GoogCcConfig { class GoogCcNetworkController : public NetworkControllerInterface { public: GoogCcNetworkController(NetworkControllerConfig config, - GoogCcConfig congestion_controller_config); + GoogCcConfig goog_cc_config); + + GoogCcNetworkController() = delete; + GoogCcNetworkController(const GoogCcNetworkController&) = delete; + GoogCcNetworkController& operator=(const GoogCcNetworkController&) = delete; + ~GoogCcNetworkController() override; // NetworkControllerInterface @@ -55,6 +59,7 @@ class GoogCcNetworkController : public NetworkControllerInterface { NetworkControlUpdate OnRemoteBitrateReport(RemoteBitrateReport msg) override; NetworkControlUpdate OnRoundTripTimeUpdate(RoundTripTimeUpdate msg) override; NetworkControlUpdate OnSentPacket(SentPacket msg) override; + NetworkControlUpdate OnReceivedPacket(ReceivedPacket msg) override; NetworkControlUpdate OnStreamsConfig(StreamsConfig msg) override; NetworkControlUpdate OnTargetRateConstraints( TargetRateConstraints msg) override; @@ -64,6 +69,8 @@ class GoogCcNetworkController : public NetworkControllerInterface { NetworkControlUpdate OnNetworkStateEstimate( NetworkStateEstimate msg) override; + BweStats GetBweStats() override; + NetworkControlUpdate GetNetworkState(Timestamp at_time) const; private: @@ -73,7 +80,7 @@ class GoogCcNetworkController : public NetworkControllerInterface { void ClampConstraints(); void MaybeTriggerOnNetworkChanged(NetworkControlUpdate* update, Timestamp at_time); - void UpdateCongestionWindowSize(TimeDelta time_since_last_packet); + void UpdateCongestionWindowSize(); PacerConfig GetPacingRates(Timestamp at_time) const; const FieldTrialBasedConfig trial_based_config_; @@ -82,11 +89,11 @@ class GoogCcNetworkController : public NetworkControllerInterface { const bool packet_feedback_only_; FieldTrialFlag safe_reset_on_route_change_; FieldTrialFlag safe_reset_acknowledged_rate_; - const bool use_stable_bandwidth_estimate_; - const bool use_downlink_delay_for_congestion_window_; - const bool fall_back_to_probe_rate_; const bool use_min_allocatable_as_lower_bound_; + const bool ignore_probes_lower_than_network_estimate_; + const bool limit_probes_lower_than_throughput_estimate_; const RateControlSettings rate_control_settings_; + const bool pace_at_max_of_bwe_and_lower_link_capacity_; const std::unique_ptr probe_controller_; const std::unique_ptr @@ -98,10 +105,12 @@ class GoogCcNetworkController : public NetworkControllerInterface { std::unique_ptr network_estimator_; std::unique_ptr network_state_predictor_; std::unique_ptr delay_based_bwe_; - std::unique_ptr acknowledged_bitrate_estimator_; + std::unique_ptr + acknowledged_bitrate_estimator_; absl::optional initial_config_; + DataRate min_target_rate_ = DataRate::Zero(); DataRate min_data_rate_ = DataRate::Zero(); DataRate max_data_rate_ = DataRate::PlusInfinity(); absl::optional starting_rate_; @@ -116,23 +125,21 @@ class GoogCcNetworkController : public NetworkControllerInterface { std::deque feedback_max_rtts_; - DataRate last_raw_target_rate_; + DataRate last_loss_based_target_rate_; DataRate last_pushback_target_rate_; + DataRate last_stable_target_rate_; - int32_t last_estimated_bitrate_bps_ = 0; - uint8_t last_estimated_fraction_loss_ = 0; - int64_t last_estimated_rtt_ms_ = 0; + absl::optional last_estimated_fraction_loss_ = 0; + TimeDelta last_estimated_round_trip_time_ = TimeDelta::PlusInfinity(); + Timestamp last_packet_received_time_ = Timestamp::MinusInfinity(); double pacing_factor_; DataRate min_total_allocated_bitrate_; DataRate max_padding_rate_; - DataRate max_total_allocated_bitrate_; bool previously_in_alr_ = false; absl::optional current_data_window_; - - RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(GoogCcNetworkController); }; } // namespace webrtc diff --git a/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/inter_arrival_delta.cc b/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/inter_arrival_delta.cc new file mode 100644 index 0000000000..44090ba60e --- /dev/null +++ b/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/inter_arrival_delta.cc @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2020 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. + */ + +#define MS_CLASS "webrtc::InterArrivalDelta" + +#include "modules/congestion_controller/goog_cc/inter_arrival_delta.h" + +#include + +#include "api/units/time_delta.h" +#include "api/units/timestamp.h" +#include "Logger.hpp" + +namespace webrtc { + +static constexpr TimeDelta kBurstDeltaThreshold = TimeDelta::Millis<5>(); +static constexpr TimeDelta kMaxBurstDuration = TimeDelta::Millis<100>(); +constexpr TimeDelta InterArrivalDelta::kArrivalTimeOffsetThreshold; + +InterArrivalDelta::InterArrivalDelta(TimeDelta send_time_group_length) + : send_time_group_length_(send_time_group_length), + current_timestamp_group_(), + prev_timestamp_group_(), + num_consecutive_reordered_packets_(0) {} + +bool InterArrivalDelta::ComputeDeltas(Timestamp send_time, + Timestamp arrival_time, + Timestamp system_time, + size_t packet_size, + TimeDelta* send_time_delta, + TimeDelta* arrival_time_delta, + int* packet_size_delta) { + bool calculated_deltas = false; + if (current_timestamp_group_.IsFirstPacket()) { + // We don't have enough data to update the filter, so we store it until we + // have two frames of data to process. + current_timestamp_group_.send_time = send_time; + current_timestamp_group_.first_send_time = send_time; + current_timestamp_group_.first_arrival = arrival_time; + } else if (current_timestamp_group_.first_send_time > send_time) { + // Reordered packet. + return false; + } else if (NewTimestampGroup(arrival_time, send_time)) { + // First packet of a later send burst, the previous packets sample is ready. + if (prev_timestamp_group_.complete_time.IsFinite()) { + *send_time_delta = + current_timestamp_group_.send_time - prev_timestamp_group_.send_time; + *arrival_time_delta = current_timestamp_group_.complete_time - + prev_timestamp_group_.complete_time; + + TimeDelta system_time_delta = current_timestamp_group_.last_system_time - + prev_timestamp_group_.last_system_time; + + if (*arrival_time_delta - system_time_delta >= + kArrivalTimeOffsetThreshold) { + MS_WARN_TAG(bwe, "the arrival time clock offset has changed (diff = %lld ms), resetting", + arrival_time_delta->ms() - system_time_delta.ms()); + Reset(); + return false; + } + if (*arrival_time_delta < TimeDelta::Zero()) { + // The group of packets has been reordered since receiving its local + // arrival timestamp. + ++num_consecutive_reordered_packets_; + if (num_consecutive_reordered_packets_ >= kReorderedResetThreshold) { + MS_WARN_TAG(bwe, "packets between send burst arrived out of order, resetting. arrival_time_delta %lld send time delta %lld", + arrival_time_delta->ms(), + send_time_delta->ms()); + Reset(); + } + return false; + } else { + num_consecutive_reordered_packets_ = 0; + } + *packet_size_delta = static_cast(current_timestamp_group_.size) - + static_cast(prev_timestamp_group_.size); + calculated_deltas = true; + } + prev_timestamp_group_ = current_timestamp_group_; + // The new timestamp is now the current frame. + current_timestamp_group_.first_send_time = send_time; + current_timestamp_group_.send_time = send_time; + current_timestamp_group_.first_arrival = arrival_time; + current_timestamp_group_.size = 0; + } else { + current_timestamp_group_.send_time = + std::max(current_timestamp_group_.send_time, send_time); + } + // Accumulate the frame size. + current_timestamp_group_.size += packet_size; + current_timestamp_group_.complete_time = arrival_time; + current_timestamp_group_.last_system_time = system_time; + + return calculated_deltas; +} + +// Assumes that `timestamp` is not reordered compared to +// `current_timestamp_group_`. +bool InterArrivalDelta::NewTimestampGroup(Timestamp arrival_time, + Timestamp send_time) const { + if (current_timestamp_group_.IsFirstPacket()) { + return false; + } else if (BelongsToBurst(arrival_time, send_time)) { + return false; + } else { + return send_time - current_timestamp_group_.first_send_time > + send_time_group_length_; + } +} + +bool InterArrivalDelta::BelongsToBurst(Timestamp arrival_time, + Timestamp send_time) const { + // RTC_DCHECK(current_timestamp_group_.complete_time.IsFinite()); + TimeDelta arrival_time_delta = + arrival_time - current_timestamp_group_.complete_time; + TimeDelta send_time_delta = send_time - current_timestamp_group_.send_time; + if (send_time_delta.IsZero()) + return true; + TimeDelta propagation_delta = arrival_time_delta - send_time_delta; + if (propagation_delta < TimeDelta::Zero() && + arrival_time_delta <= kBurstDeltaThreshold && + arrival_time - current_timestamp_group_.first_arrival < kMaxBurstDuration) + return true; + return false; +} + +void InterArrivalDelta::Reset() { + num_consecutive_reordered_packets_ = 0; + current_timestamp_group_ = SendTimeGroup(); + prev_timestamp_group_ = SendTimeGroup(); +} +} // namespace webrtc diff --git a/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/inter_arrival_delta.h b/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/inter_arrival_delta.h new file mode 100644 index 0000000000..e518578754 --- /dev/null +++ b/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/inter_arrival_delta.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2020 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_GOOG_CC_INTER_ARRIVAL_DELTA_H_ +#define MODULES_CONGESTION_CONTROLLER_GOOG_CC_INTER_ARRIVAL_DELTA_H_ + +#include "api/units/time_delta.h" +#include "api/units/timestamp.h" + +namespace webrtc { + +// Helper class to compute the inter-arrival time delta and the size delta +// between two send bursts. This code is branched from +// modules/remote_bitrate_estimator/inter_arrival. +class InterArrivalDelta { + public: + // After this many packet groups received out of order InterArrival will + // reset, assuming that clocks have made a jump. + static constexpr int kReorderedResetThreshold = 3; + static constexpr TimeDelta kArrivalTimeOffsetThreshold = + TimeDelta::Seconds<3>(); + + // A send time group is defined as all packets with a send time which are at + // most send_time_group_length older than the first timestamp in that + // group. + explicit InterArrivalDelta(TimeDelta send_time_group_length); + + InterArrivalDelta() = delete; + InterArrivalDelta(const InterArrivalDelta&) = delete; + InterArrivalDelta& operator=(const InterArrivalDelta&) = delete; + + // This function returns true if a delta was computed, or false if the current + // group is still incomplete or if only one group has been completed. + // `send_time` is the send time. + // `arrival_time` is the time at which the packet arrived. + // `packet_size` is the size of the packet. + // `timestamp_delta` (output) is the computed send time delta. + // `arrival_time_delta_ms` (output) is the computed arrival-time delta. + // `packet_size_delta` (output) is the computed size delta. + bool ComputeDeltas(Timestamp send_time, + Timestamp arrival_time, + Timestamp system_time, + size_t packet_size, + TimeDelta* send_time_delta, + TimeDelta* arrival_time_delta, + int* packet_size_delta); + + private: + struct SendTimeGroup { + SendTimeGroup() + : size(0), + first_send_time(Timestamp::MinusInfinity()), + send_time(Timestamp::MinusInfinity()), + first_arrival(Timestamp::MinusInfinity()), + complete_time(Timestamp::MinusInfinity()), + last_system_time(Timestamp::MinusInfinity()) {} + + bool IsFirstPacket() const { return complete_time.IsInfinite(); } + + size_t size; + Timestamp first_send_time; + Timestamp send_time; + Timestamp first_arrival; + Timestamp complete_time; + Timestamp last_system_time; + }; + + // Returns true if the last packet was the end of the current batch and the + // packet with `send_time` is the first of a new batch. + bool NewTimestampGroup(Timestamp arrival_time, Timestamp send_time) const; + + bool BelongsToBurst(Timestamp arrival_time, Timestamp send_time) const; + + void Reset(); + + const TimeDelta send_time_group_length_; + SendTimeGroup current_timestamp_group_; + SendTimeGroup prev_timestamp_group_; + int num_consecutive_reordered_packets_; +}; +} // namespace webrtc + +#endif // MODULES_CONGESTION_CONTROLLER_GOOG_CC_INTER_ARRIVAL_DELTA_H_ diff --git a/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/median_slope_estimator.cc b/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/median_slope_estimator.cc deleted file mode 100644 index 07648b9751..0000000000 --- a/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/median_slope_estimator.cc +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (c) 2016 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/goog_cc/median_slope_estimator.h" - -#include - -namespace webrtc { - -constexpr unsigned int kDeltaCounterMax = 1000; - -MedianSlopeEstimator::MedianSlopeEstimator(size_t window_size, - double threshold_gain) - : window_size_(window_size), - threshold_gain_(threshold_gain), - num_of_deltas_(0), - accumulated_delay_(0), - delay_hist_(), - median_filter_(0.5), - trendline_(0) {} - -MedianSlopeEstimator::~MedianSlopeEstimator() {} - -MedianSlopeEstimator::DelayInfo::DelayInfo(int64_t time, - double delay, - size_t slope_count) - : time(time), delay(delay) { - slopes.reserve(slope_count); -} - -MedianSlopeEstimator::DelayInfo::~DelayInfo() = default; - -void MedianSlopeEstimator::Update(double recv_delta_ms, - double send_delta_ms, - int64_t arrival_time_ms) { - const double delta_ms = recv_delta_ms - send_delta_ms; - ++num_of_deltas_; - if (num_of_deltas_ > kDeltaCounterMax) - num_of_deltas_ = kDeltaCounterMax; - - accumulated_delay_ += delta_ms; - // BWE_TEST_LOGGING_PLOT(1, "accumulated_delay_ms", arrival_time_ms, - // accumulated_delay_); - - // If the window is full, remove the |window_size_| - 1 slopes that belong to - // the oldest point. - if (delay_hist_.size() == window_size_) { - // for (double slope : delay_hist_.front().slopes) { - // const bool success = median_filter_.Erase(slope); - // RTC_CHECK(success); - // } - delay_hist_.pop_front(); - } - // Add |window_size_| - 1 new slopes. - for (auto& old_delay : delay_hist_) { - if (arrival_time_ms - old_delay.time != 0) { - // The C99 standard explicitly states that casts and assignments must - // perform the associated conversions. This means that |slope| will be - // a 64-bit double even if the division is computed using, e.g., 80-bit - // extended precision. I believe this also holds in C++ even though the - // C++11 standard isn't as explicit. Furthermore, there are good reasons - // to believe that compilers couldn't perform optimizations that break - // this assumption even if they wanted to. - double slope = (accumulated_delay_ - old_delay.delay) / - static_cast(arrival_time_ms - old_delay.time); - median_filter_.Insert(slope); - // We want to avoid issues with different rounding mode / precision - // which we might get if we recomputed the slope when we remove it. - old_delay.slopes.push_back(slope); - } - } - delay_hist_.emplace_back(arrival_time_ms, accumulated_delay_, - window_size_ - 1); - // Recompute the median slope. - if (delay_hist_.size() == window_size_) - trendline_ = median_filter_.GetPercentileValue(); - - // BWE_TEST_LOGGING_PLOT(1, "trendline_slope", arrival_time_ms, trendline_); -} - -} // namespace webrtc diff --git a/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/median_slope_estimator.h b/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/median_slope_estimator.h deleted file mode 100644 index 674a82829a..0000000000 --- a/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/median_slope_estimator.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2016 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_GOOG_CC_MEDIAN_SLOPE_ESTIMATOR_H_ -#define MODULES_CONGESTION_CONTROLLER_GOOG_CC_MEDIAN_SLOPE_ESTIMATOR_H_ - -#include "rtc_base/constructor_magic.h" -#include "rtc_base/numerics/percentile_filter.h" - -#include -#include -#include -#include - -namespace webrtc { - -class MedianSlopeEstimator { - public: - // |window_size| is the number of points required to compute a trend line. - // |threshold_gain| is used to scale the trendline slope for comparison to - // the old threshold. Once the old estimator has been removed (or the - // thresholds been merged into the estimators), we can just set the - // threshold instead of setting a gain. - MedianSlopeEstimator(size_t window_size, double threshold_gain); - ~MedianSlopeEstimator(); - - // Update the estimator with a new sample. The deltas should represent deltas - // between timestamp groups as defined by the InterArrival class. - void Update(double recv_delta_ms, - double send_delta_ms, - int64_t arrival_time_ms); - - // Returns the estimated trend k multiplied by some gain. - // 0 < k < 1 -> the delay increases, queues are filling up - // k == 0 -> the delay does not change - // k < 0 -> the delay decreases, queues are being emptied - double trendline_slope() const { return trendline_ * threshold_gain_; } - - // Returns the number of deltas which the current estimator state is based on. - unsigned int num_of_deltas() const { return num_of_deltas_; } - - private: - struct DelayInfo { - DelayInfo(int64_t time, double delay, size_t slope_count); - ~DelayInfo(); - int64_t time; - double delay; - std::vector slopes; - }; - // Parameters. - const size_t window_size_; - const double threshold_gain_; - // Used by the existing threshold. - unsigned int num_of_deltas_; - // Theil-Sen robust line fitting - double accumulated_delay_; - std::deque delay_hist_; - PercentileFilter median_filter_; - double trendline_; - - RTC_DISALLOW_COPY_AND_ASSIGN(MedianSlopeEstimator); -}; - -} // namespace webrtc - -#endif // MODULES_CONGESTION_CONTROLLER_GOOG_CC_MEDIAN_SLOPE_ESTIMATOR_H_ diff --git a/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/probe_controller.cc b/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/probe_controller.cc index b5e8abae36..129460c1b9 100644 --- a/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/probe_controller.cc +++ b/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/probe_controller.cc @@ -27,40 +27,30 @@ namespace webrtc { namespace { -// The minimum number probing packets used. -constexpr int kMinProbePacketsSent = 5; - -// The minimum probing duration in ms. -constexpr int kMinProbeDurationMs = 15; - // Maximum waiting time from the time of initiating probing to getting // the measured results back. -constexpr int64_t kMaxWaitingTimeForProbingResultMs = 1000; - -// Value of |min_bitrate_to_probe_further_bps_| that indicates -// further probing is disabled. -constexpr int kExponentialProbingDisabled = 0; +constexpr TimeDelta kMaxWaitingTimeForProbingResult = TimeDelta::Seconds<1>(); // Default probing bitrate limit. Applied only when the application didn't // specify max bitrate. -constexpr int64_t kDefaultMaxProbingBitrateBps = 5000000; +constexpr DataRate kDefaultMaxProbingBitrate = DataRate::KilobitsPerSec<5000>(); // If the bitrate drops to a factor |kBitrateDropThreshold| or lower // and we recover within |kBitrateDropTimeoutMs|, then we'll send // a probe at a fraction |kProbeFractionAfterDrop| of the original bitrate. constexpr double kBitrateDropThreshold = 0.66; -constexpr int kBitrateDropTimeoutMs = 5000; +constexpr TimeDelta kBitrateDropTimeout = TimeDelta::Seconds<5>(); constexpr double kProbeFractionAfterDrop = 0.85; // Timeout for probing after leaving ALR. If the bitrate drops significantly, // (as determined by the delay based estimator) and we leave ALR, then we will -// send a probe if we recover within |kLeftAlrTimeoutMs| ms. -constexpr int kAlrEndedTimeoutMs = 3000; +// send a probe if we recover within `kLeftAlrTimeoutMs` ms. +constexpr TimeDelta kAlrEndedTimeout = TimeDelta::Seconds<3>(); // The expected uncertainty of probe result (as a fraction of the target probe // This is a limit on how often probing can be done when there is a BW // drop detected in ALR. -constexpr int64_t kMinTimeBetweenAlrProbesMs = 5000; +constexpr TimeDelta kMinTimeBetweenAlrProbes = TimeDelta::Seconds<5>(); // bitrate). Used to avoid probing if the probe bitrate is close to our current // estimate. @@ -70,13 +60,6 @@ constexpr double kProbeUncertainty = 0.05; constexpr char kBweRapidRecoveryExperiment[] = "WebRTC-BweRapidRecoveryExperiment"; -// Never probe higher than configured by OnMaxTotalAllocatedBitrate(). -constexpr char kCappedProbingFieldTrialName[] = "WebRTC-BweCappedProbing"; - -// Only do allocation probing when in ALR (but not when network-limited). -constexpr char kAllocProbingOnlyInAlrFieldTrialName[] = - "WebRTC-BweAllocProbingOnlyInAlr"; - void MaybeLogProbeClusterCreated(const ProbeClusterConfig& probe) { #if MS_LOG_DEV_LEVEL == 3 size_t min_bytes = static_cast(probe.target_data_rate.bps() * @@ -98,15 +81,54 @@ ProbeControllerConfig::ProbeControllerConfig( further_probe_threshold("further_probe_threshold", 0.7), alr_probing_interval("alr_interval", TimeDelta::seconds(5)), alr_probe_scale("alr_scale", 2), + network_state_estimate_probing_interval("network_state_interval", + TimeDelta::PlusInfinity()), + probe_if_estimate_lower_than_network_state_estimate_ratio( + "est_lower_than_network_ratio", + 0), + estimate_lower_than_network_state_estimate_probing_interval( + "est_lower_than_network_interval", + TimeDelta::seconds(3)), + network_state_probe_scale("network_state_scale", 1.0), + network_state_probe_duration("network_state_probe_duration", + TimeDelta::Millis<15>()), + + probe_on_max_allocated_bitrate_change("probe_max_allocation", true), first_allocation_probe_scale("alloc_p1", 1), second_allocation_probe_scale("alloc_p2", 2), - allocation_allow_further_probing("alloc_probe_further", false) { - ParseFieldTrial( - {&first_exponential_probe_scale, &second_exponential_probe_scale, - &further_exponential_probe_scale, &further_probe_threshold, - &alr_probing_interval, &alr_probe_scale, &first_allocation_probe_scale, - &second_allocation_probe_scale, &allocation_allow_further_probing}, - key_value_config->Lookup("WebRTC-Bwe-ProbingConfiguration")); + allocation_allow_further_probing("alloc_probe_further", false), + allocation_probe_max("alloc_probe_max", DataRate::PlusInfinity()), + min_probe_packets_sent("min_probe_packets_sent", 5), + min_probe_duration("min_probe_duration", TimeDelta::ms(15)), + limit_probe_target_rate_to_loss_bwe("limit_probe_target_rate_to_loss_bwe", + false), + loss_limited_probe_scale("loss_limited_scale", 1.5), + skip_if_estimate_larger_than_fraction_of_max( + "skip_if_est_larger_than_fraction_of_max", + 0.0), + not_probe_if_delay_increased("not_probe_if_delay_increased", false) { + ParseFieldTrial({&first_exponential_probe_scale, + &second_exponential_probe_scale, + &further_exponential_probe_scale, + &further_probe_threshold, + &alr_probing_interval, + &alr_probe_scale, + &probe_on_max_allocated_bitrate_change, + &first_allocation_probe_scale, + &second_allocation_probe_scale, + &allocation_allow_further_probing, + &min_probe_duration, + &network_state_estimate_probing_interval, + &probe_if_estimate_lower_than_network_state_estimate_ratio, + &estimate_lower_than_network_state_estimate_probing_interval, + &network_state_probe_scale, + &network_state_probe_duration, + &min_probe_packets_sent, + &limit_probe_target_rate_to_loss_bwe, + &loss_limited_probe_scale, + &skip_if_estimate_larger_than_fraction_of_max, + ¬_probe_if_delay_increased}, + key_value_config->Lookup("WebRTC-Bwe-ProbingConfiguration")); // Specialized keys overriding subsets of WebRTC-Bwe-ProbingConfiguration ParseFieldTrial( @@ -114,12 +136,15 @@ ProbeControllerConfig::ProbeControllerConfig( key_value_config->Lookup("WebRTC-Bwe-InitialProbing")); ParseFieldTrial({&further_exponential_probe_scale, &further_probe_threshold}, key_value_config->Lookup("WebRTC-Bwe-ExponentialProbing")); - ParseFieldTrial({&alr_probing_interval, &alr_probe_scale}, - key_value_config->Lookup("WebRTC-Bwe-AlrProbing")); + ParseFieldTrial( + {&alr_probing_interval, &alr_probe_scale, &loss_limited_probe_scale}, + key_value_config->Lookup("WebRTC-Bwe-AlrProbing")); ParseFieldTrial( {&first_allocation_probe_scale, &second_allocation_probe_scale, - &allocation_allow_further_probing}, + &allocation_allow_further_probing, &allocation_probe_max}, key_value_config->Lookup("WebRTC-Bwe-AllocationProbing")); + ParseFieldTrial({&min_probe_packets_sent, &min_probe_duration}, + key_value_config->Lookup("WebRTC-Bwe-ProbingBehavior")); } ProbeControllerConfig::ProbeControllerConfig(const ProbeControllerConfig&) = @@ -129,46 +154,39 @@ ProbeControllerConfig::~ProbeControllerConfig() = default; ProbeController::ProbeController(const WebRtcKeyValueConfig* key_value_config) : enable_periodic_alr_probing_(false), in_rapid_recovery_experiment_( - key_value_config->Lookup(kBweRapidRecoveryExperiment) - .find("Enabled") == 0), - limit_probes_with_allocateable_rate_( - key_value_config->Lookup(kCappedProbingFieldTrialName) - .find("Disabled") != 0), - allocation_probing_only_in_alr_( - key_value_config->Lookup(kAllocProbingOnlyInAlrFieldTrialName) - .find("Enabled") == 0), + key_value_config->Lookup(kBweRapidRecoveryExperiment).find("Enabled") == 0 + ), + //event_log_(event_log), config_(ProbeControllerConfig(key_value_config)) { - Reset(0); + Reset(Timestamp::Zero()); } ProbeController::~ProbeController() {} std::vector ProbeController::SetBitrates( - int64_t min_bitrate_bps, - int64_t start_bitrate_bps, - int64_t max_bitrate_bps, - int64_t at_time_ms) { - if (start_bitrate_bps > 0) { - start_bitrate_bps_ = start_bitrate_bps; - estimated_bitrate_bps_ = start_bitrate_bps; - } else if (start_bitrate_bps_ == 0) { - start_bitrate_bps_ = min_bitrate_bps; + DataRate min_bitrate, + DataRate start_bitrate, + DataRate max_bitrate, + Timestamp at_time) { + if (start_bitrate > DataRate::Zero()) { + start_bitrate_ = start_bitrate; + estimated_bitrate_ = start_bitrate; + } else if (start_bitrate_.IsZero()) { + start_bitrate_ = min_bitrate; } - - MS_DEBUG_DEV( - "[old_max_bitrate_bps:%lld, max_bitrate_bps:%lld]", - max_bitrate_bps_, - max_bitrate_bps); - - // The reason we use the variable |old_max_bitrate_pbs| is because we - // need to set |max_bitrate_bps_| before we call InitiateProbing. - int64_t old_max_bitrate_bps = max_bitrate_bps_; - max_bitrate_bps_ = max_bitrate_bps; - + // The reason we use the variable `old_max_bitrate_pbs` is because we + // need to set `max_bitrate_` before we call InitiateProbing. + DataRate old_max_bitrate = max_bitrate_; + max_bitrate_ = + max_bitrate.IsFinite() ? max_bitrate : kDefaultMaxProbingBitrate; + MS_DEBUG_DEV( + "[old_max_bitrate_bps:%lld, max_bitrate_bps:%lld]", + old_max_bitrate.bps(), + max_bitrate_.bps()); switch (state_) { case State::kInit: if (network_available_) - return InitiateExponentialProbing(at_time_ms); + return InitiateExponentialProbing(at_time); break; case State::kWaitingForProbingResult: @@ -177,21 +195,9 @@ std::vector ProbeController::SetBitrates( case State::kProbingComplete: // If the new max bitrate is higher than both the old max bitrate and the // estimate then initiate probing. - if (estimated_bitrate_bps_ != 0 && - old_max_bitrate_bps < max_bitrate_bps_ && - estimated_bitrate_bps_ < max_bitrate_bps_) { - // The assumption is that if we jump more than 20% in the bandwidth - // estimate or if the bandwidth estimate is within 90% of the new - // max bitrate then the probing attempt was successful. - mid_call_probing_succcess_threshold_ = - std::min(estimated_bitrate_bps_ * 1.2, max_bitrate_bps_ * 0.9); - mid_call_probing_waiting_for_result_ = true; - mid_call_probing_bitrate_bps_ = max_bitrate_bps_; - - // RTC_HISTOGRAM_COUNTS_10000("WebRTC.BWE.MidCallProbing.Initiated", - // max_bitrate_bps_ / 1000); - - return InitiateProbing(at_time_ms, {max_bitrate_bps_}, false); + if (!estimated_bitrate_.IsZero() && old_max_bitrate < max_bitrate_ && + estimated_bitrate_ < max_bitrate_) { + return InitiateProbing(at_time, {max_bitrate_}, false); } break; } @@ -199,34 +205,37 @@ std::vector ProbeController::SetBitrates( } std::vector ProbeController::OnMaxTotalAllocatedBitrate( - int64_t max_total_allocated_bitrate, - int64_t at_time_ms) { - MS_DEBUG_DEV("[max_total_allocated_bitrate:%" PRIi64 "]", max_total_allocated_bitrate); - - const bool in_alr = alr_start_time_ms_.has_value(); - const bool allow_allocation_probe = - allocation_probing_only_in_alr_ ? in_alr : true; + DataRate max_total_allocated_bitrate, + Timestamp at_time) { + const bool in_alr = alr_start_time_.has_value(); + const bool allow_allocation_probe = in_alr; - if (state_ == State::kProbingComplete && + if (config_.probe_on_max_allocated_bitrate_change && + state_ == State::kProbingComplete && max_total_allocated_bitrate != max_total_allocated_bitrate_ && - estimated_bitrate_bps_ != 0 && - (max_bitrate_bps_ <= 0 || estimated_bitrate_bps_ < max_bitrate_bps_) && - estimated_bitrate_bps_ < max_total_allocated_bitrate && + estimated_bitrate_ < max_bitrate_ && + estimated_bitrate_ < max_total_allocated_bitrate && allow_allocation_probe) { max_total_allocated_bitrate_ = max_total_allocated_bitrate; if (!config_.first_allocation_probe_scale) return std::vector(); - std::vector probes = { - static_cast(config_.first_allocation_probe_scale.Value() * - max_total_allocated_bitrate)}; + DataRate first_probe_rate = max_total_allocated_bitrate * + config_.first_allocation_probe_scale.Value(); + DataRate probe_cap = config_.allocation_probe_max.Get(); + first_probe_rate = std::min(first_probe_rate, probe_cap); + std::vector probes = {first_probe_rate}; if (config_.second_allocation_probe_scale) { - probes.push_back(config_.second_allocation_probe_scale.Value() * - max_total_allocated_bitrate); + DataRate second_probe_rate = + max_total_allocated_bitrate * + config_.second_allocation_probe_scale.Value(); + second_probe_rate = std::min(second_probe_rate, probe_cap); + if (second_probe_rate > first_probe_rate) + probes.push_back(second_probe_rate); } - return InitiateProbing(at_time_ms, probes, - config_.allocation_allow_further_probing); + return InitiateProbing(at_time, probes, + config_.allocation_allow_further_probing.Get()); } max_total_allocated_bitrate_ = max_total_allocated_bitrate; return std::vector(); @@ -238,16 +247,16 @@ std::vector ProbeController::OnNetworkAvailability( if (!network_available_ && state_ == State::kWaitingForProbingResult) { state_ = State::kProbingComplete; - min_bitrate_to_probe_further_bps_ = kExponentialProbingDisabled; + min_bitrate_to_probe_further_ = DataRate::PlusInfinity(); } - if (network_available_ && state_ == State::kInit && start_bitrate_bps_ > 0) - return InitiateExponentialProbing(msg.at_time.ms()); + if (network_available_ && state_ == State::kInit && !start_bitrate_.IsZero()) + return InitiateExponentialProbing(msg.at_time); return std::vector(); } std::vector ProbeController::InitiateExponentialProbing( - int64_t at_time_ms) { + Timestamp at_time) { //RTC_DCHECK(network_available_); //RTC_DCHECK(state_ == State::kInit); //RTC_DCHECK_GT(start_bitrate_bps_, 0); @@ -257,57 +266,53 @@ std::vector ProbeController::InitiateExponentialProbing( if (state_ != State::kInit) { MS_ERROR("state_ must be State::kInit"); } - if (start_bitrate_bps_ <= 0) { + if (start_bitrate_bps_ <= DataRate::Zero()) { MS_ERROR("start_bitrate_bps_ must be > 0"); } // When probing at 1.8 Mbps ( 6x 300), this represents a threshold of // 1.2 Mbps to continue probing. - std::vector probes = {static_cast( - config_.first_exponential_probe_scale * start_bitrate_bps_)}; - if (config_.second_exponential_probe_scale) { + std::vector probes = {config_.first_exponential_probe_scale * + start_bitrate_}; + if (config_.second_exponential_probe_scale && + config_.second_exponential_probe_scale.GetOptional().value() > 0) { probes.push_back(config_.second_exponential_probe_scale.Value() * - start_bitrate_bps_); + start_bitrate_); } - return InitiateProbing(at_time_ms, probes, true); + return InitiateProbing(at_time, probes, true); } std::vector ProbeController::SetEstimatedBitrate( - int64_t bitrate_bps, - int64_t at_time_ms) { - if (mid_call_probing_waiting_for_result_ && - bitrate_bps >= mid_call_probing_succcess_threshold_) { - // RTC_HISTOGRAM_COUNTS_10000("WebRTC.BWE.MidCallProbing.Success", - // mid_call_probing_bitrate_bps_ / 1000); - // RTC_HISTOGRAM_COUNTS_10000("WebRTC.BWE.MidCallProbing.ProbedKbps", - // bitrate_bps / 1000); - mid_call_probing_waiting_for_result_ = false; + DataRate bitrate, + BandwidthLimitedCause bandwidth_limited_cause, + Timestamp at_time) { + bandwidth_limited_cause_ = bandwidth_limited_cause; + if (bitrate < kBitrateDropThreshold * estimated_bitrate_) { + time_of_last_large_drop_ = at_time; + bitrate_before_last_large_drop_ = estimated_bitrate_; } - std::vector pending_probes; + estimated_bitrate_ = bitrate; if (state_ == State::kWaitingForProbingResult) { // Continue probing if probing results indicate channel has greater // capacity. - // MS_DEBUG_DEV( - // "[measured bitrate:%" PRIi64 ", minimum to probe further:%" PRIi64 "]", - // bitrate_bps, min_bitrate_to_probe_further_bps_); - - if (min_bitrate_to_probe_further_bps_ != kExponentialProbingDisabled && - bitrate_bps > min_bitrate_to_probe_further_bps_) { - pending_probes = InitiateProbing( - at_time_ms, - {static_cast(config_.further_exponential_probe_scale * - bitrate_bps)}, - true); + DataRate network_state_estimate_probe_further_limit = + config_.network_state_estimate_probing_interval->IsFinite() && + network_estimate_ + ? network_estimate_->link_capacity_upper * + config_.further_probe_threshold + : DataRate::PlusInfinity(); +/* RTC_LOG(LS_INFO) << "Measured bitrate: " << bitrate + << " Minimum to probe further: " + << min_bitrate_to_probe_further_ << " upper limit: " + << network_state_estimate_probe_further_limit;*/ + + if (bitrate > min_bitrate_to_probe_further_ && + bitrate <= network_state_estimate_probe_further_limit) { + return InitiateProbing( + at_time, {config_.further_exponential_probe_scale * bitrate}, true); } } - - if (bitrate_bps < kBitrateDropThreshold * estimated_bitrate_bps_) { - time_of_last_large_drop_ms_ = at_time_ms; - bitrate_before_last_large_drop_bps_ = estimated_bitrate_bps_; - } - - estimated_bitrate_bps_ = bitrate_bps; - return pending_probes; + return {}; } void ProbeController::EnablePeriodicAlrProbing(bool enable) { @@ -316,153 +321,249 @@ void ProbeController::EnablePeriodicAlrProbing(bool enable) { void ProbeController::SetAlrStartTimeMs( absl::optional alr_start_time_ms) { - alr_start_time_ms_ = alr_start_time_ms; + if ((alr_start_time_ms.has_value() && !alr_start_time_.has_value()) || + (alr_start_time_ms.has_value() && alr_start_time_.has_value() && (alr_start_time_.value().ms() != alr_start_time_ms.value()))) + { + MS_DEBUG_TAG(bwe, "ALR Start, start time %ld", alr_start_time_ms.value()); + alr_start_time_ = Timestamp::ms(alr_start_time_ms.value()); + } + if (alr_start_time_.has_value() && !alr_start_time_ms.has_value()) { + alr_start_time_ = absl::nullopt; + } + /*} else { + alr_start_time_ = absl::nullopt; + }*/ } void ProbeController::SetAlrEndedTimeMs(int64_t alr_end_time_ms) { - alr_end_time_ms_.emplace(alr_end_time_ms); + MS_DEBUG_TAG(bwe, "ALR End, end time %lld", alr_end_time_ms); + alr_end_time_.emplace(Timestamp::ms(alr_end_time_ms)); } std::vector ProbeController::RequestProbe( - int64_t at_time_ms) { + Timestamp at_time) { + MS_DEBUG_DEV("Requesting probe"); // Called once we have returned to normal state after a large drop in // estimated bandwidth. The current response is to initiate a single probe // session (if not already probing) at the previous bitrate. // // If the probe session fails, the assumption is that this drop was a // real one from a competing flow or a network change. - bool in_alr = alr_start_time_ms_.has_value(); + bool in_alr = alr_start_time_.has_value(); bool alr_ended_recently = - (alr_end_time_ms_.has_value() && - at_time_ms - alr_end_time_ms_.value() < kAlrEndedTimeoutMs); + (alr_end_time_.has_value() && + at_time - alr_end_time_.value() < kAlrEndedTimeout); + MS_DEBUG_DEV("in_alr: %d, alr_ended_recently:%d, in_rapid_recovery_experiment_:%d, state: %d", in_alr, alr_ended_recently, in_rapid_recovery_experiment_, state_); if (in_alr || alr_ended_recently || in_rapid_recovery_experiment_) { if (state_ == State::kProbingComplete) { - uint32_t suggested_probe_bps = - kProbeFractionAfterDrop * bitrate_before_last_large_drop_bps_; - uint32_t min_expected_probe_result_bps = - (1 - kProbeUncertainty) * suggested_probe_bps; - int64_t time_since_drop_ms = at_time_ms - time_of_last_large_drop_ms_; - int64_t time_since_probe_ms = at_time_ms - last_bwe_drop_probing_time_ms_; - if (min_expected_probe_result_bps > estimated_bitrate_bps_ && - time_since_drop_ms < kBitrateDropTimeoutMs && - time_since_probe_ms > kMinTimeBetweenAlrProbesMs) { - MS_WARN_TAG(bwe, "detected big bandwidth drop, start probing"); + DataRate suggested_probe = + kProbeFractionAfterDrop * bitrate_before_last_large_drop_; + DataRate min_expected_probe_result = + (1 - kProbeUncertainty) * suggested_probe; + TimeDelta time_since_drop = at_time - time_of_last_large_drop_; + TimeDelta time_since_probe = at_time - last_bwe_drop_probing_time_; + MS_DEBUG_DEV("min_expected_probe_result: %lld, estimated_bitrate_:%lld, time_since_drop:%lld, time_since_probe: %lld", min_expected_probe_result.bps(), estimated_bitrate_.bps(), time_since_drop.seconds(), time_since_probe.seconds()); + if (min_expected_probe_result > estimated_bitrate_ && + time_since_drop < kBitrateDropTimeout && + time_since_probe > kMinTimeBetweenAlrProbes) { + MS_WARN_TAG(bwe, "detected big bandwidth drop, start probing"); // Track how often we probe in response to bandwidth drop in ALR. // RTC_HISTOGRAM_COUNTS_10000( // "WebRTC.BWE.BweDropProbingIntervalInS", // (at_time_ms - last_bwe_drop_probing_time_ms_) / 1000); - last_bwe_drop_probing_time_ms_ = at_time_ms; - return InitiateProbing(at_time_ms, {suggested_probe_bps}, false); + last_bwe_drop_probing_time_ = at_time; + return InitiateProbing(at_time, {suggested_probe}, false); } } } return std::vector(); } -void ProbeController::SetMaxBitrate(int64_t max_bitrate_bps) { - MS_DEBUG_DEV("[max_bitrate_bps:%" PRIi64 "]", max_bitrate_bps); - - max_bitrate_bps_ = max_bitrate_bps; +void ProbeController::SetNetworkStateEstimate( + webrtc::NetworkStateEstimate estimate) { + network_estimate_ = estimate; } -void ProbeController::Reset(int64_t at_time_ms) { - MS_DEBUG_DEV("resetted"); - +void ProbeController::Reset(Timestamp at_time) { network_available_ = true; + bandwidth_limited_cause_ = BandwidthLimitedCause::kDelayBasedLimited; state_ = State::kInit; - min_bitrate_to_probe_further_bps_ = kExponentialProbingDisabled; - time_last_probing_initiated_ms_ = 0; - estimated_bitrate_bps_ = 0; - start_bitrate_bps_ = 0; - max_bitrate_bps_ = 0; - int64_t now_ms = at_time_ms; - last_bwe_drop_probing_time_ms_ = now_ms; - alr_end_time_ms_.reset(); - mid_call_probing_waiting_for_result_ = false; - time_of_last_large_drop_ms_ = now_ms; - bitrate_before_last_large_drop_bps_ = 0; - max_total_allocated_bitrate_ = 0; + min_bitrate_to_probe_further_ = DataRate::PlusInfinity(); + time_last_probing_initiated_ = Timestamp::Zero(); + estimated_bitrate_ = DataRate::Zero(); + network_estimate_ = absl::nullopt; + start_bitrate_ = DataRate::Zero(); + max_bitrate_ = kDefaultMaxProbingBitrate; + Timestamp now = at_time; + last_bwe_drop_probing_time_ = now; + alr_end_time_.reset(); + time_of_last_large_drop_ = now; + bitrate_before_last_large_drop_ = DataRate::Zero(); + max_total_allocated_bitrate_ = DataRate::Zero(); +} + +bool ProbeController::TimeForAlrProbe(Timestamp at_time) const { + if (enable_periodic_alr_probing_ && alr_start_time_) { + Timestamp next_probe_time = + std::max(*alr_start_time_, time_last_probing_initiated_) + + config_.alr_probing_interval; + return at_time >= next_probe_time; + } + return false; } -std::vector ProbeController::Process(int64_t at_time_ms) { - if (at_time_ms - time_last_probing_initiated_ms_ > - kMaxWaitingTimeForProbingResultMs) { - mid_call_probing_waiting_for_result_ = false; +bool ProbeController::TimeForNetworkStateProbe(Timestamp at_time) const { + if (!network_estimate_ || + network_estimate_->link_capacity_upper.IsInfinite()) { + return false; + } + + bool probe_due_to_low_estimate = + bandwidth_limited_cause_ == BandwidthLimitedCause::kDelayBasedLimited && + estimated_bitrate_ < + config_.probe_if_estimate_lower_than_network_state_estimate_ratio * + network_estimate_->link_capacity_upper; + if (probe_due_to_low_estimate && + config_.estimate_lower_than_network_state_estimate_probing_interval + ->IsFinite()) { + Timestamp next_probe_time = + time_last_probing_initiated_ + + config_.estimate_lower_than_network_state_estimate_probing_interval; + return at_time >= next_probe_time; + } + + bool periodic_probe = + estimated_bitrate_ < network_estimate_->link_capacity_upper; + if (periodic_probe && + config_.network_state_estimate_probing_interval->IsFinite()) { + Timestamp next_probe_time = time_last_probing_initiated_ + + config_.network_state_estimate_probing_interval; + return at_time >= next_probe_time; + } + return false; +} + +std::vector ProbeController::Process(Timestamp at_time) { + if (at_time - time_last_probing_initiated_ > + kMaxWaitingTimeForProbingResult) { if (state_ == State::kWaitingForProbingResult) { MS_WARN_TAG(bwe, "kWaitingForProbingResult: timeout"); state_ = State::kProbingComplete; - min_bitrate_to_probe_further_bps_ = kExponentialProbingDisabled; + min_bitrate_to_probe_further_ = DataRate::PlusInfinity(); } } - - if (enable_periodic_alr_probing_ && state_ == State::kProbingComplete) { - // Probe bandwidth periodically when in ALR state. - if (alr_start_time_ms_ && estimated_bitrate_bps_ > 0) { - int64_t next_probe_time_ms = - std::max(*alr_start_time_ms_, time_last_probing_initiated_ms_) + - config_.alr_probing_interval->ms(); - if (at_time_ms >= next_probe_time_ms) { - return InitiateProbing(at_time_ms, - {static_cast(estimated_bitrate_bps_ * - config_.alr_probe_scale)}, - true); - } - } + if (estimated_bitrate_.IsZero() || state_ != State::kProbingComplete) { + return {}; + } + if (TimeForAlrProbe(at_time) || TimeForNetworkStateProbe(at_time)) { + return InitiateProbing( + at_time, {estimated_bitrate_ * config_.alr_probe_scale}, true); } return std::vector(); } - std::vector ProbeController::InitiateProbing( - int64_t now_ms, - std::vector bitrates_to_probe, + Timestamp now, + std::vector bitrates_to_probe, bool probe_further) { - int64_t max_probe_bitrate_bps = - max_bitrate_bps_ > 0 ? max_bitrate_bps_ : kDefaultMaxProbingBitrateBps; - - MS_DEBUG_DEV( - "[max_bitrate_bps_:%lld, max_probe_bitrate_bps:%" PRIi64 "]", - max_bitrate_bps_, - max_probe_bitrate_bps); - - if (limit_probes_with_allocateable_rate_ && - max_total_allocated_bitrate_ > 0) { + if (config_.skip_if_estimate_larger_than_fraction_of_max > 0) { + DataRate network_estimate = network_estimate_ + ? network_estimate_->link_capacity_upper + : DataRate::PlusInfinity(); + DataRate max_probe_rate = + max_total_allocated_bitrate_.IsZero() + ? max_bitrate_ + : std::min(max_total_allocated_bitrate_, max_bitrate_); + if (std::min(network_estimate, estimated_bitrate_) > + config_.skip_if_estimate_larger_than_fraction_of_max * max_probe_rate) { + state_ = State::kProbingComplete; + min_bitrate_to_probe_further_ = DataRate::PlusInfinity(); + return {}; + } + } + DataRate max_probe_bitrate = max_bitrate_; + if (max_total_allocated_bitrate_ > DataRate::Zero()) { // If a max allocated bitrate has been configured, allow probing up to 2x // that rate. This allows some overhead to account for bursty streams, // which otherwise would have to ramp up when the overshoot is already in // progress. // It also avoids minor quality reduction caused by probes often being // received at slightly less than the target probe bitrate. - max_probe_bitrate_bps = - std::min(max_probe_bitrate_bps, max_total_allocated_bitrate_ * 2); + max_probe_bitrate = + std::min(max_probe_bitrate, max_total_allocated_bitrate_ * 2); + } + + DataRate estimate_capped_bitrate = DataRate::PlusInfinity(); + if (config_.limit_probe_target_rate_to_loss_bwe) { + switch (bandwidth_limited_cause_) { + case BandwidthLimitedCause::kLossLimitedBweDecreasing: + // If bandwidth estimate is decreasing because of packet loss, do not + // send probes. + return {}; + case BandwidthLimitedCause::kLossLimitedBweIncreasing: + estimate_capped_bitrate = + std::min(max_probe_bitrate, + estimated_bitrate_ * config_.loss_limited_probe_scale); + break; + case BandwidthLimitedCause::kDelayBasedLimited: + break; + default: + break; + } + } + if (config_.not_probe_if_delay_increased && + bandwidth_limited_cause_ == + BandwidthLimitedCause::kDelayBasedLimitedDelayIncreased) { + return {}; + } + if (config_.network_state_estimate_probing_interval->IsFinite() && + network_estimate_ && network_estimate_->link_capacity_upper.IsFinite()) { + if (network_estimate_->link_capacity_upper.IsZero()) { + MS_DEBUG_TAG(bwe, "Not sending probe, Network state estimate is zero"); + return {}; + } + estimate_capped_bitrate = + std::min({estimate_capped_bitrate, max_probe_bitrate, + network_estimate_->link_capacity_upper * + config_.network_state_probe_scale}); } std::vector pending_probes; - for (int64_t bitrate : bitrates_to_probe) { - //RTC_DCHECK_GT(bitrate, 0); + for (DataRate bitrate : bitrates_to_probe) { + // RTC_DCHECK(!bitrate.IsZero()); - if (bitrate > max_probe_bitrate_bps) { - bitrate = max_probe_bitrate_bps; + bitrate = std::min(bitrate, estimate_capped_bitrate); + if (bitrate > max_probe_bitrate) { + bitrate = max_probe_bitrate; probe_further = false; } ProbeClusterConfig config; - config.at_time = Timestamp::ms(now_ms); - config.target_data_rate = DataRate::bps(rtc::dchecked_cast(bitrate)); - config.target_duration = TimeDelta::ms(kMinProbeDurationMs); - config.target_probe_count = kMinProbePacketsSent; + config.at_time = now; + config.target_data_rate = bitrate; + if (network_estimate_ && + config_.network_state_estimate_probing_interval->IsFinite()) { + config.target_duration = config_.network_state_probe_duration; + } else { + config.target_duration = config_.min_probe_duration; + } + + config.target_probe_count = config_.min_probe_packets_sent; config.id = next_probe_cluster_id_; next_probe_cluster_id_++; MaybeLogProbeClusterCreated(config); pending_probes.push_back(config); } - time_last_probing_initiated_ms_ = now_ms; + time_last_probing_initiated_ = now; if (probe_further) { state_ = State::kWaitingForProbingResult; - min_bitrate_to_probe_further_bps_ = - (*(bitrates_to_probe.end() - 1)) * config_.further_probe_threshold; + // Dont expect probe results to be larger than a fraction of the actual + // probe rate. + min_bitrate_to_probe_further_ = + std::min(estimate_capped_bitrate, (*(bitrates_to_probe.end() - 1))) * + config_.further_probe_threshold; } else { state_ = State::kProbingComplete; - min_bitrate_to_probe_further_bps_ = kExponentialProbingDisabled; + min_bitrate_to_probe_further_ = DataRate::PlusInfinity(); } return pending_probes; } diff --git a/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/probe_controller.h b/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/probe_controller.h index c928927a42..8502ea6b24 100644 --- a/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/probe_controller.h +++ b/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/probe_controller.h @@ -31,7 +31,7 @@ struct ProbeControllerConfig { ~ProbeControllerConfig(); // These parameters configure the initial probes. First we send one or two - // probes of sizes p1 * start_bitrate_bps_ and p2 * start_bitrate_bps_. + // probes of sizes p1 * start_bitrate_ and p2 * start_bitrate_. // Then whenever we get a bitrate estimate of at least further_probe_threshold // times the size of the last sent probe we'll send another one of size // step_size times the new estimate. @@ -44,10 +44,48 @@ struct ProbeControllerConfig { FieldTrialParameter alr_probing_interval; FieldTrialParameter alr_probe_scale; + // Configures how often we send probes if NetworkStateEstimate is available. + FieldTrialParameter network_state_estimate_probing_interval; + // Periodically probe as long as the the ratio beteeen current estimate and + // NetworkStateEstimate is lower then this. + FieldTrialParameter + probe_if_estimate_lower_than_network_state_estimate_ratio; + FieldTrialParameter + estimate_lower_than_network_state_estimate_probing_interval; + FieldTrialParameter network_state_probe_scale; + // Overrides min_probe_duration if network_state_estimate_probing_interval + // is set and a network state estimate is known. + FieldTrialParameter network_state_probe_duration; + // Configures the probes emitted by changed to the allocated bitrate. + FieldTrialParameter probe_on_max_allocated_bitrate_change; FieldTrialOptional first_allocation_probe_scale; FieldTrialOptional second_allocation_probe_scale; FieldTrialFlag allocation_allow_further_probing; + FieldTrialParameter allocation_probe_max; + + // The minimum number probing packets used. + FieldTrialParameter min_probe_packets_sent; + // The minimum probing duration. + FieldTrialParameter min_probe_duration; + // Periodically probe when bandwidth estimate is loss limited. + FieldTrialParameter limit_probe_target_rate_to_loss_bwe; + FieldTrialParameter loss_limited_probe_scale; + // Dont send a probe if min(estimate, network state estimate) is larger than + // this fraction of the set max bitrate. + FieldTrialParameter skip_if_estimate_larger_than_fraction_of_max; + // Do not send probes if network is either overusing or underusing. + FieldTrialParameter not_probe_if_delay_increased; +}; + +// Reason that bandwidth estimate is limited. Bandwidth estimate can be limited +// by either delay based bwe, or loss based bwe when it increases/decreases the +// estimate. +enum class BandwidthLimitedCause { + kLossLimitedBweIncreasing = 0, + kLossLimitedBweDecreasing = 1, + kDelayBasedLimited = 2, + kDelayBasedLimitedDelayIncreased = 3, }; // This class controls initiation of probing to estimate initial channel @@ -58,43 +96,49 @@ class ProbeController { explicit ProbeController(const WebRtcKeyValueConfig* key_value_config); ~ProbeController(); - RTC_WARN_UNUSED_RESULT std::vector SetBitrates( - int64_t min_bitrate_bps, - int64_t start_bitrate_bps, - int64_t max_bitrate_bps, - int64_t at_time_ms); + ProbeController(const ProbeController&) = delete; + ProbeController& operator=(const ProbeController&) = delete; + + ABSL_MUST_USE_RESULT std::vector SetBitrates( + DataRate min_bitrate, + DataRate start_bitrate, + DataRate max_bitrate, + Timestamp at_time); // The total bitrate, as opposed to the max bitrate, is the sum of the // configured bitrates for all active streams. - RTC_WARN_UNUSED_RESULT std::vector - OnMaxTotalAllocatedBitrate(int64_t max_total_allocated_bitrate, - int64_t at_time_ms); + ABSL_MUST_USE_RESULT std::vector + OnMaxTotalAllocatedBitrate(DataRate max_total_allocated_bitrate, + Timestamp at_time); - RTC_WARN_UNUSED_RESULT std::vector OnNetworkAvailability( + ABSL_MUST_USE_RESULT std::vector OnNetworkAvailability( NetworkAvailability msg); - RTC_WARN_UNUSED_RESULT std::vector SetEstimatedBitrate( - int64_t bitrate_bps, - int64_t at_time_ms); + ABSL_MUST_USE_RESULT std::vector SetEstimatedBitrate( + DataRate bitrate, + BandwidthLimitedCause bandwidth_limited_cause, + Timestamp at_time); void EnablePeriodicAlrProbing(bool enable); void SetAlrStartTimeMs(absl::optional alr_start_time); void SetAlrEndedTimeMs(int64_t alr_end_time); - RTC_WARN_UNUSED_RESULT std::vector RequestProbe( - int64_t at_time_ms); + ABSL_MUST_USE_RESULT std::vector RequestProbe( + Timestamp at_time); - // Sets a new maximum probing bitrate, without generating a new probe cluster. - void SetMaxBitrate(int64_t max_bitrate_bps); + void SetNetworkStateEstimate(webrtc::NetworkStateEstimate estimate); // Resets the ProbeController to a state equivalent to as if it was just - // created EXCEPT for |enable_periodic_alr_probing_|. - void Reset(int64_t at_time_ms); - - RTC_WARN_UNUSED_RESULT std::vector Process( - int64_t at_time_ms); - + // created EXCEPT for `enable_periodic_alr_probing_`. + void Reset(Timestamp at_time); + + ABSL_MUST_USE_RESULT std::vector Process( + Timestamp at_time); + // Gets the value of field trial not_probe_if_delay_increased. + bool DontProbeIfDelayIncreased() { + return config_.not_probe_if_delay_increased; + } private: enum class State { // Initial state where no probing has been triggered yet. @@ -105,41 +149,39 @@ class ProbeController { kProbingComplete, }; - RTC_WARN_UNUSED_RESULT std::vector - InitiateExponentialProbing(int64_t at_time_ms); - RTC_WARN_UNUSED_RESULT std::vector InitiateProbing( - int64_t now_ms, - std::vector bitrates_to_probe, + ABSL_MUST_USE_RESULT std::vector + InitiateExponentialProbing(Timestamp at_time); + ABSL_MUST_USE_RESULT std::vector InitiateProbing( + Timestamp now, + std::vector bitrates_to_probe, bool probe_further); + bool TimeForAlrProbe(Timestamp at_time) const; + bool TimeForNetworkStateProbe(Timestamp at_time) const; bool network_available_; + BandwidthLimitedCause bandwidth_limited_cause_ = + BandwidthLimitedCause::kDelayBasedLimited; State state_; - int64_t min_bitrate_to_probe_further_bps_; - int64_t time_last_probing_initiated_ms_; - int64_t estimated_bitrate_bps_; - int64_t start_bitrate_bps_; - int64_t max_bitrate_bps_; - int64_t last_bwe_drop_probing_time_ms_; - absl::optional alr_start_time_ms_; - absl::optional alr_end_time_ms_; + DataRate min_bitrate_to_probe_further_ = DataRate::PlusInfinity(); + Timestamp time_last_probing_initiated_ = Timestamp::MinusInfinity(); + DataRate estimated_bitrate_ = DataRate::Zero(); + absl::optional network_estimate_; + DataRate start_bitrate_ = DataRate::Zero(); + DataRate max_bitrate_ = DataRate::PlusInfinity(); + Timestamp last_bwe_drop_probing_time_ = Timestamp::Zero(); + absl::optional alr_start_time_; + absl::optional alr_end_time_; bool enable_periodic_alr_probing_; - int64_t time_of_last_large_drop_ms_; - int64_t bitrate_before_last_large_drop_bps_; - int64_t max_total_allocated_bitrate_; + Timestamp time_of_last_large_drop_ = Timestamp::MinusInfinity(); + DataRate bitrate_before_last_large_drop_ = DataRate::Zero(); + DataRate max_total_allocated_bitrate_ = DataRate::Zero(); const bool in_rapid_recovery_experiment_; - const bool limit_probes_with_allocateable_rate_; - const bool allocation_probing_only_in_alr_; - // For WebRTC.BWE.MidCallProbing.* metric. - bool mid_call_probing_waiting_for_result_; - int64_t mid_call_probing_bitrate_bps_; - int64_t mid_call_probing_succcess_threshold_; + // RtcEventLog* event_log_; int32_t next_probe_cluster_id_ = 1; ProbeControllerConfig config_; - - RTC_DISALLOW_COPY_AND_ASSIGN(ProbeController); }; } // namespace webrtc diff --git a/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/robust_throughput_estimator.cc b/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/robust_throughput_estimator.cc new file mode 100644 index 0000000000..5bdcf1bac6 --- /dev/null +++ b/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/robust_throughput_estimator.cc @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2019 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/goog_cc/robust_throughput_estimator.h" + +#include + +#include +#include + +#include "api/units/data_rate.h" +#include "api/units/data_size.h" +#include "api/units/time_delta.h" +#include "api/units/timestamp.h" +// #include "rtc_base/checks.h" + +namespace webrtc { + +RobustThroughputEstimator::RobustThroughputEstimator( + const RobustThroughputEstimatorSettings& settings) + : settings_(settings), + latest_discarded_send_time_(Timestamp::MinusInfinity()) { + // RTC_DCHECK(settings.enabled); +} + +RobustThroughputEstimator::~RobustThroughputEstimator() {} + +bool RobustThroughputEstimator::FirstPacketOutsideWindow() { + if (window_.empty()) + return false; + if (window_.size() > settings_.max_window_packets) + return true; + TimeDelta current_window_duration = + window_.back().receive_time - window_.front().receive_time; + if (current_window_duration > settings_.max_window_duration) + return true; + if (window_.size() > settings_.window_packets && + current_window_duration > settings_.min_window_duration) { + return true; + } + return false; +} + +void RobustThroughputEstimator::IncomingPacketFeedbackVector( + const std::vector& packet_feedback_vector) { + // RTC_DCHECK(std::is_sorted(packet_feedback_vector.begin(), + // packet_feedback_vector.end(), + // PacketResult::ReceiveTimeOrder())); + for (const auto& packet : packet_feedback_vector) { + // Ignore packets without valid send or receive times. + // (This should not happen in production since lost packets are filtered + // out before passing the feedback vector to the throughput estimator. + // However, explicitly handling this case makes the estimator more robust + // and avoids a hard-to-detect bad state.) + if (packet.receive_time.IsInfinite() || + packet.sent_packet.send_time.IsInfinite()) { + continue; + } + + // Insert the new packet. + window_.push_back(packet); + window_.back().sent_packet.prior_unacked_data = + window_.back().sent_packet.prior_unacked_data * + settings_.unacked_weight; + // In most cases, receive timestamps should already be in order, but in the + // rare case where feedback packets have been reordered, we do some swaps to + // ensure that the window is sorted. + for (size_t i = window_.size() - 1; + i > 0 && window_[i].receive_time < window_[i - 1].receive_time; i--) { + std::swap(window_[i], window_[i - 1]); + } + } + + // Remove old packets. + while (FirstPacketOutsideWindow()) { + latest_discarded_send_time_ = std::max( + latest_discarded_send_time_, window_.front().sent_packet.send_time); + window_.pop_front(); + } +} + +absl::optional RobustThroughputEstimator::bitrate() const { + if (window_.empty() || window_.size() < settings_.required_packets) + return absl::nullopt; + + TimeDelta largest_recv_gap(TimeDelta::Zero()); + TimeDelta second_largest_recv_gap(TimeDelta::Zero()); + for (size_t i = 1; i < window_.size(); i++) { + // Find receive time gaps. + TimeDelta gap = window_[i].receive_time - window_[i - 1].receive_time; + if (gap > largest_recv_gap) { + second_largest_recv_gap = largest_recv_gap; + largest_recv_gap = gap; + } else if (gap > second_largest_recv_gap) { + second_largest_recv_gap = gap; + } + } + + Timestamp first_send_time = Timestamp::PlusInfinity(); + Timestamp last_send_time = Timestamp::MinusInfinity(); + Timestamp first_recv_time = Timestamp::PlusInfinity(); + Timestamp last_recv_time = Timestamp::MinusInfinity(); + DataSize recv_size = DataSize::Bytes<0>(); + DataSize send_size = DataSize::Bytes<0>(); + DataSize first_recv_size = DataSize::Bytes<0>(); + DataSize last_send_size = DataSize::Bytes<0>(); + size_t num_sent_packets_in_window = 0; + for (const auto& packet : window_) { + if (packet.receive_time < first_recv_time) { + first_recv_time = packet.receive_time; + first_recv_size = + packet.sent_packet.size + packet.sent_packet.prior_unacked_data; + } + last_recv_time = std::max(last_recv_time, packet.receive_time); + recv_size += packet.sent_packet.size; + recv_size += packet.sent_packet.prior_unacked_data; + + if (packet.sent_packet.send_time < latest_discarded_send_time_) { + // If we have dropped packets from the window that were sent after + // this packet, then this packet was reordered. Ignore it from + // the send rate computation (since the send time may be very far + // in the past, leading to underestimation of the send rate.) + // However, ignoring packets creates a risk that we end up without + // any packets left to compute a send rate. + continue; + } + if (packet.sent_packet.send_time > last_send_time) { + last_send_time = packet.sent_packet.send_time; + last_send_size = + packet.sent_packet.size + packet.sent_packet.prior_unacked_data; + } + first_send_time = std::min(first_send_time, packet.sent_packet.send_time); + + send_size += packet.sent_packet.size; + send_size += packet.sent_packet.prior_unacked_data; + ++num_sent_packets_in_window; + } + + // Suppose a packet of size S is sent every T milliseconds. + // A window of N packets would contain N*S bytes, but the time difference + // between the first and the last packet would only be (N-1)*T. Thus, we + // need to remove the size of one packet to get the correct rate of S/T. + // Which packet to remove (if the packets have varying sizes), + // depends on the network model. + // Suppose that 2 packets with sizes s1 and s2, are received at times t1 + // and t2, respectively. If the packets were transmitted back to back over + // a bottleneck with rate capacity r, then we'd expect t2 = t1 + r * s2. + // Thus, r = (t2-t1) / s2, so the size of the first packet doesn't affect + // the difference between t1 and t2. + // Analoguously, if the first packet is sent at time t1 and the sender + // paces the packets at rate r, then the second packet can be sent at time + // t2 = t1 + r * s1. Thus, the send rate estimate r = (t2-t1) / s1 doesn't + // depend on the size of the last packet. + recv_size -= first_recv_size; + send_size -= last_send_size; + + // Remove the largest gap by replacing it by the second largest gap. + // This is to ensure that spurious "delay spikes" (i.e. when the + // network stops transmitting packets for a short period, followed + // by a burst of delayed packets), don't cause the estimate to drop. + // This could cause an overestimation, which we guard against by + // never returning an estimate above the send rate. + // RTC_DCHECK(first_recv_time.IsFinite()); + // RTC_DCHECK(last_recv_time.IsFinite()); + TimeDelta recv_duration = (last_recv_time - first_recv_time) - + largest_recv_gap + second_largest_recv_gap; + recv_duration = std::max(recv_duration, TimeDelta::Millis<1>()); + + if (num_sent_packets_in_window < settings_.required_packets) { + // Too few send times to calculate a reliable send rate. + return recv_size / recv_duration; + } + + // RTC_DCHECK(first_send_time.IsFinite()); + // RTC_DCHECK(last_send_time.IsFinite()); + TimeDelta send_duration = last_send_time - first_send_time; + send_duration = std::max(send_duration, TimeDelta::Millis<1>()); + + return std::min(send_size / send_duration, recv_size / recv_duration); +} + +} // namespace webrtc diff --git a/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/robust_throughput_estimator.h b/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/robust_throughput_estimator.h new file mode 100644 index 0000000000..9d89856496 --- /dev/null +++ b/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/robust_throughput_estimator.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2019 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_GOOG_CC_ROBUST_THROUGHPUT_ESTIMATOR_H_ +#define MODULES_CONGESTION_CONTROLLER_GOOG_CC_ROBUST_THROUGHPUT_ESTIMATOR_H_ + +#include +#include + +#include "absl/types/optional.h" +#include "api/transport/network_types.h" +#include "api/units/data_rate.h" +#include "api/units/timestamp.h" +#include "modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator_interface.h" + +namespace webrtc { + +class RobustThroughputEstimator : public AcknowledgedBitrateEstimatorInterface { + public: + explicit RobustThroughputEstimator( + const RobustThroughputEstimatorSettings& settings); + ~RobustThroughputEstimator() override; + + void IncomingPacketFeedbackVector( + const std::vector& packet_feedback_vector) override; + + absl::optional bitrate() const override; + + absl::optional PeekRate() const override { return bitrate(); } + void SetAlr(bool /*in_alr*/) override {} + void SetAlrEndedTime(Timestamp /*alr_ended_time*/) override {} + + private: + bool FirstPacketOutsideWindow(); + + const RobustThroughputEstimatorSettings settings_; + std::deque window_; + Timestamp latest_discarded_send_time_ = Timestamp::MinusInfinity(); +}; + +} // namespace webrtc + +#endif // MODULES_CONGESTION_CONTROLLER_GOOG_CC_ROBUST_THROUGHPUT_ESTIMATOR_H_ diff --git a/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/trendline_estimator.cc b/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/trendline_estimator.cc index 885c6776cb..c23ed7c483 100644 --- a/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/trendline_estimator.cc +++ b/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/trendline_estimator.cc @@ -12,15 +12,16 @@ // #define MS_LOG_DEV_LEVEL 3 #include "modules/congestion_controller/goog_cc/trendline_estimator.h" - #include "modules/remote_bitrate_estimator/include/bwe_defines.h" #include "rtc_base/numerics/safe_minmax.h" +#include "DepLibUV.hpp" #include "Logger.hpp" #include -#include #include +#include +#include #include namespace webrtc { @@ -28,14 +29,14 @@ namespace webrtc { namespace { // Parameters for linear least squares fit of regression line to noisy data. -constexpr size_t kDefaultTrendlineWindowSize = 20; -constexpr double kDefaultTrendlineSmoothingCoeff = 0.6; +constexpr double kDefaultTrendlineSmoothingCoeff = 0.9; constexpr double kDefaultTrendlineThresholdGain = 4.0; +constexpr double kDefaultRSquaredUpperBound = 0.20; +constexpr double kDefaultRSquaredLowerBound = 0.02; const char kBweWindowSizeInPacketsExperiment[] = "WebRTC-BweWindowSizeInPackets"; -size_t ReadTrendlineFilterWindowSize( - const WebRtcKeyValueConfig* key_value_config) { +size_t ReadTrendlineFilterWindowSize(const WebRtcKeyValueConfig* key_value_config) { std::string experiment_string = key_value_config->Lookup(kBweWindowSizeInPacketsExperiment); size_t window_size; @@ -49,134 +50,245 @@ size_t ReadTrendlineFilterWindowSize( MS_WARN_DEV( "failed to parse parameters for BweWindowSizeInPackets" " experiment from field trial string, using default"); - return kDefaultTrendlineWindowSize; + return TrendlineEstimatorSettings::kDefaultTrendlineWindowSize; } -absl::optional LinearFitSlope( - const std::deque>& points) { - //RTC_DCHECK(points.size() >= 2); +absl::optional LinearFitSlope( + const std::deque& packets) { + // RTC_DCHECK(packets.size() >= 2); // Compute the "center of mass". double sum_x = 0; double sum_y = 0; - for (const auto& point : points) { - sum_x += point.first; - sum_y += point.second; + for (const auto& packet : packets) { + sum_x += packet.arrival_time_ms; + sum_y += packet.smoothed_delay_ms; } - double x_avg = sum_x / points.size(); - double y_avg = sum_y / points.size(); + double x_avg = sum_x / packets.size(); + double y_avg = sum_y / packets.size(); // Compute the slope k = \sum (x_i-x_avg)(y_i-y_avg) / \sum (x_i-x_avg)^2 double numerator = 0; double denominator = 0; - for (const auto& point : points) { - numerator += (point.first - x_avg) * (point.second - y_avg); - denominator += (point.first - x_avg) * (point.first - x_avg); + for (const auto& packet : packets) { + double x = packet.arrival_time_ms; + double y = packet.smoothed_delay_ms; + numerator += (x - x_avg) * (y - y_avg); + denominator += (x - x_avg) * (x - x_avg); } if (denominator == 0) return absl::nullopt; - return numerator / denominator; + double b1 = numerator / denominator; + double b0 = y_avg - (b1 * x_avg); + + // Compute the R squared + double r_numerator = 0; + double r_denominator = 0; + for (const auto& packet : packets) { + double x = packet.arrival_time_ms; + double y = packet.smoothed_delay_ms; + r_numerator += pow(((b0 + (b1 * x)) - y_avg), 2); + r_denominator += pow((y - y_avg), 2); + } + + double r_squared = r_numerator / r_denominator; + + return DelayIncreaseDetectorInterface::RegressionResult(b1, r_squared); +} + +absl::optional ComputeSlopeCap( + const std::deque& packets, + const TrendlineEstimatorSettings& settings) { + // RTC_DCHECK(1 <= settings.beginning_packets && + // settings.beginning_packets < packets.size()); + // RTC_DCHECK(1 <= settings.end_packets && + // settings.end_packets < packets.size()); + // RTC_DCHECK(settings.beginning_packets + settings.end_packets <= + // packets.size()); + TrendlineEstimator::PacketTiming early = packets[0]; + for (size_t i = 1; i < settings.beginning_packets; ++i) { + if (packets[i].raw_delay_ms < early.raw_delay_ms) + early = packets[i]; + } + size_t late_start = packets.size() - settings.end_packets; + TrendlineEstimator::PacketTiming late = packets[late_start]; + for (size_t i = late_start + 1; i < packets.size(); ++i) { + if (packets[i].raw_delay_ms < late.raw_delay_ms) + late = packets[i]; + } + if (late.arrival_time_ms - early.arrival_time_ms < 1) { + return absl::nullopt; + } + return (late.raw_delay_ms - early.raw_delay_ms) / + (late.arrival_time_ms - early.arrival_time_ms) + + settings.cap_uncertainty; +} + +double getAverage(std::deque const& hist) { + if (hist.empty()) { + return 0; + } + return std::accumulate(hist.begin(), hist.end(), 0.0) / hist.size(); } constexpr double kMaxAdaptOffsetMs = 15.0; -constexpr double kOverUsingTimeThreshold = 30; +constexpr double kOverUsingTimeThreshold = 10; constexpr int kMinNumDeltas = 60; -constexpr int kDeltaCounterMax = 1000; +constexpr int kDeltaCounterMax = 300; } // namespace -TrendlineEstimator::TrendlineEstimator( - const WebRtcKeyValueConfig* key_value_config, - NetworkStatePredictor* network_state_predictor) - : TrendlineEstimator( - key_value_config->Lookup(kBweWindowSizeInPacketsExperiment) - .find("Enabled") == 0 - ? ReadTrendlineFilterWindowSize(key_value_config) - : kDefaultTrendlineWindowSize, - kDefaultTrendlineSmoothingCoeff, - kDefaultTrendlineThresholdGain, - network_state_predictor) {} +constexpr char TrendlineEstimatorSettings::kKey[]; + +TrendlineEstimatorSettings::TrendlineEstimatorSettings( + const WebRtcKeyValueConfig* key_value_config) { + if (key_value_config->Lookup(kBweWindowSizeInPacketsExperiment).find("Enabled") == 0) { + window_size = ReadTrendlineFilterWindowSize(key_value_config); + } + Parser()->Parse(key_value_config->Lookup(TrendlineEstimatorSettings::kKey)); + if (window_size < 10 || 200 < window_size) { + MS_WARN_TAG(bwe, "window size must be between 10 and 200 packets"); + window_size = kDefaultTrendlineWindowSize; + } + MS_DEBUG_DEV( + "using Trendline filter for delay change estimation with window size: %zu", + window_size); + if (enable_cap) { + if (beginning_packets < 1 || end_packets < 1 || + beginning_packets > window_size || end_packets > window_size) { + MS_WARN_TAG(bwe, "size of beginning and end must be between 1 and %d", window_size); + enable_cap = false; + beginning_packets = end_packets = 0; + cap_uncertainty = 0.0; + } + if (beginning_packets + end_packets > window_size) { + MS_WARN_TAG(bwe, "size of beginning plus end can't exceed the window size"); + enable_cap = false; + beginning_packets = end_packets = 0; + cap_uncertainty = 0.0; + } + if (cap_uncertainty < 0.0 || 0.025 < cap_uncertainty) { + MS_WARN_TAG(bwe, "cap uncertainty must be between 0 and 0.025"); + cap_uncertainty = 0.0; + } + } +} + +std::unique_ptr TrendlineEstimatorSettings::Parser() { + return StructParametersParser::Create("sort", &enable_sort, // + "cap", &enable_cap, // + "beginning_packets", + &beginning_packets, // + "end_packets", &end_packets, // + "cap_uncertainty", &cap_uncertainty, // + "window_size", &window_size); +} TrendlineEstimator::TrendlineEstimator( - size_t window_size, - double smoothing_coef, - double threshold_gain, + const WebRtcKeyValueConfig* key_value_config, NetworkStatePredictor* network_state_predictor) - : window_size_(window_size), - smoothing_coef_(smoothing_coef), - threshold_gain_(threshold_gain), + : settings_(key_value_config), + smoothing_coef_(kDefaultTrendlineSmoothingCoeff), + threshold_gain_(kDefaultTrendlineThresholdGain), num_of_deltas_(0), first_arrival_time_ms_(-1), accumulated_delay_(0), smoothed_delay_(0), delay_hist_(), + r_squared_hist_(), k_up_(0.0087), k_down_(0.039), overusing_time_threshold_(kOverUsingTimeThreshold), threshold_(12.5), prev_modified_trend_(NAN), last_update_ms_(-1), - prev_trend_(0.0), + prev_trend_(0.0, 0.0), time_over_using_(-1), overuse_counter_(0), + r_squared_overuse_counter_(0), hypothesis_(BandwidthUsage::kBwNormal), hypothesis_predicted_(BandwidthUsage::kBwNormal), network_state_predictor_(network_state_predictor) { - MS_DEBUG_DEV( - "using Trendline filter for delay change estimation with window size: %zu", - window_size_); } TrendlineEstimator::~TrendlineEstimator() {} +void TrendlineEstimator::UpdateTrendline(double recv_delta_ms, + double send_delta_ms, + int64_t send_time_ms, + int64_t arrival_time_ms, + size_t packet_size) { + const double delta_ms = recv_delta_ms - send_delta_ms; + ++num_of_deltas_; + num_of_deltas_ = std::min(num_of_deltas_, kDeltaCounterMax); + if (first_arrival_time_ms_ == -1) + first_arrival_time_ms_ = arrival_time_ms; + + // Exponential backoff filter. + accumulated_delay_ += delta_ms; + // BWE_TEST_LOGGING_PLOT(1, "accumulated_delay_ms", arrival_time_ms, + // accumulated_delay_); + smoothed_delay_ = smoothing_coef_ * smoothed_delay_ + + (1 - smoothing_coef_) * accumulated_delay_; + // BWE_TEST_LOGGING_PLOT(1, "smoothed_delay_ms", arrival_time_ms, + // smoothed_delay_); + + // Maintain packet window + delay_hist_.emplace_back( + static_cast(arrival_time_ms - first_arrival_time_ms_), + smoothed_delay_, accumulated_delay_); + if (settings_.enable_sort) { + for (size_t i = delay_hist_.size() - 1; + i > 0 && + delay_hist_[i].arrival_time_ms < delay_hist_[i - 1].arrival_time_ms; + --i) { + std::swap(delay_hist_[i], delay_hist_[i - 1]); + } + } + if (delay_hist_.size() > settings_.window_size) + delay_hist_.pop_front(); + + // Simple linear regression. + auto trend = prev_trend_; + DelayIncreaseDetectorInterface::RegressionResult result; + double avg_r_squared {0.0}; + if (delay_hist_.size() == settings_.window_size) { + // Update trend_ if it is possible to fit a line to the data. The delay + // trend can be seen as an estimate of (send_rate - capacity)/capacity. + // 0 < trend < 1 -> the delay increases, queues are filling up + // trend == 0 -> the delay does not change + // trend < 0 -> the delay decreases, queues are being emptied + result = LinearFitSlope(delay_hist_).value_or(trend); + //if (result.slope > 0) { + r_squared_hist_.emplace_back(result.r_squared); + if (r_squared_hist_.size() > settings_.window_size) + r_squared_hist_.pop_front(); + //} + avg_r_squared = getAverage(r_squared_hist_); + trend.r_squared = avg_r_squared; + result.r_squared = avg_r_squared; + if (settings_.enable_cap) { + absl::optional cap = ComputeSlopeCap(delay_hist_, settings_); + // We only use the cap to filter out overuse detections, not + // to detect additional underuses. + if (trend.slope >= 0 && cap.has_value() && trend.slope > cap.value()) { + trend.slope = cap.value(); + } + } + } + + + Detect(result, send_delta_ms, arrival_time_ms, avg_r_squared); +} + void TrendlineEstimator::Update(double recv_delta_ms, double send_delta_ms, int64_t send_time_ms, int64_t arrival_time_ms, + size_t packet_size, bool calculated_deltas) { if (calculated_deltas) { - const double delta_ms = recv_delta_ms - send_delta_ms; - ++num_of_deltas_; - num_of_deltas_ = std::min(num_of_deltas_, kDeltaCounterMax); - if (first_arrival_time_ms_ == -1) - first_arrival_time_ms_ = arrival_time_ms; - - // Exponential backoff filter. - accumulated_delay_ += delta_ms; - // BWE_TEST_LOGGING_PLOT(1, "accumulated_delay_ms", arrival_time_ms, - // accumulated_delay_); - // smoothed_delay_ = smoothing_coef_ * smoothed_delay_ + - // (1 - smoothing_coef_) * accumulated_delay_; - // MS_NOTE: Apply WEMA to the current delta_ms. Don't consider the - // accumulated delay. Tests show it behaves more robustly upon delta peaks. - smoothed_delay_ = smoothing_coef_ * delta_ms + - (1 - smoothing_coef_) * smoothed_delay_; - // BWE_TEST_LOGGING_PLOT(1, "smoothed_delay_ms", arrival_time_ms, - // smoothed_delay_); - - // Simple linear regression. - delay_hist_.push_back(std::make_pair( - static_cast(arrival_time_ms - first_arrival_time_ms_), - smoothed_delay_)); - if (delay_hist_.size() > window_size_) - delay_hist_.pop_front(); - double trend = prev_trend_; - if (delay_hist_.size() == window_size_) { - // Update trend_ if it is possible to fit a line to the data. The delay - // trend can be seen as an estimate of (send_rate - capacity)/capacity. - // 0 < trend < 1 -> the delay increases, queues are filling up - // trend == 0 -> the delay does not change - // trend < 0 -> the delay decreases, queues are being emptied - trend = LinearFitSlope(delay_hist_).value_or(trend); - } - - // BWE_TEST_LOGGING_PLOT(1, "trendline_slope", arrival_time_ms, trend); - - MS_DEBUG_DEV("trend:%f, send_delta_ms:%f, recv_delta_ms:%f, delta_ms:%f arrival_time_ms:%" PRIi64 ", accumulated_delay_:%f, smoothed_delay_:%f", trend, send_delta_ms, recv_delta_ms, delta_ms, arrival_time_ms, accumulated_delay_, smoothed_delay_); - Detect(trend, send_delta_ms, arrival_time_ms); - } - else { - MS_DEBUG_DEV("no calculated deltas"); + UpdateTrendline(recv_delta_ms, send_delta_ms, send_time_ms, arrival_time_ms, + packet_size); } - if (network_state_predictor_) { hypothesis_predicted_ = network_state_predictor_->Update( send_time_ms, arrival_time_ms, hypothesis_); @@ -187,16 +299,48 @@ BandwidthUsage TrendlineEstimator::State() const { return network_state_predictor_ ? hypothesis_predicted_ : hypothesis_; } -void TrendlineEstimator::Detect(double trend, double ts_delta, int64_t now_ms) { +void TrendlineEstimator::Detect(DelayIncreaseDetectorInterface::RegressionResult trend, double ts_delta, int64_t now_ms, double avg_r_squared) { if (num_of_deltas_ < 2) { hypothesis_ = BandwidthUsage::kBwNormal; return; } + + BandwidthUsage prev_hypothesis = hypothesis_; + const double modified_trend = - std::min(num_of_deltas_, kMinNumDeltas) * trend * threshold_gain_; + std::min(num_of_deltas_, kMinNumDeltas) * trend.slope * threshold_gain_; prev_modified_trend_ = modified_trend; // BWE_TEST_LOGGING_PLOT(1, "T", now_ms, modified_trend); // BWE_TEST_LOGGING_PLOT(1, "threshold", now_ms, threshold_); + /*for (auto it = delay_hist_.crbegin(); it != delay_hist_.crend(); ++it) { + MS_DEBUG_DEV("arrival_time_ms - first_arrival_time_ms_:%f, smoothed_delay_:%f, raw_delay_:%f", it->arrival_time_ms, it->smoothed_delay_ms, it->raw_delay_ms); + }*/ + + // MS_NOTE: In case of positive slope we want to limit BW increase or even decrease + // in case we see that we have many outliers. + if (trend.slope > 0.0 && avg_r_squared > 0 && avg_r_squared < kDefaultRSquaredUpperBound) { + if (avg_r_squared < kDefaultRSquaredLowerBound) { + r_squared_overuse_counter_++; + if (r_squared_overuse_counter_ > 3) { + hypothesis_ = BandwidthUsage::kBwOverusing; + MS_DEBUG_DEV("slope, r_squared, avg_r_squared [%f, %f, %f]", trend.slope, trend.r_squared, avg_r_squared); + MS_DEBUG_DEV("OverUsing!"); + r_squared_overuse_counter_ = 0; + } + } else { + hypothesis_ = BandwidthUsage::kBwUnderusing; + MS_DEBUG_DEV("slope, r_squared, avg_r_squared [%f, %f, %f]", trend.slope, trend.r_squared, avg_r_squared); + MS_DEBUG_DEV("HOLD"); + r_squared_overuse_counter_ = 0; + } + + prev_trend_ = trend; + UpdateThreshold(modified_trend, now_ms); + + return; + } + + if (modified_trend > threshold_) { if (time_over_using_ == -1) { // Initialize the timer. Assume that we've been @@ -208,31 +352,27 @@ void TrendlineEstimator::Detect(double trend, double ts_delta, int64_t now_ms) { time_over_using_ += ts_delta; } overuse_counter_++; - if (time_over_using_ > overusing_time_threshold_ && overuse_counter_ > 1) { - if (trend >= prev_trend_) { + if (time_over_using_ > overusing_time_threshold_ && overuse_counter_ > 3) { + if (trend.slope >= prev_trend_.slope) { time_over_using_ = 0; overuse_counter_ = 0; - MS_DEBUG_DEV("hypothesis_: BandwidthUsage::kBwOverusing"); - -#if MS_LOG_DEV_LEVEL == 3 - for (auto& kv : delay_hist_) { - MS_DEBUG_DEV("arrival_time_ms - first_arrival_time_ms_:%f, smoothed_delay_:%f", kv.first, kv.second); - } -#endif - - hypothesis_ = BandwidthUsage::kBwOverusing; + hypothesis_ = BandwidthUsage::kBwOverusing; + if (hypothesis_ != prev_hypothesis) + MS_DEBUG_DEV("hypothesis_: BandwidthUsage::kBwOverusing"); } } } else if (modified_trend < -threshold_) { time_over_using_ = -1; overuse_counter_ = 0; hypothesis_ = BandwidthUsage::kBwUnderusing; - MS_DEBUG_DEV("---- BandwidthUsage::kBwUnderusing ---"); + if (hypothesis_ != prev_hypothesis) + MS_DEBUG_DEV("---- BandwidthUsage::kBwUnderusing ---"); } else { time_over_using_ = -1; overuse_counter_ = 0; - MS_DEBUG_DEV("---- BandwidthUsage::kBwNormal ---"); hypothesis_ = BandwidthUsage::kBwNormal; + if (hypothesis_ != prev_hypothesis) + MS_DEBUG_DEV("---- BandwidthUsage::kBwNormal ---"); } prev_trend_ = trend; UpdateThreshold(modified_trend, now_ms); diff --git a/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/trendline_estimator.h b/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/trendline_estimator.h index f4c23d706d..e1a501ebb5 100644 --- a/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/trendline_estimator.h +++ b/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/trendline_estimator.h @@ -15,6 +15,7 @@ #include "modules/congestion_controller/goog_cc/delay_increase_detector_interface.h" #include "modules/remote_bitrate_estimator/include/bwe_defines.h" #include "rtc_base/constructor_magic.h" +#include "rtc_base/experiments/struct_parameters_parser.h" #include #include @@ -23,6 +24,30 @@ namespace webrtc { +struct TrendlineEstimatorSettings { + static constexpr char kKey[] = "WebRTC-Bwe-TrendlineEstimatorSettings"; + static constexpr unsigned kDefaultTrendlineWindowSize = 10; + + TrendlineEstimatorSettings() = delete; + explicit TrendlineEstimatorSettings(const WebRtcKeyValueConfig* key_value_config); + + // Sort the packets in the window. Should be redundant, + // but then almost no cost. + bool enable_sort = false; + + // Cap the trendline slope based on the minimum delay seen + // in the beginning_packets and end_packets respectively. + bool enable_cap = false; + unsigned beginning_packets = 7; + unsigned end_packets = 7; + double cap_uncertainty = 0.0; + + // Size (in packets) of the window. + unsigned window_size = kDefaultTrendlineWindowSize; + + std::unique_ptr Parser(); +}; + class TrendlineEstimator : public DelayIncreaseDetectorInterface { public: TrendlineEstimator(const WebRtcKeyValueConfig* key_value_config, @@ -41,29 +66,55 @@ class TrendlineEstimator : public DelayIncreaseDetectorInterface { ~TrendlineEstimator() override; + TrendlineEstimator(const TrendlineEstimator&) = delete; + TrendlineEstimator& operator=(const TrendlineEstimator&) = delete; + // Update the estimator with a new sample. The deltas should represent deltas // between timestamp groups as defined by the InterArrival class. void Update(double recv_delta_ms, double send_delta_ms, int64_t send_time_ms, int64_t arrival_time_ms, + size_t packet_size, bool calculated_deltas) override; + void UpdateTrendline(double recv_delta_ms, + double send_delta_ms, + int64_t send_time_ms, + int64_t arrival_time_ms, + size_t packet_size); + BandwidthUsage State() const override; - protected: - // Used in unit tests. - double modified_trend() const { return prev_trend_ * threshold_gain_; } + struct PacketTiming { + PacketTiming(double arrival_time_ms, + double smoothed_delay_ms, + double raw_delay_ms) + : arrival_time_ms(arrival_time_ms), + smoothed_delay_ms(smoothed_delay_ms), + raw_delay_ms(raw_delay_ms) {} + double arrival_time_ms; + double smoothed_delay_ms; + double raw_delay_ms; + }; + DelayIncreaseDetectorInterface::RegressionResult GetTrend() override + { + return prev_trend_; + } + + double GetThreshold() override + { + return threshold_; + } private: friend class GoogCcStatePrinter; - - void Detect(double trend, double ts_delta, int64_t now_ms); + void Detect(RegressionResult trend, double ts_delta, int64_t now_ms, double avg_r_squared); void UpdateThreshold(double modified_offset, int64_t now_ms); // Parameters. - const size_t window_size_; + TrendlineEstimatorSettings settings_; const double smoothing_coef_; const double threshold_gain_; // Used by the existing threshold. @@ -74,7 +125,9 @@ class TrendlineEstimator : public DelayIncreaseDetectorInterface { double accumulated_delay_; double smoothed_delay_; // Linear least squares regression. - std::deque> delay_hist_; + std::deque delay_hist_; + // + std::deque r_squared_hist_; const double k_up_; const double k_down_; @@ -82,14 +135,13 @@ class TrendlineEstimator : public DelayIncreaseDetectorInterface { double threshold_; double prev_modified_trend_; int64_t last_update_ms_; - double prev_trend_; + DelayIncreaseDetectorInterface::RegressionResult prev_trend_; double time_over_using_; int overuse_counter_; + int r_squared_overuse_counter_; BandwidthUsage hypothesis_; BandwidthUsage hypothesis_predicted_; NetworkStatePredictor* network_state_predictor_; - - RTC_DISALLOW_COPY_AND_ASSIGN(TrendlineEstimator); }; } // namespace webrtc diff --git a/worker/deps/libwebrtc/libwebrtc/modules/remote_bitrate_estimator/aimd_rate_control.cc b/worker/deps/libwebrtc/libwebrtc/modules/remote_bitrate_estimator/aimd_rate_control.cc index 3bc3253376..a3bd35f487 100644 --- a/worker/deps/libwebrtc/libwebrtc/modules/remote_bitrate_estimator/aimd_rate_control.cc +++ b/worker/deps/libwebrtc/libwebrtc/modules/remote_bitrate_estimator/aimd_rate_control.cc @@ -32,7 +32,7 @@ namespace webrtc { namespace { constexpr TimeDelta kDefaultRtt = TimeDelta::Millis<200>(); -constexpr double kDefaultBackoffFactor = 0.85; +constexpr double kDefaultBackoffFactor = 0.95; constexpr char kBweBackOffFactorExperiment[] = "WebRTC-BweBackOffFactor"; @@ -41,6 +41,10 @@ bool IsEnabled(const WebRtcKeyValueConfig& field_trials, return field_trials.Lookup(key).find("Enabled") == 0; } +bool IsNotDisabled(const WebRtcKeyValueConfig& field_trials, absl::string_view key) { + return field_trials.Lookup(key).find("Disabled") != 1; +} + double ReadBackoffFactor(const WebRtcKeyValueConfig& key_value_config) { std::string experiment_string = key_value_config.Lookup(kBweBackOffFactorExperiment); @@ -74,7 +78,7 @@ AimdRateControl::AimdRateControl(const WebRtcKeyValueConfig* key_value_config, current_bitrate_(max_configured_bitrate_), latest_estimated_throughput_(current_bitrate_), link_capacity_(), - rate_control_state_(kRcHold), + rate_control_state_(RateControlState::kRcHold), time_last_bitrate_change_(Timestamp::MinusInfinity()), time_last_bitrate_decrease_(Timestamp::MinusInfinity()), time_first_throughput_estimate_(Timestamp::MinusInfinity()), @@ -89,28 +93,25 @@ AimdRateControl::AimdRateControl(const WebRtcKeyValueConfig* key_value_config, no_bitrate_increase_in_alr_( IsEnabled(*key_value_config, "WebRTC-DontIncreaseDelayBasedBweInAlr")), - smoothing_experiment_(false), estimate_bounded_backoff_( - IsEnabled(*key_value_config, "WebRTC-Bwe-EstimateBoundedBackoff")), - estimate_bounded_increase_( - IsEnabled(*key_value_config, "WebRTC-Bwe-EstimateBoundedIncrease")), + IsNotDisabled(*key_value_config, + "WebRTC-Bwe-EstimateBoundedBackoff")), initial_backoff_interval_("initial_backoff_interval"), - low_throughput_threshold_("low_throughput", DataRate::Zero()), - capacity_deviation_ratio_threshold_("cap_thr", 0.2), - capacity_limit_deviation_factor_("cap_lim", 1) { + link_capacity_fix_("link_capacity_fix") { + ParseFieldTrial( + {&disable_estimate_bounded_increase_, &estimate_bounded_increase_ratio_, + &ignore_throughput_limit_if_network_estimate_, + &ignore_network_estimate_decrease_, &increase_to_network_estimate_}, + key_value_config->Lookup("WebRTC-Bwe-EstimateBoundedIncrease")); // E.g - // WebRTC-BweAimdRateControlConfig/initial_backoff_interval:100ms, - // low_throughput:50kbps/ - ParseFieldTrial({&initial_backoff_interval_, &low_throughput_threshold_}, + // WebRTC-BweAimdRateControlConfig/initial_backoff_interval:100ms/ + ParseFieldTrial({&initial_backoff_interval_, &link_capacity_fix_}, key_value_config->Lookup("WebRTC-BweAimdRateControlConfig")); if (initial_backoff_interval_) { MS_DEBUG_TAG(bwe, "Using aimd rate control with initial back-off interval: %s", ToString(*initial_backoff_interval_).c_str()); } MS_DEBUG_TAG(bwe, "Using aimd rate control with back off factor: %f ", beta_); - ParseFieldTrial( - {&capacity_deviation_ratio_threshold_, &capacity_limit_deviation_factor_}, - key_value_config->Lookup("WebRTC-Bwe-AimdRateControl-NetworkState")); } AimdRateControl::~AimdRateControl() {} @@ -121,6 +122,10 @@ void AimdRateControl::SetStartBitrate(DataRate start_bitrate) { bitrate_is_initialized_ = true; } +RateControlState AimdRateControl::GetRateControlState() const { + return rate_control_state_; +}; + void AimdRateControl::SetMinBitrate(DataRate min_bitrate) { MS_DEBUG_DEV("[min_bitrate:%" PRIi64 "]", min_bitrate.bps()); @@ -203,7 +208,7 @@ DataRate AimdRateControl::Update(const RateControlInput* input, } } - current_bitrate_ = ChangeBitrate(current_bitrate_, *input, at_time); + ChangeBitrate(*input, at_time); return current_bitrate_; } @@ -214,7 +219,7 @@ void AimdRateControl::SetInApplicationLimitedRegion(bool in_alr) { void AimdRateControl::SetEstimate(DataRate bitrate, Timestamp at_time) { bitrate_is_initialized_ = true; DataRate prev_bitrate = current_bitrate_; - current_bitrate_ = ClampBitrate(bitrate, bitrate); + current_bitrate_ = ClampBitrate(bitrate); time_last_bitrate_change_ = at_time; if (current_bitrate_ < prev_bitrate) { time_last_bitrate_decrease_ = at_time; @@ -245,23 +250,22 @@ double AimdRateControl::GetNearMaxIncreaseRateBpsPerSecond() const { } TimeDelta AimdRateControl::GetExpectedBandwidthPeriod() const { - const TimeDelta kMinPeriod = - smoothing_experiment_ ? TimeDelta::ms(500) : TimeDelta::seconds(2); + const TimeDelta kMinPeriod = TimeDelta::seconds(2); const TimeDelta kDefaultPeriod = TimeDelta::seconds(3); const TimeDelta kMaxPeriod = TimeDelta::seconds(50); double increase_rate_bps_per_second = GetNearMaxIncreaseRateBpsPerSecond(); if (!last_decrease_) - return smoothing_experiment_ ? kMinPeriod : kDefaultPeriod; + return kDefaultPeriod; double time_to_recover_decrease_seconds = last_decrease_->bps() / increase_rate_bps_per_second; TimeDelta period = TimeDelta::seconds(time_to_recover_decrease_seconds); return period.Clamped(kMinPeriod, kMaxPeriod); } -DataRate AimdRateControl::ChangeBitrate(DataRate new_bitrate, - const RateControlInput& input, - Timestamp at_time) { +void AimdRateControl::ChangeBitrate(const RateControlInput& input, + Timestamp at_time) { + absl::optional new_bitrate; DataRate estimated_throughput = input.estimated_throughput.value_or(latest_estimated_throughput_); if (input.estimated_throughput) @@ -272,82 +276,90 @@ DataRate AimdRateControl::ChangeBitrate(DataRate new_bitrate, // we will end up with a valid estimate. if (!bitrate_is_initialized_ && input.bw_state != BandwidthUsage::kBwOverusing) - return current_bitrate_; + return; ChangeState(input, at_time); - +/* MS_DEBUG_DEV("[estimated_throughput %lld, link_capacity_: %lld]", + estimated_throughput.bps(), + link_capacity_.has_estimate() ? link_capacity_.estimate().bps() : -1);*/ switch (rate_control_state_) { - case kRcHold: + case RateControlState::kRcHold: break; - case kRcIncrease: + case RateControlState::kRcIncrease: { if (estimated_throughput > link_capacity_.UpperBound()) link_capacity_.Reset(); - // Do not increase the delay based estimate in alr since the estimator - // will not be able to get transport feedback necessary to detect if - // the new estimate is correct. - if (!(send_side_ && in_alr_ && no_bitrate_increase_in_alr_)) { - if (link_capacity_.has_estimate()) { + // We limit the new bitrate based on the troughput to avoid unlimited + // bitrate increases. We allow a bit more lag at very low rates to not too + // easily get stuck if the encoder produces uneven outputs. + DataRate increase_limit = + 1.5 * estimated_throughput + DataRate::kbps(10); + if (ignore_throughput_limit_if_network_estimate_ && network_estimate_ && + network_estimate_->link_capacity_upper.IsFinite()) { + // If we have a Network estimate, we do allow the estimate to increase. + increase_limit = network_estimate_->link_capacity_upper * + estimate_bounded_increase_ratio_.Get(); + } else if (send_side_ && in_alr_ && no_bitrate_increase_in_alr_) { + // Do not increase the delay based estimate in alr since the estimator + // will not be able to get transport feedback necessary to detect if + // the new estimate is correct. + // If we have previously increased above the limit (for instance due to + // probing), we don't allow further changes. + increase_limit = current_bitrate_; + } + + if (current_bitrate_ < increase_limit) { + DataRate increased_bitrate = DataRate::MinusInfinity(); + if (increase_to_network_estimate_ && network_estimate_ && + network_estimate_->link_capacity_upper.IsFinite()) { + increased_bitrate = increase_limit; + } else if (link_capacity_.has_estimate()) { // The link_capacity estimate is reset if the measured throughput // is too far from the estimate. We can therefore assume that our // target rate is reasonably close to link capacity and use additive // increase. DataRate additive_increase = AdditiveRateIncrease(at_time, time_last_bitrate_change_); - new_bitrate += additive_increase; + increased_bitrate = current_bitrate_ + additive_increase; } else { // If we don't have an estimate of the link capacity, use faster ramp // up to discover the capacity. DataRate multiplicative_increase = MultiplicativeRateIncrease( - at_time, time_last_bitrate_change_, new_bitrate); - new_bitrate += multiplicative_increase; + at_time, time_last_bitrate_change_, current_bitrate_); + increased_bitrate = current_bitrate_ + multiplicative_increase; } + new_bitrate = std::min(increased_bitrate, increase_limit); } - time_last_bitrate_change_ = at_time; break; + } - case kRcDecrease: - // TODO(srte): Remove when |estimate_bounded_backoff_| has been validated. - if (network_estimate_ && capacity_deviation_ratio_threshold_ && - !estimate_bounded_backoff_) { - estimated_throughput = std::max(estimated_throughput, - network_estimate_->link_capacity_lower); - } - if (estimated_throughput > low_throughput_threshold_) { - // Set bit rate to something slightly lower than the measured throughput - // to get rid of any self-induced delay. - new_bitrate = estimated_throughput * beta_; - if (new_bitrate > current_bitrate_) { - // Avoid increasing the rate when over-using. - if (link_capacity_.has_estimate()) { - new_bitrate = beta_ * link_capacity_.estimate(); - } - } - if (estimate_bounded_backoff_ && network_estimate_) { - new_bitrate = std::max( - new_bitrate, network_estimate_->link_capacity_lower * beta_); - } - } else { - new_bitrate = estimated_throughput; + case RateControlState::kRcDecrease: { + DataRate decreased_bitrate = DataRate::PlusInfinity(); + + // Set bit rate to something slightly lower than the measured throughput + // to get rid of any self-induced delay. + decreased_bitrate = estimated_throughput * beta_; + MS_DEBUG_DEV("estimated_throughput: %lld, decreased_bitrate: %lld", estimated_throughput.bps(), decreased_bitrate.bps()); + if (decreased_bitrate > current_bitrate_ && !link_capacity_fix_) { + // TODO(terelius): The link_capacity estimate may be based on old + // throughput measurements. Relying on them may lead to unnecessary + // BWE drops. if (link_capacity_.has_estimate()) { - new_bitrate = std::max(new_bitrate, link_capacity_.estimate()); + decreased_bitrate = beta_ * link_capacity_.estimate(); } - new_bitrate = std::min(new_bitrate, low_throughput_threshold_.Get()); } - new_bitrate = std::min(new_bitrate, current_bitrate_); + // Avoid increasing the rate when over-using. + if (decreased_bitrate < current_bitrate_) { + new_bitrate = decreased_bitrate; + } if (bitrate_is_initialized_ && estimated_throughput < current_bitrate_) { - constexpr double kDegradationFactor = 0.9; - if (smoothing_experiment_ && - new_bitrate < kDegradationFactor * beta_ * current_bitrate_) { - // If bitrate decreases more than a normal back off after overuse, it - // indicates a real network degradation. We do not let such a decrease - // to determine the bandwidth estimation period. - last_decrease_ = absl::nullopt; + if (!new_bitrate.has_value()) { + last_decrease_ = DataRate::Zero(); } else { - last_decrease_ = current_bitrate_ - new_bitrate; + last_decrease_ = current_bitrate_ - *new_bitrate; } } if (estimated_throughput < link_capacity_.LowerBound()) { @@ -359,38 +371,33 @@ DataRate AimdRateControl::ChangeBitrate(DataRate new_bitrate, bitrate_is_initialized_ = true; link_capacity_.OnOveruseDetected(estimated_throughput); // Stay on hold until the pipes are cleared. - rate_control_state_ = kRcHold; + rate_control_state_ = RateControlState::kRcHold; time_last_bitrate_change_ = at_time; time_last_bitrate_decrease_ = at_time; break; - + } default: MS_THROW_ERROR("unknown rate control state"); } - return ClampBitrate(new_bitrate, estimated_throughput); + + current_bitrate_ = ClampBitrate(new_bitrate.value_or(current_bitrate_)); } -DataRate AimdRateControl::ClampBitrate(DataRate new_bitrate, - DataRate estimated_throughput) const { - // Allow the estimate to increase as long as alr is not detected to ensure - // that there is no BWE values that can make the estimate stuck at a too - // low bitrate. If an encoder can not produce the bitrate necessary to - // fully use the capacity, alr will sooner or later trigger. - if (!(send_side_ && no_bitrate_increase_in_alr_)) { - // Don't change the bit rate if the send side is too far off. - // We allow a bit more lag at very low rates to not too easily get stuck if - // the encoder produces uneven outputs. - const DataRate max_bitrate = - 1.5 * estimated_throughput + DataRate::kbps(10); - if (new_bitrate > current_bitrate_ && new_bitrate > max_bitrate) { - new_bitrate = std::max(current_bitrate_, max_bitrate); +DataRate AimdRateControl::ClampBitrate(DataRate new_bitrate) const { + if (!disable_estimate_bounded_increase_ && network_estimate_ && + network_estimate_->link_capacity_upper.IsFinite()) { + DataRate upper_bound = network_estimate_->link_capacity_upper * + estimate_bounded_increase_ratio_.Get(); + if (ignore_network_estimate_decrease_) { + upper_bound = std::max(upper_bound, current_bitrate_); } + new_bitrate = std::min(upper_bound, new_bitrate); } - - if (network_estimate_ && - (estimate_bounded_increase_ || capacity_limit_deviation_factor_)) { - DataRate upper_bound = network_estimate_->link_capacity_upper; - new_bitrate = std::min(new_bitrate, upper_bound); + if (network_estimate_ && network_estimate_->link_capacity_lower.IsFinite() && + new_bitrate < current_bitrate_) { + new_bitrate = std::min( + current_bitrate_, + std::max(new_bitrate, network_estimate_->link_capacity_lower * beta_)); } new_bitrate = std::max(new_bitrate, min_configured_bitrate_); return new_bitrate; @@ -422,18 +429,18 @@ void AimdRateControl::ChangeState(const RateControlInput& input, Timestamp at_time) { switch (input.bw_state) { case BandwidthUsage::kBwNormal: - if (rate_control_state_ == kRcHold) { + if (rate_control_state_ == RateControlState::kRcHold) { time_last_bitrate_change_ = at_time; - rate_control_state_ = kRcIncrease; + rate_control_state_ = RateControlState::kRcIncrease; } break; case BandwidthUsage::kBwOverusing: - if (rate_control_state_ != kRcDecrease) { - rate_control_state_ = kRcDecrease; + if (rate_control_state_ != RateControlState::kRcDecrease) { + rate_control_state_ = RateControlState::kRcDecrease; } break; case BandwidthUsage::kBwUnderusing: - rate_control_state_ = kRcHold; + rate_control_state_ = RateControlState::kRcHold; break; default: MS_THROW_ERROR("unknown input.bw_state"); diff --git a/worker/deps/libwebrtc/libwebrtc/modules/remote_bitrate_estimator/aimd_rate_control.h b/worker/deps/libwebrtc/libwebrtc/modules/remote_bitrate_estimator/aimd_rate_control.h index cefea2f2a5..75fad29704 100644 --- a/worker/deps/libwebrtc/libwebrtc/modules/remote_bitrate_estimator/aimd_rate_control.h +++ b/worker/deps/libwebrtc/libwebrtc/modules/remote_bitrate_estimator/aimd_rate_control.h @@ -63,8 +63,9 @@ class AimdRateControl { double GetNearMaxIncreaseRateBpsPerSecond() const; // Returns the expected time between overuse signals (assuming steady state). TimeDelta GetExpectedBandwidthPeriod() const; - + RateControlState GetRateControlState() const; private: + friend class GoogCcStatePrinter; // Update the target bitrate based on, among other things, the current rate // control state, the current target bitrate and the estimated throughput. @@ -73,14 +74,9 @@ class AimdRateControl { // in the "decrease" state the bitrate will be decreased to slightly below the // current throughput. When in the "hold" state the bitrate will be kept // constant to allow built up queues to drain. - DataRate ChangeBitrate(DataRate current_bitrate, - const RateControlInput& input, - Timestamp at_time); - // Clamps new_bitrate to within the configured min bitrate and a linear - // function of the throughput, so that the new bitrate can't grow too - // large compared to the bitrate actually being received by the other end. - DataRate ClampBitrate(DataRate new_bitrate, - DataRate estimated_throughput) const; + void ChangeBitrate(const RateControlInput& input, Timestamp at_time); + + DataRate ClampBitrate(DataRate new_bitrate) const; DataRate MultiplicativeRateIncrease(Timestamp at_time, Timestamp last_ms, DataRate current_bitrate) const; @@ -107,20 +103,22 @@ class AimdRateControl { // Allow the delay based estimate to only increase as long as application // limited region (alr) is not detected. const bool no_bitrate_increase_in_alr_; - const bool smoothing_experiment_; // Use estimated link capacity lower bound if it is higher than the // acknowledged rate when backing off due to overuse. const bool estimate_bounded_backoff_; - // Use estimated link capacity upper bound as upper limit for increasing - // bitrate over the acknowledged rate. - const bool estimate_bounded_increase_; + // If false, uses estimated link capacity upper bound * + // `estimate_bounded_increase_ratio_` as upper limit for the estimate. + FieldTrialFlag disable_estimate_bounded_increase_{"Disabled"}; + FieldTrialParameter estimate_bounded_increase_ratio_{"ratio", 1.0}; + FieldTrialParameter ignore_throughput_limit_if_network_estimate_{ + "ignore_acked", false}; + FieldTrialParameter increase_to_network_estimate_{"immediate_incr", + false}; + FieldTrialParameter ignore_network_estimate_decrease_{"ignore_decr", + false}; absl::optional last_decrease_; FieldTrialOptional initial_backoff_interval_; - FieldTrialParameter low_throughput_threshold_; - // Deprecated, enable |estimate_bounded_backoff_| instead. - FieldTrialOptional capacity_deviation_ratio_threshold_; - // Deprecated, enable |estimate_bounded_increase_| instead. - FieldTrialOptional capacity_limit_deviation_factor_; + FieldTrialFlag link_capacity_fix_; }; } // namespace webrtc diff --git a/worker/deps/libwebrtc/libwebrtc/modules/remote_bitrate_estimator/include/bwe_defines.h b/worker/deps/libwebrtc/libwebrtc/modules/remote_bitrate_estimator/include/bwe_defines.h index 11469b6a43..18a4de0b88 100644 --- a/worker/deps/libwebrtc/libwebrtc/modules/remote_bitrate_estimator/include/bwe_defines.h +++ b/worker/deps/libwebrtc/libwebrtc/modules/remote_bitrate_estimator/include/bwe_defines.h @@ -29,6 +29,8 @@ DataRate GetMinBitrate(); static const int64_t kBitrateWindowMs = 1000; +constexpr DataRate kCongestionControllerMinBitrate = DataRate::BitsPerSec<5000>(); + extern const char kBweTypeHistogram[]; enum BweNames { @@ -39,7 +41,7 @@ enum BweNames { kBweNamesMax = 4 }; -enum RateControlState { kRcHold, kRcIncrease, kRcDecrease }; +enum class RateControlState { kRcHold, kRcIncrease, kRcDecrease }; struct RateControlInput { RateControlInput(BandwidthUsage bw_state, diff --git a/worker/deps/libwebrtc/libwebrtc/rtc_base/experiments/field_trial_list.cc b/worker/deps/libwebrtc/libwebrtc/rtc_base/experiments/field_trial_list.cc new file mode 100644 index 0000000000..101e428f7e --- /dev/null +++ b/worker/deps/libwebrtc/libwebrtc/rtc_base/experiments/field_trial_list.cc @@ -0,0 +1,59 @@ +/* + * Copyright 2019 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 "rtc_base/experiments/field_trial_list.h" + +//#include "absl/strings/string_view.h" + +namespace webrtc { + +FieldTrialListBase::FieldTrialListBase(std::string key) + : FieldTrialParameterInterface(key), + failed_(false), + parse_got_called_(false) {} + +bool FieldTrialListBase::Failed() const { + return failed_; +} +bool FieldTrialListBase::Used() const { + return parse_got_called_; +} + +int FieldTrialListWrapper::Length() { + return GetList()->Size(); +} +bool FieldTrialListWrapper::Failed() { + return GetList()->Failed(); +} +bool FieldTrialListWrapper::Used() { + return GetList()->Used(); +} + +bool FieldTrialStructListBase::Parse(absl::optional str_value) { + // RTC_DCHECK_NOTREACHED(); + return true; +} + +int FieldTrialStructListBase::ValidateAndGetLength() { + int length = -1; + for (std::unique_ptr& list : sub_lists_) { + if (list->Failed()) + return -1; + else if (!list->Used()) + continue; + else if (length == -1) + length = list->Length(); + else if (length != list->Length()) + return -1; + } + + return length; +} + +} // namespace webrtc diff --git a/worker/deps/libwebrtc/libwebrtc/rtc_base/experiments/field_trial_list.h b/worker/deps/libwebrtc/libwebrtc/rtc_base/experiments/field_trial_list.h new file mode 100644 index 0000000000..b302104c64 --- /dev/null +++ b/worker/deps/libwebrtc/libwebrtc/rtc_base/experiments/field_trial_list.h @@ -0,0 +1,237 @@ +/* + * Copyright 2018 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 RTC_BASE_EXPERIMENTS_FIELD_TRIAL_LIST_H_ +#define RTC_BASE_EXPERIMENTS_FIELD_TRIAL_LIST_H_ + +#include +#include +#include +#include + +#include "absl/strings/string_view.h" +#include "rtc_base/experiments/field_trial_parser.h" + +// List support for field trial strings. FieldTrialList and FieldTrialStructList +// are used similarly to the other FieldTrialParameters, but take a variable +// number of parameters. A FieldTrialList parses a |-delimeted string into a +// list of T, using ParseTypedParameter to parse the individual tokens. +// Example string: "my_list:1|2|3,empty_list,other_list:aardvark". + +// A FieldTrialStructList combines multiple lists into a list-of-structs. It +// ensures that all its sublists parse correctly and have the same length, then +// uses user-supplied accessor functions to write those elements into structs of +// a user-supplied type. + +// See the unit test for usage and behavior. + +namespace webrtc { + +class FieldTrialListBase : public FieldTrialParameterInterface { + protected: + friend class FieldTrialListWrapper; + explicit FieldTrialListBase(std::string key); + + bool Failed() const; + bool Used() const; + + virtual int Size() = 0; + + bool failed_; + bool parse_got_called_; +}; + +// This class represents a vector of type T. The elements are separated by a | +// and parsed using ParseTypedParameter. +template +class FieldTrialList : public FieldTrialListBase { + public: + explicit FieldTrialList(std::string key) : FieldTrialList(key, {}) {} + FieldTrialList(std::string key, std::initializer_list default_values) + : FieldTrialListBase(key), values_(default_values) {} + + std::vector Get() const { return values_; } + operator std::vector() const { return Get(); } + typename std::vector::const_reference operator[](size_t index) const { + return values_[index]; + } + const std::vector* operator->() const { return &values_; } + std::vector split(std::string source, char delimiter) { + std::vector fields; + size_t last = 0; + for (size_t i = 0; i < source.length(); ++i) { + if (source[i] == delimiter) { + fields.push_back(source.substr(last, i - last)); + last = i + 1; + } + } + fields.push_back(source.substr(last)); + return fields; + } + + protected: + bool Parse(absl::optional str_value) override { + parse_got_called_ = true; + + if (!str_value) { + values_.clear(); + return true; + } + + std::vector new_values_; + + for (const std::string& token : split(str_value.value(), '|')) { + absl::optional value = ParseTypedParameter(token); + if (value) { + new_values_.push_back(*value); + } else { + failed_ = true; + return false; + } + } + + values_.swap(new_values_); + return true; + } + + int Size() override { return values_.size(); } + + private: + std::vector values_; +}; + +class FieldTrialListWrapper { + public: + virtual ~FieldTrialListWrapper() = default; + + // Takes the element at the given index in the wrapped list and writes it to + // the given struct. + virtual void WriteElement(void* struct_to_write, int index) = 0; + + virtual FieldTrialListBase* GetList() = 0; + + int Length(); + + // Returns true iff the wrapped list has failed to parse at least one token. + bool Failed(); + + bool Used(); + + protected: + FieldTrialListWrapper() = default; +}; + +namespace field_trial_list_impl { +// The LambdaTypeTraits struct provides type information about lambdas in the +// template expressions below. +template +struct LambdaTypeTraits : public LambdaTypeTraits {}; + +template +struct LambdaTypeTraits { + using ret = RetType; + using src = SourceType; +}; + +template +struct TypedFieldTrialListWrapper : FieldTrialListWrapper { + public: + TypedFieldTrialListWrapper(absl::string_view key, + std::function sink) + : list_(key), sink_(sink) {} + + void WriteElement(void* struct_to_write, int index) override { + sink_(struct_to_write, list_[index]); + } + + FieldTrialListBase* GetList() override { return &list_; } + + private: + FieldTrialList list_; + std::function sink_; +}; + +} // namespace field_trial_list_impl + +template > +FieldTrialListWrapper* FieldTrialStructMember(std::string key, + F accessor) { + return new field_trial_list_impl::TypedFieldTrialListWrapper< + typename Traits::ret>(key, [accessor](void* s, typename Traits::ret t) { + *accessor(static_cast(s)) = t; + }); +} + +// This base class is here to reduce the amount of code we have to generate for +// each type of FieldTrialStructList. +class FieldTrialStructListBase : public FieldTrialParameterInterface { + protected: + FieldTrialStructListBase( + std::initializer_list sub_lists) + : FieldTrialParameterInterface(""), sub_lists_() { + // Take ownership of the list wrappers generated by FieldTrialStructMember + // on the call site. + for (FieldTrialListWrapper* const* it = sub_lists.begin(); + it != sub_lists.end(); it++) { + sub_parameters_.push_back((*it)->GetList()); + sub_lists_.push_back(std::unique_ptr(*it)); + } + } + + // Check that all of our sublists that were in the field trial string had the + // same number of elements. If they do, we return that length. If they had + // different lengths, any sublist had parse failures or no sublists had + // user-supplied values, we return -1. + int ValidateAndGetLength(); + + bool Parse(absl::optional str_value) override; + + std::vector> sub_lists_; +}; + +template +class FieldTrialStructList : public FieldTrialStructListBase { + public: + FieldTrialStructList(std::initializer_list l, + std::initializer_list default_list) + : FieldTrialStructListBase(l), values_(default_list) {} + + std::vector Get() const { return values_; } + operator std::vector() const { return Get(); } + const S& operator[](size_t index) const { return values_[index]; } + const std::vector* operator->() const { return &values_; } + + protected: + void ParseDone() override { + int length = ValidateAndGetLength(); + + if (length == -1) + return; + + std::vector new_values(length, S()); + + for (std::unique_ptr& li : sub_lists_) { + if (li->Used()) { + for (int i = 0; i < length; i++) { + li->WriteElement(&new_values[i], i); + } + } + } + + values_.swap(new_values); + } + + private: + std::vector values_; +}; + +} // namespace webrtc + +#endif // RTC_BASE_EXPERIMENTS_FIELD_TRIAL_LIST_H_ diff --git a/worker/deps/libwebrtc/libwebrtc/rtc_base/experiments/field_trial_parser.cc b/worker/deps/libwebrtc/libwebrtc/rtc_base/experiments/field_trial_parser.cc index 9cfc67286b..b53715f5f0 100644 --- a/worker/deps/libwebrtc/libwebrtc/rtc_base/experiments/field_trial_parser.cc +++ b/worker/deps/libwebrtc/libwebrtc/rtc_base/experiments/field_trial_parser.cc @@ -118,21 +118,55 @@ absl::optional ParseTypedParameter(std::string str) { template <> absl::optional ParseTypedParameter(std::string str) { - int value; - if (sscanf(str.c_str(), "%i", &value) == 1) { - return value; - } else { - return absl::nullopt; + int64_t value; + if (sscanf(std::string(str).c_str(), "%" SCNd64, &value) == 1) { + //if (rtc::IsValueInRangeForNumericType(value)) { + return static_cast(value); + //} } + return absl::nullopt; +} + +template <> +absl::optional ParseTypedParameter(std::string str) { + int64_t value; + if (sscanf(std::string(str).c_str(), "%" SCNd64, &value) == 1) { + //if (rtc::IsValueInRangeForNumericType(value)) { + return static_cast(value); + //} + } + return absl::nullopt; } template <> -absl::optional ParseTypedParameter(std::string str) { - return std::move(str); +absl::optional ParseTypedParameter( + std::string str) { + return std::string(str); } FieldTrialFlag::FieldTrialFlag(std::string key) : FieldTrialFlag(key, false) {} +template <> +absl::optional> ParseTypedParameter>( + std::string str) { + return ParseOptionalParameter(str); +} +template <> +absl::optional> ParseTypedParameter>( + std::string str) { + return ParseOptionalParameter(str); +} +template <> +absl::optional> +ParseTypedParameter>(std::string str) { + return ParseOptionalParameter(str); +} +template <> +absl::optional> +ParseTypedParameter>(std::string str) { + return ParseOptionalParameter(str); +} + FieldTrialFlag::FieldTrialFlag(std::string key, bool default_value) : FieldTrialParameterInterface(key), value_(default_value) {} @@ -191,13 +225,16 @@ bool AbstractFieldTrialEnum::Parse(absl::optional str_value) { template class FieldTrialParameter; template class FieldTrialParameter; template class FieldTrialParameter; +template class FieldTrialParameter; template class FieldTrialParameter; template class FieldTrialConstrained; template class FieldTrialConstrained; +template class FieldTrialConstrained; template class FieldTrialOptional; template class FieldTrialOptional; +template class FieldTrialOptional; template class FieldTrialOptional; template class FieldTrialOptional; diff --git a/worker/deps/libwebrtc/libwebrtc/rtc_base/experiments/field_trial_parser.h b/worker/deps/libwebrtc/libwebrtc/rtc_base/experiments/field_trial_parser.h index 685468f2ac..6401ea08cc 100644 --- a/worker/deps/libwebrtc/libwebrtc/rtc_base/experiments/field_trial_parser.h +++ b/worker/deps/libwebrtc/libwebrtc/rtc_base/experiments/field_trial_parser.h @@ -226,20 +226,60 @@ class FieldTrialFlag : public FieldTrialParameterInterface { bool value_; }; +template +absl::optional> ParseOptionalParameter( + std::string str) { + if (str.empty()) + return absl::optional(); + auto parsed = ParseTypedParameter(str); + if (parsed.has_value()) + return parsed; + return absl::nullopt; +} + +template <> +absl::optional ParseTypedParameter(std::string str); +template <> +absl::optional ParseTypedParameter(std::string str); +template <> +absl::optional ParseTypedParameter(std::string str); +template <> +absl::optional ParseTypedParameter(std::string str); +template <> +absl::optional ParseTypedParameter( + std::string str); + +template <> +absl::optional> ParseTypedParameter>( + std::string str); +template <> +absl::optional> ParseTypedParameter>( + std::string str); +template <> +absl::optional> +ParseTypedParameter>(std::string str); +template <> +absl::optional> +ParseTypedParameter>(std::string str); + // Accepts true, false, else parsed with sscanf %i, true if != 0. extern template class FieldTrialParameter; // Interpreted using sscanf %lf. extern template class FieldTrialParameter; // Interpreted using sscanf %i. extern template class FieldTrialParameter; +// Interpreted using sscanf %u. +extern template class FieldTrialParameter; // Using the given value as is. extern template class FieldTrialParameter; extern template class FieldTrialConstrained; extern template class FieldTrialConstrained; +extern template class FieldTrialConstrained; extern template class FieldTrialOptional; extern template class FieldTrialOptional; +extern template class FieldTrialOptional; extern template class FieldTrialOptional; extern template class FieldTrialOptional; diff --git a/worker/deps/libwebrtc/libwebrtc/rtc_base/experiments/field_trial_units.cc b/worker/deps/libwebrtc/libwebrtc/rtc_base/experiments/field_trial_units.cc index 7fb514df7d..4d32ef3244 100644 --- a/worker/deps/libwebrtc/libwebrtc/rtc_base/experiments/field_trial_units.cc +++ b/worker/deps/libwebrtc/libwebrtc/rtc_base/experiments/field_trial_units.cc @@ -82,6 +82,22 @@ absl::optional ParseTypedParameter(std::string str) { return absl::nullopt; } +template <> +absl::optional> +ParseTypedParameter>(std::string str) { + return ParseOptionalParameter(str); +} +template <> +absl::optional> +ParseTypedParameter>(std::string str) { + return ParseOptionalParameter(str); +} +template <> +absl::optional> +ParseTypedParameter>(std::string str) { + return ParseOptionalParameter(str); +} + template class FieldTrialParameter; template class FieldTrialParameter; template class FieldTrialParameter; diff --git a/worker/deps/libwebrtc/libwebrtc/rtc_base/experiments/rate_control_settings.cc b/worker/deps/libwebrtc/libwebrtc/rtc_base/experiments/rate_control_settings.cc index 0b5e61ecb3..f486f20741 100644 --- a/worker/deps/libwebrtc/libwebrtc/rtc_base/experiments/rate_control_settings.cc +++ b/worker/deps/libwebrtc/libwebrtc/rtc_base/experiments/rate_control_settings.cc @@ -11,6 +11,7 @@ #include "rtc_base/experiments/rate_control_settings.h" #include "api/transport/field_trial_based_config.h" #include "rtc_base/experiments/field_trial_parser.h" +#include "rtc_base/experiments/struct_parameters_parser.h" #include "rtc_base/numerics/safe_conversions.h" #include @@ -21,27 +22,69 @@ namespace webrtc { namespace { -const int kDefaultAcceptedQueueMs = 250; +const int kDefaultAcceptedQueueMs = 350; const int kDefaultMinPushbackTargetBitrateBps = 30000; +const char kCongestionWindowDefaultFieldTrialString[] = + "QueueSize:350,MinBitrate:30000,DropFrame:true"; + +const char kUseBaseHeavyVp8Tl3RateAllocationFieldTrialName[] = + "WebRTC-UseBaseHeavyVP8TL3RateAllocation"; + +bool IsEnabled(const WebRtcKeyValueConfig* const key_value_config, + absl::string_view key) { + return key_value_config->Lookup(key).find("Enabled") == 0; +} + } // namespace +constexpr char CongestionWindowConfig::kKey[]; + +std::unique_ptr CongestionWindowConfig::Parser() { + return StructParametersParser::Create("QueueSize", &queue_size_ms, // + "MinBitrate", &min_bitrate_bps, + "InitWin", &initial_data_window, + "DropFrame", &drop_frame_only); +} + +// static +CongestionWindowConfig CongestionWindowConfig::Parse(absl::string_view config) { + CongestionWindowConfig res; + res.Parser()->Parse(config); + return res; +} + +constexpr char VideoRateControlConfig::kKey[]; + +std::unique_ptr VideoRateControlConfig::Parser() { + // The empty comments ensures that each pair is on a separate line. + return StructParametersParser::Create( + "pacing_factor", &pacing_factor, // + "alr_probing", &alr_probing, // + "vp8_qp_max", &vp8_qp_max, // + "vp8_min_pixels", &vp8_min_pixels, // + "trust_vp8", &trust_vp8, // + "trust_vp9", &trust_vp9, // + "probe_max_allocation", &probe_max_allocation, // + "bitrate_adjuster", &bitrate_adjuster, // + "adjuster_use_headroom", &adjuster_use_headroom, // + "vp8_s0_boost", &vp8_s0_boost, // + "vp8_base_heavy_tl3_alloc", &vp8_base_heavy_tl3_alloc); +} + RateControlSettings::RateControlSettings( - const WebRtcKeyValueConfig* const key_value_config) - : congestion_window_("QueueSize"), - congestion_window_pushback_("MinBitrate"), - pacing_factor_("pacing_factor"), - alr_probing_("alr_probing", false), - probe_max_allocation_("probe_max_allocation", true), - bitrate_adjuster_("bitrate_adjuster", false), - adjuster_use_headroom_("adjuster_use_headroom", false) { - ParseFieldTrial({&congestion_window_, &congestion_window_pushback_}, - key_value_config->Lookup("WebRTC-CongestionWindow")); - ParseFieldTrial( - {&pacing_factor_, &alr_probing_, - &probe_max_allocation_, &bitrate_adjuster_, &adjuster_use_headroom_}, - key_value_config->Lookup("WebRTC-VideoRateControl")); + const WebRtcKeyValueConfig* const key_value_config) { + std::string congestion_window_config = + key_value_config->Lookup(CongestionWindowConfig::kKey).empty() + ? kCongestionWindowDefaultFieldTrialString + : key_value_config->Lookup(CongestionWindowConfig::kKey); + congestion_window_config_ = + CongestionWindowConfig::Parse(congestion_window_config); + video_config_.vp8_base_heavy_tl3_alloc = IsEnabled( + key_value_config, kUseBaseHeavyVp8Tl3RateAllocationFieldTrialName); + video_config_.Parser()->Parse( + key_value_config->Lookup(VideoRateControlConfig::kKey)); } RateControlSettings::~RateControlSettings() = default; @@ -60,41 +103,84 @@ RateControlSettings RateControlSettings::ParseFromKeyValueConfig( } bool RateControlSettings::UseCongestionWindow() const { - return static_cast(congestion_window_); + return static_cast(congestion_window_config_.queue_size_ms); } int64_t RateControlSettings::GetCongestionWindowAdditionalTimeMs() const { - return congestion_window_.GetOptional().value_or(kDefaultAcceptedQueueMs); + return congestion_window_config_.queue_size_ms.value_or( + kDefaultAcceptedQueueMs); } bool RateControlSettings::UseCongestionWindowPushback() const { - return congestion_window_ && congestion_window_pushback_; + return congestion_window_config_.queue_size_ms && + congestion_window_config_.min_bitrate_bps; +} + +bool RateControlSettings::UseCongestionWindowDropFrameOnly() const { + return congestion_window_config_.drop_frame_only; } uint32_t RateControlSettings::CongestionWindowMinPushbackTargetBitrateBps() const { - return congestion_window_pushback_.GetOptional().value_or( + return congestion_window_config_.min_bitrate_bps.value_or( kDefaultMinPushbackTargetBitrateBps); } +absl::optional +RateControlSettings::CongestionWindowInitialDataWindow() const { + return congestion_window_config_.initial_data_window; +} + absl::optional RateControlSettings::GetPacingFactor() const { - return pacing_factor_.GetOptional(); + return video_config_.pacing_factor; } bool RateControlSettings::UseAlrProbing() const { - return alr_probing_.Get(); + return video_config_.alr_probing; +} + +absl::optional RateControlSettings::LibvpxVp8QpMax() const { + if (video_config_.vp8_qp_max && + (*video_config_.vp8_qp_max < 0 || *video_config_.vp8_qp_max > 63)) { + // RTC_LOG(LS_WARNING) << "Unsupported vp8_qp_max_ value, ignored."; + return absl::nullopt; + } + return video_config_.vp8_qp_max; +} + +absl::optional RateControlSettings::LibvpxVp8MinPixels() const { + if (video_config_.vp8_min_pixels && *video_config_.vp8_min_pixels < 1) { + return absl::nullopt; + } + return video_config_.vp8_min_pixels; +} + +bool RateControlSettings::LibvpxVp8TrustedRateController() const { + return video_config_.trust_vp8; +} + +bool RateControlSettings::Vp8BoostBaseLayerQuality() const { + return video_config_.vp8_s0_boost; +} + +bool RateControlSettings::LibvpxVp9TrustedRateController() const { + return video_config_.trust_vp9; +} + +bool RateControlSettings::Vp8BaseHeavyTl3RateAllocation() const { + return video_config_.vp8_base_heavy_tl3_alloc; } bool RateControlSettings::TriggerProbeOnMaxAllocatedBitrateChange() const { - return probe_max_allocation_.Get(); + return video_config_.probe_max_allocation; } bool RateControlSettings::UseEncoderBitrateAdjuster() const { - return bitrate_adjuster_.Get(); + return video_config_.bitrate_adjuster; } bool RateControlSettings::BitrateAdjusterCanUseNetworkHeadroom() const { - return adjuster_use_headroom_.Get(); + return video_config_.adjuster_use_headroom; } } // namespace webrtc diff --git a/worker/deps/libwebrtc/libwebrtc/rtc_base/experiments/rate_control_settings.h b/worker/deps/libwebrtc/libwebrtc/rtc_base/experiments/rate_control_settings.h index a08afbd03f..fce5831159 100644 --- a/worker/deps/libwebrtc/libwebrtc/rtc_base/experiments/rate_control_settings.h +++ b/worker/deps/libwebrtc/libwebrtc/rtc_base/experiments/rate_control_settings.h @@ -13,12 +13,40 @@ #include "api/transport/webrtc_key_value_config.h" #include "rtc_base/experiments/field_trial_parser.h" -// #include "rtc_base/experiments/field_trial_units.h" +#include "rtc_base/experiments/field_trial_units.h" +#include "rtc_base/experiments/struct_parameters_parser.h" #include namespace webrtc { +struct CongestionWindowConfig { + static constexpr char kKey[] = "WebRTC-CongestionWindow"; + absl::optional queue_size_ms; + absl::optional min_bitrate_bps; + absl::optional initial_data_window; + bool drop_frame_only = false; + std::unique_ptr Parser(); + static CongestionWindowConfig Parse(absl::string_view config); +}; + +struct VideoRateControlConfig { + static constexpr char kKey[] = "WebRTC-VideoRateControl"; + absl::optional pacing_factor; + bool alr_probing = false; + absl::optional vp8_qp_max; + absl::optional vp8_min_pixels; + bool trust_vp8 = true; + bool trust_vp9 = true; + bool probe_max_allocation = true; + bool bitrate_adjuster = true; + bool adjuster_use_headroom = true; + bool vp8_s0_boost = false; + bool vp8_base_heavy_tl3_alloc = false; + + std::unique_ptr Parser(); +}; + class RateControlSettings final { public: ~RateControlSettings(); @@ -34,11 +62,23 @@ class RateControlSettings final { bool UseCongestionWindow() const; int64_t GetCongestionWindowAdditionalTimeMs() const; bool UseCongestionWindowPushback() const; + bool UseCongestionWindowDropFrameOnly() const; uint32_t CongestionWindowMinPushbackTargetBitrateBps() const; + absl::optional CongestionWindowInitialDataWindow() const; absl::optional GetPacingFactor() const; bool UseAlrProbing() const; + absl::optional LibvpxVp8QpMax() const; + absl::optional LibvpxVp8MinPixels() const; + bool LibvpxVp8TrustedRateController() const; + bool Vp8BoostBaseLayerQuality() const; + bool Vp8DynamicRateSettings() const; + bool LibvpxVp9TrustedRateController() const; + bool Vp9DynamicRateSettings() const; + + bool Vp8BaseHeavyTl3RateAllocation() const; + bool TriggerProbeOnMaxAllocatedBitrateChange() const; bool UseEncoderBitrateAdjuster() const; bool BitrateAdjusterCanUseNetworkHeadroom() const; @@ -47,15 +87,8 @@ class RateControlSettings final { explicit RateControlSettings( const WebRtcKeyValueConfig* const key_value_config); - double GetSimulcastScreenshareHysteresisFactor() const; - - FieldTrialOptional congestion_window_; - FieldTrialOptional congestion_window_pushback_; - FieldTrialOptional pacing_factor_; - FieldTrialParameter alr_probing_; - FieldTrialParameter probe_max_allocation_; - FieldTrialParameter bitrate_adjuster_; - FieldTrialParameter adjuster_use_headroom_; + CongestionWindowConfig congestion_window_config_; + VideoRateControlConfig video_config_; }; } // namespace webrtc diff --git a/worker/deps/libwebrtc/libwebrtc/rtc_base/experiments/struct_parameters_parser.cc b/worker/deps/libwebrtc/libwebrtc/rtc_base/experiments/struct_parameters_parser.cc new file mode 100644 index 0000000000..b2cf80c66b --- /dev/null +++ b/worker/deps/libwebrtc/libwebrtc/rtc_base/experiments/struct_parameters_parser.cc @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2019 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 "rtc_base/experiments/struct_parameters_parser.h" + +#include + +#include "absl/strings/string_view.h" +//#include "rtc_base/logging.h" + +namespace webrtc { +namespace { +size_t FindOrEnd(absl::string_view str, size_t start, char delimiter) { + size_t pos = str.find(delimiter, start); + pos = (pos == absl::string_view::npos) ? str.length() : pos; + return pos; +} +} // namespace + +std::string ToString(const double d) { + char buf[32]; + const int len = std::snprintf(&buf[0], ABSL_ARRAYSIZE(buf), "%g", d); + // RTC_DCHECK_LE(len, arraysize(buf)); + return std::string(&buf[0], len); +} + +std::string ToString(const bool b) { + return b ? "true" : "false"; +} + +std::string ToString(const int s) { + char buf[32]; + const int len = std::snprintf(&buf[0], ABSL_ARRAYSIZE(buf), "%d", s); + // RTC_DCHECK_LE(len, arraysize(buf)); + return std::string(&buf[0], len); +} + +std::string ToString(const unsigned int s) { + char buf[32]; + const int len = std::snprintf(&buf[0], ABSL_ARRAYSIZE(buf), "%u", s); + // RTC_DCHECK_LE(len, arraysize(buf)); + return std::string(&buf[0], len); +} + +namespace struct_parser_impl { +namespace { +inline void StringEncode(std::string* target, bool val) { + *target += ToString(val); +} +inline void StringEncode(std::string* target, double val) { + *target += ToString(val); +} +inline void StringEncode(std::string* target, int val) { + *target += ToString(val); +} +inline void StringEncode(std::string* target, unsigned val) { + *target += ToString(val); +} +inline void StringEncode(std::string* target, DataRate val) { + *target += webrtc::ToString(val); +} +inline void StringEncode(std::string* target, DataSize val) { + *target += webrtc::ToString(val); +} +inline void StringEncode(std::string* target, TimeDelta val) { + *target += webrtc::ToString(val); +} + +template +inline void StringEncode(std::string* sb, absl::optional val) { + if (val) + StringEncode(sb, *val); +} +} // namespace +template +bool TypedParser::Parse(absl::string_view src, void* target) { + auto parsed = ParseTypedParameter(std::string(src)); + if (parsed.has_value()) + *reinterpret_cast(target) = *parsed; + return parsed.has_value(); +} +template +void TypedParser::Encode(const void* src, std::string* target) { + StringEncode(target, *reinterpret_cast(src)); +} + +template class TypedParser; +template class TypedParser; +template class TypedParser; +template class TypedParser; +template class TypedParser>; +template class TypedParser>; +template class TypedParser>; + +template class TypedParser; +template class TypedParser; +template class TypedParser; +template class TypedParser>; +template class TypedParser>; +template class TypedParser>; +} // namespace struct_parser_impl + +StructParametersParser::StructParametersParser( + std::vector members) + : members_(std::move(members)) {} + +void StructParametersParser::Parse(absl::string_view src) { + size_t i = 0; + while (i < src.length()) { + size_t val_end = FindOrEnd(src, i, ','); + size_t colon_pos = FindOrEnd(src, i, ':'); + size_t key_end = std::min(val_end, colon_pos); + size_t val_begin = key_end + 1u; + absl::string_view key(src.substr(i, key_end - i)); + absl::string_view opt_value; + if (val_end >= val_begin) + opt_value = src.substr(val_begin, val_end - val_begin); + i = val_end + 1u; + bool found = false; + for (auto& member : members_) { + if (key == member.key) { + found = true; + if (!member.parser.parse(opt_value, member.member_ptr)) { + // RTC_LOG(LS_WARNING) << "Failed to read field with key: '" << key + // << "' in trial: \"" << src << "\""; + } + break; + } + } + // "_" is be used to prefix keys that are part of the string for + // debugging purposes but not neccessarily used. + // e.g. WebRTC-Experiment/param: value, _DebuggingString + if (!found && (key.empty() || key[0] != '_')) { + // RTC_LOG(LS_INFO) << "No field with key: '" << key + // << "' (found in trial: \"" << src << "\")"; + } + } +} + +std::string StructParametersParser::Encode() const { + std::string res; + bool first = true; + for (const auto& member : members_) { + if (!first) + res += ","; + res += member.key; + res += ":"; + member.parser.encode(member.member_ptr, &res); + first = false; + } + return res; +} + +} // namespace webrtc diff --git a/worker/deps/libwebrtc/libwebrtc/rtc_base/experiments/struct_parameters_parser.h b/worker/deps/libwebrtc/libwebrtc/rtc_base/experiments/struct_parameters_parser.h new file mode 100644 index 0000000000..1de1c00ff0 --- /dev/null +++ b/worker/deps/libwebrtc/libwebrtc/rtc_base/experiments/struct_parameters_parser.h @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2019 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 RTC_BASE_EXPERIMENTS_STRUCT_PARAMETERS_PARSER_H_ +#define RTC_BASE_EXPERIMENTS_STRUCT_PARAMETERS_PARSER_H_ + +#include +#include +#include +#include +#include +#include + +#include "absl/memory/memory.h" +#include "absl/strings/string_view.h" +#include "absl/types/optional.h" +#include "rtc_base/experiments/field_trial_parser.h" +#include "rtc_base/experiments/field_trial_units.h" + +namespace webrtc { +namespace struct_parser_impl { +struct TypedMemberParser { + public: + bool (*parse)(absl::string_view src, void* target); + void (*encode)(const void* src, std::string* target); +}; + +struct MemberParameter { + const char* key; + void* member_ptr; + TypedMemberParser parser; +}; + +template +class TypedParser { + public: + static bool Parse(absl::string_view src, void* target); + static void Encode(const void* src, std::string* target); +}; + +// Instantiated in cc file to avoid duplication during compile. Add additional +// parsers as needed. Generally, try to use these suggested types even if the +// context where the value is used might require a different type. For instance, +// a size_t representing a packet size should use an int parameter as there's no +// need to support packet sizes larger than INT32_MAX. +extern template class TypedParser; +extern template class TypedParser; +extern template class TypedParser; +extern template class TypedParser; +extern template class TypedParser>; +extern template class TypedParser>; +extern template class TypedParser>; + +extern template class TypedParser; +extern template class TypedParser; +extern template class TypedParser; +extern template class TypedParser>; +extern template class TypedParser>; +extern template class TypedParser>; + +template +void AddMembers(MemberParameter* out, const char* key, T* member) { + *out = MemberParameter{ + key, member, + TypedMemberParser{&TypedParser::Parse, &TypedParser::Encode}}; +} + +template +void AddMembers(MemberParameter* out, + const char* key, + T* member, + Args... args) { + AddMembers(out, key, member); + AddMembers(++out, args...); +} +} // namespace struct_parser_impl + +class StructParametersParser { + public: + template + static std::unique_ptr Create(const char* first_key, + T* first_member, + Args... args) { + std::vector members( + sizeof...(args) / 2 + 1); + struct_parser_impl::AddMembers(&members.front(), std::move(first_key), + first_member, args...); + return absl::WrapUnique(new StructParametersParser(std::move(members))); + } + + void Parse(absl::string_view src); + std::string Encode() const; + + private: + explicit StructParametersParser( + std::vector members); + + std::vector members_; +}; + +} // namespace webrtc + +#endif // RTC_BASE_EXPERIMENTS_STRUCT_PARAMETERS_PARSER_H_ diff --git a/worker/deps/libwebrtc/meson.build b/worker/deps/libwebrtc/meson.build index 7d2c54e219..78076c8e6c 100644 --- a/worker/deps/libwebrtc/meson.build +++ b/worker/deps/libwebrtc/meson.build @@ -4,7 +4,9 @@ libwebrtc_sources = [ 'libwebrtc/rtc_base/experiments/field_trial_parser.cc', 'libwebrtc/rtc_base/experiments/alr_experiment.cc', 'libwebrtc/rtc_base/experiments/field_trial_units.cc', + 'libwebrtc/rtc_base/experiments/field_trial_list.cc', 'libwebrtc/rtc_base/experiments/rate_control_settings.cc', + 'libwebrtc/rtc_base/experiments/struct_parameters_parser.cc', 'libwebrtc/rtc_base/network/sent_packet.cc', 'libwebrtc/call/rtp_transport_controller_send.cc', 'libwebrtc/api/transport/bitrate_settings.cc', @@ -23,23 +25,26 @@ libwebrtc_sources = [ 'libwebrtc/modules/remote_bitrate_estimator/overuse_detector.cc', 'libwebrtc/modules/remote_bitrate_estimator/overuse_estimator.cc', 'libwebrtc/modules/remote_bitrate_estimator/aimd_rate_control.cc', - 'libwebrtc/modules/remote_bitrate_estimator/inter_arrival.cc', 'libwebrtc/modules/remote_bitrate_estimator/bwe_defines.cc', 'libwebrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_abs_send_time.cc', + 'libwebrtc/modules/remote_bitrate_estimator/inter_arrival.cc', 'libwebrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.cc', 'libwebrtc/modules/bitrate_controller/send_side_bandwidth_estimation.cc', 'libwebrtc/modules/bitrate_controller/loss_based_bandwidth_estimation.cc', + 'libwebrtc/modules/bitrate_controller/loss_based_bwe_v2.cc', 'libwebrtc/modules/congestion_controller/goog_cc/goog_cc_network_control.cc', 'libwebrtc/modules/congestion_controller/goog_cc/probe_bitrate_estimator.cc', 'libwebrtc/modules/congestion_controller/goog_cc/congestion_window_pushback_controller.cc', 'libwebrtc/modules/congestion_controller/goog_cc/link_capacity_estimator.cc', 'libwebrtc/modules/congestion_controller/goog_cc/alr_detector.cc', 'libwebrtc/modules/congestion_controller/goog_cc/probe_controller.cc', - 'libwebrtc/modules/congestion_controller/goog_cc/median_slope_estimator.cc', 'libwebrtc/modules/congestion_controller/goog_cc/bitrate_estimator.cc', 'libwebrtc/modules/congestion_controller/goog_cc/trendline_estimator.cc', 'libwebrtc/modules/congestion_controller/goog_cc/delay_based_bwe.cc', 'libwebrtc/modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator.cc', + 'libwebrtc/modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator_interface.cc', + 'libwebrtc/modules/congestion_controller/goog_cc/inter_arrival_delta.cc', + 'libwebrtc/modules/congestion_controller/goog_cc/robust_throughput_estimator.cc', 'libwebrtc/modules/congestion_controller/rtp/send_time_history.cc', 'libwebrtc/modules/congestion_controller/rtp/transport_feedback_adapter.cc', 'libwebrtc/modules/congestion_controller/rtp/control_handler.cc', diff --git a/worker/include/RTC/Transport.hpp b/worker/include/RTC/Transport.hpp index c52a197616..180499030c 100644 --- a/worker/include/RTC/Transport.hpp +++ b/worker/include/RTC/Transport.hpp @@ -117,6 +117,7 @@ namespace RTC { bool probation{ false }; bool bwe{ false }; + bool bweStats{ false }; }; public: @@ -267,6 +268,9 @@ namespace RTC RTC::TransportCongestionControlClient* tccClient, RTC::RtpPacket* packet, const webrtc::PacedPacketInfo& pacingInfo) override; + void OnTransportCongestionControlClientBweStats( + const webrtc::BweStats& bweStats, + RTC::TransportCongestionControlClient::Bitrates& bitrates) override; /* Pure virtual methods inherited from RTC::TransportCongestionControlServer::Listener. */ public: diff --git a/worker/include/RTC/TransportCongestionControlClient.hpp b/worker/include/RTC/TransportCongestionControlClient.hpp index 17f7684f04..8252f0c2af 100644 --- a/worker/include/RTC/TransportCongestionControlClient.hpp +++ b/worker/include/RTC/TransportCongestionControlClient.hpp @@ -21,7 +21,8 @@ namespace RTC class TransportCongestionControlClient : public webrtc::PacketRouter, public webrtc::TargetTransferRateObserver, - public Timer::Listener + public Timer::Listener, + public webrtc::BweStatsTracer { public: struct Bitrates @@ -49,6 +50,9 @@ namespace RTC RTC::TransportCongestionControlClient* tccClient, RTC::RtpPacket* packet, const webrtc::PacedPacketInfo& pacingInfo) = 0; + virtual void OnTransportCongestionControlClientBweStats( + const webrtc::BweStats& bweStats, + RTC::TransportCongestionControlClient::Bitrates& bitrates) = 0; }; public: @@ -97,6 +101,9 @@ namespace RTC public: void OnTargetTransferRate(webrtc::TargetTransferRate targetTransferRate) override; + public: + void OnBweStats(webrtc::BweStats) override; + /* Pure virtual methods inherited from webrtc::PacketRouter. */ public: void SendPacket(RTC::RtpPacket* packet, const webrtc::PacedPacketInfo& pacingInfo) override; diff --git a/worker/include/Settings.hpp b/worker/include/Settings.hpp index bd3343546d..5a4f08f7cf 100644 --- a/worker/include/Settings.hpp +++ b/worker/include/Settings.hpp @@ -38,7 +38,9 @@ class Settings uint16_t rtcMaxPort{ 59999u }; std::string dtlsCertificateFile; std::string dtlsPrivateKeyFile; - std::string libwebrtcFieldTrials{ "WebRTC-Bwe-AlrLimitedBackoff/Enabled/" }; + std::string libwebrtcFieldTrials{ + "WebRTC-Bwe-AlrLimitedBackoff/Enabled/WebRTC-Bwe-LossBasedBweV2/BwRampupUpperBoundFactor:1.1,TrendlineIntegrationEnabled:true/WebRTC-Bwe-RobustThroughputEstimatorSettings/enabled/" + }; }; public: diff --git a/worker/src/DepLibWebRTC.cpp b/worker/src/DepLibWebRTC.cpp index c5edfa2999..9155847994 100644 --- a/worker/src/DepLibWebRTC.cpp +++ b/worker/src/DepLibWebRTC.cpp @@ -32,4 +32,4 @@ void DepLibWebRTC::ClassInit() void DepLibWebRTC::ClassDestroy() { MS_TRACE(); -} +} \ No newline at end of file diff --git a/worker/src/RTC/Transport.cpp b/worker/src/RTC/Transport.cpp index 9aef0f78cc..4b78be3430 100644 --- a/worker/src/RTC/Transport.cpp +++ b/worker/src/RTC/Transport.cpp @@ -440,6 +440,8 @@ namespace RTC traceEventTypes.emplace_back("probation"); if (this->traceEventTypes.bwe) traceEventTypes.emplace_back("bwe"); + if (this->traceEventTypes.bweStats) + traceEventTypes.emplace_back("bweStats"); if (!traceEventTypes.empty()) { @@ -1293,6 +1295,8 @@ namespace RTC newTraceEventTypes.probation = true; if (typeStr == "bwe") newTraceEventTypes.bwe = true; + if (typeStr == "bweStats") + newTraceEventTypes.bweStats = true; } this->traceEventTypes = newTraceEventTypes; @@ -2305,7 +2309,14 @@ namespace RTC this->tccClient->RescheduleNextAvailableBitrateEvent(); + auto rtxSendBitrate = this->sendRtxTransmission.GetBitrate(DepLibUV::GetTimeMs()); + MS_DEBUG_DEV("before layer-by-layer iterations [availableBitrate:%" PRIu32 "]", availableBitrate); + MS_DEBUG_DEV( + "before layer-by-layer iterations [availableBitrate - sendRtxTransmission:%" PRIu32 "]", + availableBitrate - rtxSendBitrate); + + availableBitrate = availableBitrate - rtxSendBitrate; // Redistribute the available bitrate by allowing Consumers to increase // layer by layer. Initially try to spread the bitrate across all @@ -2935,6 +2946,52 @@ namespace RTC EmitTraceEventBweType(bitrates); } + inline void Transport::OnTransportCongestionControlClientBweStats( + const webrtc::BweStats& bweStats, RTC::TransportCongestionControlClient::Bitrates& bitrates) + { + MS_TRACE(); + + if (!this->traceEventTypes.bweStats) + return; + + json data = json::object(); + + data["type"] = "bweStats"; + data["timestamp"] = bweStats.time.ms(); + data["direction"] = "out"; + data["info"]["estimatedBitrate"] = + bweStats.estimated_bitrate.value_or(webrtc::DataRate::Zero()).bps(); + data["info"]["availableOutgoingBitrate"] = this->tccClient->GetAvailableBitrate(); + data["info"]["delay"]["slope"] = bweStats.delay.trend.slope; + data["info"]["delay"]["rSquared"] = bweStats.delay.trend.r_squared; + data["info"]["delay"]["threshold"] = bweStats.delay.threshold; + data["info"]["delay"]["rtt"] = bweStats.rtt.ms(); + data["info"]["delay"]["rateControlState"] = bweStats.delay.rate_control_state; + data["info"]["delay"]["delayDetectorState"] = bweStats.delay.delay_detector_state; + data["info"]["alr"] = bweStats.in_alr; + data["info"]["probe"]["estimatedBitrate"] = + bweStats.probe_bitrate.value_or(webrtc::DataRate::Zero()).bps(); + data["info"]["ackBitrate"] = + bweStats.acknowledged_bitrate.value_or(webrtc::DataRate::Zero()).bps(); + + bweStats.probe_bitrate.value_or(webrtc::DataRate::Zero()).bps(); + data["info"]["loss"]["inherent"] = bweStats.loss_estimator_state.inherent_loss; + data["info"]["loss"]["avg"] = bweStats.loss_estimator_state.avg_loss; + data["info"]["loss"]["estimatedBitrate"] = + bweStats.loss_estimator_state.bandwidth_estimate.value_or(webrtc::DataRate::Zero()).bps(); + data["info"]["loss"]["sendingRate"] = + bweStats.loss_estimator_state.sending_rate.value_or(webrtc::DataRate::Zero()).bps(); + data["info"]["desiredBitrate"] = bitrates.desiredBitrate; + data["info"]["effectiveDesiredBitrate"] = bitrates.effectiveDesiredBitrate; + data["info"]["minBitrate"] = bitrates.minBitrate; + data["info"]["maxBitrate"] = bitrates.maxBitrate; + data["info"]["startBitrate"] = bitrates.startBitrate; + data["info"]["maxPaddingBitrate"] = bitrates.maxPaddingBitrate; + data["info"]["sendingRate"] = sendTransmission.GetRate(DepLibUV::GetTimeMsInt64()); + + this->shared->channelNotifier->Emit(this->id, "trace", data); + } + inline void Transport::OnTransportCongestionControlClientSendRtpPacket( RTC::TransportCongestionControlClient* tccClient, RTC::RtpPacket* packet, diff --git a/worker/src/RTC/TransportCongestionControlClient.cpp b/worker/src/RTC/TransportCongestionControlClient.cpp index f555bdf7a5..4b9206a270 100644 --- a/worker/src/RTC/TransportCongestionControlClient.cpp +++ b/worker/src/RTC/TransportCongestionControlClient.cpp @@ -64,6 +64,7 @@ namespace RTC new webrtc::RtpTransportControllerSend(this, nullptr, this->controllerFactory, bitrateConfig); this->rtpTransportControllerSend->RegisterTargetTransferRateObserver(this); + this->rtpTransportControllerSend->RegisterBweStatsTracer(this); this->probationGenerator = new RTC::RtpProbationGenerator(); @@ -473,6 +474,11 @@ namespace RTC } } + void TransportCongestionControlClient::OnBweStats(webrtc::BweStats stats) + { + this->listener->OnTransportCongestionControlClientBweStats(stats, this->bitrates); + } + void TransportCongestionControlClient::OnTargetTransferRate(webrtc::TargetTransferRate targetTransferRate) { MS_TRACE();