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/pacing/alr_detector.h"
12 
13 #include "test/field_trial.h"
14 #include "test/gtest.h"
15 
16 namespace {
17 
18 constexpr int kEstimatedBitrateBps = 300000;
19 
20 }  // namespace
21 
22 namespace webrtc {
23 
24 namespace {
25 class SimulateOutgoingTrafficIn {
26  public:
SimulateOutgoingTrafficIn(AlrDetector * alr_detector)27   explicit SimulateOutgoingTrafficIn(AlrDetector* alr_detector)
28       : alr_detector_(alr_detector) {
29     RTC_CHECK(alr_detector_);
30   }
31 
ForTimeMs(int time_ms)32   SimulateOutgoingTrafficIn& ForTimeMs(int time_ms) {
33     interval_ms_ = rtc::Optional<int>(time_ms);
34     interval_ms_.emplace(time_ms);
35     ProduceTraffic();
36     return *this;
37   }
38 
AtPercentOfEstimatedBitrate(int usage_percentage)39   SimulateOutgoingTrafficIn& AtPercentOfEstimatedBitrate(int usage_percentage) {
40     usage_percentage_.emplace(usage_percentage);
41     ProduceTraffic();
42     return *this;
43   }
44 
45  private:
ProduceTraffic()46   void ProduceTraffic() {
47     if (!interval_ms_ || !usage_percentage_)
48       return;
49     const int kTimeStepMs = 10;
50     for (int t = 0; t < *interval_ms_; t += kTimeStepMs) {
51       alr_detector_->OnBytesSent(kEstimatedBitrateBps * *usage_percentage_ *
52                                      kTimeStepMs / (8 * 100 * 1000),
53                                  kTimeStepMs);
54     }
55     int remainder_ms = *interval_ms_ % kTimeStepMs;
56     if (remainder_ms > 0) {
57       alr_detector_->OnBytesSent(kEstimatedBitrateBps * *usage_percentage_ *
58                                      remainder_ms / (8 * 100 * 1000),
59                                  kTimeStepMs);
60     }
61   }
62   AlrDetector* const alr_detector_;
63   rtc::Optional<int> interval_ms_;
64   rtc::Optional<int> usage_percentage_;
65 };
66 }  // namespace
67 
68 class AlrDetectorTest : public testing::Test {
69  public:
SetUp()70   void SetUp() override {
71     alr_detector_.SetEstimatedBitrate(kEstimatedBitrateBps);
72   }
73 
74  protected:
75   AlrDetector alr_detector_;
76 };
77 
TEST_F(AlrDetectorTest,AlrDetection)78 TEST_F(AlrDetectorTest, AlrDetection) {
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_)
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_)
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_)
96       .ForTimeMs(4000)
97       .AtPercentOfEstimatedBitrate(100);
98   EXPECT_FALSE(alr_detector_.GetApplicationLimitedRegionStartTime());
99 }
100 
TEST_F(AlrDetectorTest,ShortSpike)101 TEST_F(AlrDetectorTest, ShortSpike) {
102   // Start in non-ALR state.
103   EXPECT_FALSE(alr_detector_.GetApplicationLimitedRegionStartTime());
104 
105   // Verify that we ALR starts when bitrate drops below 20%.
106   SimulateOutgoingTrafficIn(&alr_detector_)
107       .ForTimeMs(1000)
108       .AtPercentOfEstimatedBitrate(20);
109   EXPECT_TRUE(alr_detector_.GetApplicationLimitedRegionStartTime());
110 
111   // Verify that we stay in ALR region even after a short bitrate spike.
112   SimulateOutgoingTrafficIn(&alr_detector_)
113       .ForTimeMs(100)
114       .AtPercentOfEstimatedBitrate(150);
115   EXPECT_TRUE(alr_detector_.GetApplicationLimitedRegionStartTime());
116 
117   // ALR ends when usage is above 65%.
118   SimulateOutgoingTrafficIn(&alr_detector_)
119       .ForTimeMs(3000)
120       .AtPercentOfEstimatedBitrate(100);
121   EXPECT_FALSE(alr_detector_.GetApplicationLimitedRegionStartTime());
122 }
123 
TEST_F(AlrDetectorTest,BandwidthEstimateChanges)124 TEST_F(AlrDetectorTest, BandwidthEstimateChanges) {
125   // Start in non-ALR state.
126   EXPECT_FALSE(alr_detector_.GetApplicationLimitedRegionStartTime());
127 
128   // ALR starts when bitrate drops below 20%.
129   SimulateOutgoingTrafficIn(&alr_detector_)
130       .ForTimeMs(1000)
131       .AtPercentOfEstimatedBitrate(20);
132   EXPECT_TRUE(alr_detector_.GetApplicationLimitedRegionStartTime());
133 
134   // When bandwidth estimate drops the detector should stay in ALR mode and quit
135   // it shortly afterwards as the sender continues sending the same amount of
136   // traffic. This is necessary to ensure that ProbeController can still react
137   // to the BWE drop by initiating a new probe.
138   alr_detector_.SetEstimatedBitrate(kEstimatedBitrateBps / 5);
139   EXPECT_TRUE(alr_detector_.GetApplicationLimitedRegionStartTime());
140   SimulateOutgoingTrafficIn(&alr_detector_)
141       .ForTimeMs(1000)
142       .AtPercentOfEstimatedBitrate(50);
143   EXPECT_FALSE(alr_detector_.GetApplicationLimitedRegionStartTime());
144 }
145 
TEST_F(AlrDetectorTest,ParseControlFieldTrial)146 TEST_F(AlrDetectorTest, ParseControlFieldTrial) {
147   webrtc::test::ScopedFieldTrials field_trial(
148       "WebRTC-ProbingScreenshareBwe/Control/");
149   rtc::Optional<AlrDetector::AlrExperimentSettings> parsed_params =
150       AlrDetector::ParseAlrSettingsFromFieldTrial(
151           "WebRTC-ProbingScreenshareBwe");
152   EXPECT_FALSE(static_cast<bool>(parsed_params));
153 }
154 
TEST_F(AlrDetectorTest,ParseActiveFieldTrial)155 TEST_F(AlrDetectorTest, ParseActiveFieldTrial) {
156   webrtc::test::ScopedFieldTrials field_trial(
157       "WebRTC-ProbingScreenshareBwe/1.1,2875,85,20,-20,1/");
158   rtc::Optional<AlrDetector::AlrExperimentSettings> parsed_params =
159       AlrDetector::ParseAlrSettingsFromFieldTrial(
160           "WebRTC-ProbingScreenshareBwe");
161   ASSERT_TRUE(static_cast<bool>(parsed_params));
162   EXPECT_EQ(1.1f, parsed_params->pacing_factor);
163   EXPECT_EQ(2875, parsed_params->max_paced_queue_time);
164   EXPECT_EQ(85, parsed_params->alr_bandwidth_usage_percent);
165   EXPECT_EQ(20, parsed_params->alr_start_budget_level_percent);
166   EXPECT_EQ(-20, parsed_params->alr_stop_budget_level_percent);
167   EXPECT_EQ(1, parsed_params->group_id);
168 }
169 
170 }  // namespace webrtc
171