1 /*
2  *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include "modules/congestion_controller/goog_cc/alr_detector.h"
12 
13 #include "api/transport/field_trial_based_config.h"
14 #include "rtc_base/checks.h"
15 #include "rtc_base/experiments/alr_experiment.h"
16 #include "test/field_trial.h"
17 #include "test/gtest.h"
18 
19 namespace {
20 
21 constexpr int kEstimatedBitrateBps = 300000;
22 
23 }  // namespace
24 
25 namespace webrtc {
26 namespace {
27 class SimulateOutgoingTrafficIn {
28  public:
SimulateOutgoingTrafficIn(AlrDetector * alr_detector,int64_t * timestamp_ms)29   explicit SimulateOutgoingTrafficIn(AlrDetector* alr_detector,
30                                      int64_t* timestamp_ms)
31       : alr_detector_(alr_detector), timestamp_ms_(timestamp_ms) {
32     RTC_CHECK(alr_detector_);
33   }
34 
ForTimeMs(int time_ms)35   SimulateOutgoingTrafficIn& ForTimeMs(int time_ms) {
36     interval_ms_ = time_ms;
37     ProduceTraffic();
38     return *this;
39   }
40 
AtPercentOfEstimatedBitrate(int usage_percentage)41   SimulateOutgoingTrafficIn& AtPercentOfEstimatedBitrate(int usage_percentage) {
42     usage_percentage_.emplace(usage_percentage);
43     ProduceTraffic();
44     return *this;
45   }
46 
47  private:
ProduceTraffic()48   void ProduceTraffic() {
49     if (!interval_ms_ || !usage_percentage_)
50       return;
51     const int kTimeStepMs = 10;
52     for (int t = 0; t < *interval_ms_; t += kTimeStepMs) {
53       *timestamp_ms_ += kTimeStepMs;
54       alr_detector_->OnBytesSent(kEstimatedBitrateBps * *usage_percentage_ *
55                                      kTimeStepMs / (8 * 100 * 1000),
56                                  *timestamp_ms_);
57     }
58     int remainder_ms = *interval_ms_ % kTimeStepMs;
59     if (remainder_ms > 0) {
60       *timestamp_ms_ += kTimeStepMs;
61       alr_detector_->OnBytesSent(kEstimatedBitrateBps * *usage_percentage_ *
62                                      remainder_ms / (8 * 100 * 1000),
63                                  *timestamp_ms_);
64     }
65   }
66   AlrDetector* const alr_detector_;
67   int64_t* timestamp_ms_;
68   absl::optional<int> interval_ms_;
69   absl::optional<int> usage_percentage_;
70 };
71 }  // namespace
72 
TEST(AlrDetectorTest,AlrDetection)73 TEST(AlrDetectorTest, AlrDetection) {
74   FieldTrialBasedConfig field_trials;
75   int64_t timestamp_ms = 1000;
76   AlrDetector alr_detector(&field_trials);
77   alr_detector.SetEstimatedBitrate(kEstimatedBitrateBps);
78 
79   // Start in non-ALR state.
80   EXPECT_FALSE(alr_detector.GetApplicationLimitedRegionStartTime());
81 
82   // Stay in non-ALR state when usage is close to 100%.
83   SimulateOutgoingTrafficIn(&alr_detector, &timestamp_ms)
84       .ForTimeMs(1000)
85       .AtPercentOfEstimatedBitrate(90);
86   EXPECT_FALSE(alr_detector.GetApplicationLimitedRegionStartTime());
87 
88   // Verify that we ALR starts when bitrate drops below 20%.
89   SimulateOutgoingTrafficIn(&alr_detector, &timestamp_ms)
90       .ForTimeMs(1500)
91       .AtPercentOfEstimatedBitrate(20);
92   EXPECT_TRUE(alr_detector.GetApplicationLimitedRegionStartTime());
93 
94   // Verify that ALR ends when usage is above 65%.
95   SimulateOutgoingTrafficIn(&alr_detector, &timestamp_ms)
96       .ForTimeMs(4000)
97       .AtPercentOfEstimatedBitrate(100);
98   EXPECT_FALSE(alr_detector.GetApplicationLimitedRegionStartTime());
99 }
100 
TEST(AlrDetectorTest,ShortSpike)101 TEST(AlrDetectorTest, ShortSpike) {
102   FieldTrialBasedConfig field_trials;
103   int64_t timestamp_ms = 1000;
104   AlrDetector alr_detector(&field_trials);
105   alr_detector.SetEstimatedBitrate(kEstimatedBitrateBps);
106   // Start in non-ALR state.
107   EXPECT_FALSE(alr_detector.GetApplicationLimitedRegionStartTime());
108 
109   // Verify that we ALR starts when bitrate drops below 20%.
110   SimulateOutgoingTrafficIn(&alr_detector, &timestamp_ms)
111       .ForTimeMs(1000)
112       .AtPercentOfEstimatedBitrate(20);
113   EXPECT_TRUE(alr_detector.GetApplicationLimitedRegionStartTime());
114 
115   // Verify that we stay in ALR region even after a short bitrate spike.
116   SimulateOutgoingTrafficIn(&alr_detector, &timestamp_ms)
117       .ForTimeMs(100)
118       .AtPercentOfEstimatedBitrate(150);
119   EXPECT_TRUE(alr_detector.GetApplicationLimitedRegionStartTime());
120 
121   // ALR ends when usage is above 65%.
122   SimulateOutgoingTrafficIn(&alr_detector, &timestamp_ms)
123       .ForTimeMs(3000)
124       .AtPercentOfEstimatedBitrate(100);
125   EXPECT_FALSE(alr_detector.GetApplicationLimitedRegionStartTime());
126 }
127 
TEST(AlrDetectorTest,BandwidthEstimateChanges)128 TEST(AlrDetectorTest, BandwidthEstimateChanges) {
129   FieldTrialBasedConfig field_trials;
130   int64_t timestamp_ms = 1000;
131   AlrDetector alr_detector(&field_trials);
132   alr_detector.SetEstimatedBitrate(kEstimatedBitrateBps);
133 
134   // Start in non-ALR state.
135   EXPECT_FALSE(alr_detector.GetApplicationLimitedRegionStartTime());
136 
137   // ALR starts when bitrate drops below 20%.
138   SimulateOutgoingTrafficIn(&alr_detector, &timestamp_ms)
139       .ForTimeMs(1000)
140       .AtPercentOfEstimatedBitrate(20);
141   EXPECT_TRUE(alr_detector.GetApplicationLimitedRegionStartTime());
142 
143   // When bandwidth estimate drops the detector should stay in ALR mode and quit
144   // it shortly afterwards as the sender continues sending the same amount of
145   // traffic. This is necessary to ensure that ProbeController can still react
146   // to the BWE drop by initiating a new probe.
147   alr_detector.SetEstimatedBitrate(kEstimatedBitrateBps / 5);
148   EXPECT_TRUE(alr_detector.GetApplicationLimitedRegionStartTime());
149   SimulateOutgoingTrafficIn(&alr_detector, &timestamp_ms)
150       .ForTimeMs(1000)
151       .AtPercentOfEstimatedBitrate(50);
152   EXPECT_FALSE(alr_detector.GetApplicationLimitedRegionStartTime());
153 }
154 
TEST(AlrDetectorTest,ParseControlFieldTrial)155 TEST(AlrDetectorTest, ParseControlFieldTrial) {
156   webrtc::test::ScopedFieldTrials scoped_field_trial(
157       "WebRTC-ProbingScreenshareBwe/Control/");
158   absl::optional<AlrExperimentSettings> parsed_params =
159       AlrExperimentSettings::CreateFromFieldTrial(
160           FieldTrialBasedConfig(), "WebRTC-ProbingScreenshareBwe");
161   EXPECT_FALSE(static_cast<bool>(parsed_params));
162 }
163 
TEST(AlrDetectorTest,ParseActiveFieldTrial)164 TEST(AlrDetectorTest, ParseActiveFieldTrial) {
165   webrtc::test::ScopedFieldTrials scoped_field_trial(
166       "WebRTC-ProbingScreenshareBwe/1.1,2875,85,20,-20,1/");
167   absl::optional<AlrExperimentSettings> parsed_params =
168       AlrExperimentSettings::CreateFromFieldTrial(
169           FieldTrialBasedConfig(), "WebRTC-ProbingScreenshareBwe");
170   ASSERT_TRUE(static_cast<bool>(parsed_params));
171   EXPECT_EQ(1.1f, parsed_params->pacing_factor);
172   EXPECT_EQ(2875, parsed_params->max_paced_queue_time);
173   EXPECT_EQ(85, parsed_params->alr_bandwidth_usage_percent);
174   EXPECT_EQ(20, parsed_params->alr_start_budget_level_percent);
175   EXPECT_EQ(-20, parsed_params->alr_stop_budget_level_percent);
176   EXPECT_EQ(1, parsed_params->group_id);
177 }
178 
TEST(AlrDetectorTest,ParseAlrSpecificFieldTrial)179 TEST(AlrDetectorTest, ParseAlrSpecificFieldTrial) {
180   webrtc::test::ScopedFieldTrials scoped_field_trial(
181       "WebRTC-AlrDetectorParameters/"
182       "bw_usage:90%,start:0%,stop:-10%/");
183   FieldTrialBasedConfig field_trials;
184   AlrDetector alr_detector(&field_trials);
185   int64_t timestamp_ms = 1000;
186   alr_detector.SetEstimatedBitrate(kEstimatedBitrateBps);
187 
188   // Start in non-ALR state.
189   EXPECT_FALSE(alr_detector.GetApplicationLimitedRegionStartTime());
190 
191   // ALR does not start at 100% utilization.
192   SimulateOutgoingTrafficIn(&alr_detector, &timestamp_ms)
193       .ForTimeMs(1000)
194       .AtPercentOfEstimatedBitrate(100);
195   EXPECT_FALSE(alr_detector.GetApplicationLimitedRegionStartTime());
196 
197   // ALR does start at 85% utilization.
198   // Overused 10% above so it should take about 2s to reach a budget level of
199   // 0%.
200   SimulateOutgoingTrafficIn(&alr_detector, &timestamp_ms)
201       .ForTimeMs(2100)
202       .AtPercentOfEstimatedBitrate(85);
203   EXPECT_TRUE(alr_detector.GetApplicationLimitedRegionStartTime());
204 }
205 
206 }  // namespace webrtc
207