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