1 /*
2 * Copyright 2020 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 "call/adaptation/new_resource_adaptation_processor_poc.h"
12
13 #include "absl/types/optional.h"
14 #include "call/adaptation/resource.h"
15 #include "call/adaptation/test/fake_resource.h"
16 #include "call/adaptation/test/fake_resource_consumer_configuration.h"
17 #include "test/gmock.h"
18 #include "test/gtest.h"
19
20 namespace webrtc {
21
22 // The indices of different resolutions returned by
23 // AddStandardResolutionConfigurations().
24 static size_t k1080pIndex = 0;
25 static size_t k720pIndex = 1;
26 static size_t k360pIndex = 2;
27 static size_t k180pIndex = 3;
28
ConnectNeighbors(ResourceConsumerConfiguration * upper,ResourceConsumerConfiguration * lower)29 void ConnectNeighbors(ResourceConsumerConfiguration* upper,
30 ResourceConsumerConfiguration* lower) {
31 upper->AddLowerNeighbor(lower);
32 lower->AddUpperNeighbor(upper);
33 }
34
35 std::vector<FakeResourceConsumerConfiguration*>
AddStandardResolutionConfigurations(NewResourceAdaptationProcessorPoc * processor)36 AddStandardResolutionConfigurations(
37 NewResourceAdaptationProcessorPoc* processor) {
38 std::vector<FakeResourceConsumerConfiguration*> configs;
39 configs.push_back(processor->AddConfiguration(
40 std::make_unique<FakeResourceConsumerConfiguration>(1920, 1080, 30.0,
41 1.0)));
42 configs.push_back(processor->AddConfiguration(
43 std::make_unique<FakeResourceConsumerConfiguration>(1280, 720, 30.0,
44 1.0)));
45 configs.push_back(processor->AddConfiguration(
46 std::make_unique<FakeResourceConsumerConfiguration>(640, 360, 30.0,
47 1.0)));
48 configs.push_back(processor->AddConfiguration(
49 std::make_unique<FakeResourceConsumerConfiguration>(320, 180, 30.0,
50 1.0)));
51 for (size_t i = 1; i < configs.size(); ++i) {
52 ConnectNeighbors(configs[i - 1], configs[i]);
53 }
54 return configs;
55 }
56
TEST(NewResourceAdaptationProcessorPocTest,SingleStreamAndResourceDontAdaptDownWhenStable)57 TEST(NewResourceAdaptationProcessorPocTest,
58 SingleStreamAndResourceDontAdaptDownWhenStable) {
59 NewResourceAdaptationProcessorPoc processor;
60 processor.AddResource(
61 std::make_unique<FakeResource>(ResourceUsageState::kStable));
62 auto resolution_configs = AddStandardResolutionConfigurations(&processor);
63 processor.AddConsumer(std::make_unique<ResourceConsumer>(
64 "OnlyStream", resolution_configs[k1080pIndex]));
65 EXPECT_EQ(absl::nullopt, processor.FindNextConfiguration());
66 }
67
TEST(NewResourceAdaptationProcessorPocTest,SingleStreamAndResourceAdaptDownOnOveruse)68 TEST(NewResourceAdaptationProcessorPocTest,
69 SingleStreamAndResourceAdaptDownOnOveruse) {
70 NewResourceAdaptationProcessorPoc processor;
71 processor.AddResource(
72 std::make_unique<FakeResource>(ResourceUsageState::kOveruse));
73 auto resolution_configs = AddStandardResolutionConfigurations(&processor);
74 auto* consumer = processor.AddConsumer(std::make_unique<ResourceConsumer>(
75 "OnlyStream", resolution_configs[k1080pIndex]));
76 auto next_config = processor.FindNextConfiguration();
77 EXPECT_TRUE(next_config.has_value());
78 EXPECT_EQ(consumer, next_config->consumer);
79 EXPECT_EQ(resolution_configs[k720pIndex], next_config->configuration);
80 }
81
TEST(NewResourceAdaptationProcessorPocTest,SingleStreamAndResourceDontAdaptOnOveruseIfMinResolution)82 TEST(NewResourceAdaptationProcessorPocTest,
83 SingleStreamAndResourceDontAdaptOnOveruseIfMinResolution) {
84 NewResourceAdaptationProcessorPoc processor;
85 processor.AddResource(
86 std::make_unique<FakeResource>(ResourceUsageState::kOveruse));
87 auto resolution_configs = AddStandardResolutionConfigurations(&processor);
88 processor.AddConsumer(std::make_unique<ResourceConsumer>(
89 "OnlyStream", resolution_configs.back()));
90 EXPECT_EQ(absl::nullopt, processor.FindNextConfiguration());
91 }
92
TEST(NewResourceAdaptationProcessorPocTest,SingleStreamAndResourceAdaptUpOnUnderuse)93 TEST(NewResourceAdaptationProcessorPocTest,
94 SingleStreamAndResourceAdaptUpOnUnderuse) {
95 NewResourceAdaptationProcessorPoc processor;
96 processor.AddResource(
97 std::make_unique<FakeResource>(ResourceUsageState::kUnderuse));
98 auto resolution_configs = AddStandardResolutionConfigurations(&processor);
99 auto* consumer = processor.AddConsumer(std::make_unique<ResourceConsumer>(
100 "OnlyStream", resolution_configs[k720pIndex]));
101 auto next_config = processor.FindNextConfiguration();
102 EXPECT_TRUE(next_config.has_value());
103 EXPECT_EQ(consumer, next_config->consumer);
104 EXPECT_EQ(resolution_configs[k1080pIndex], next_config->configuration);
105 }
106
TEST(NewResourceAdaptationProcessorPocTest,SingleStreamAndResourceDontAdaptOnUnderuseIfMaxResolution)107 TEST(NewResourceAdaptationProcessorPocTest,
108 SingleStreamAndResourceDontAdaptOnUnderuseIfMaxResolution) {
109 NewResourceAdaptationProcessorPoc processor;
110 processor.AddResource(
111 std::make_unique<FakeResource>(ResourceUsageState::kUnderuse));
112 auto resolution_configs = AddStandardResolutionConfigurations(&processor);
113 processor.AddConsumer(std::make_unique<ResourceConsumer>(
114 "OnlyStream", resolution_configs[k1080pIndex]));
115 EXPECT_EQ(absl::nullopt, processor.FindNextConfiguration());
116 }
117
TEST(NewResourceAdaptationProcessorPocTest,MultipleStreamsLargestStreamGetsAdaptedDownOnOveruse)118 TEST(NewResourceAdaptationProcessorPocTest,
119 MultipleStreamsLargestStreamGetsAdaptedDownOnOveruse) {
120 NewResourceAdaptationProcessorPoc processor;
121 processor.AddResource(
122 std::make_unique<FakeResource>(ResourceUsageState::kOveruse));
123 auto resolution_configs = AddStandardResolutionConfigurations(&processor);
124 auto* first_stream = processor.AddConsumer(std::make_unique<ResourceConsumer>(
125 "FirstStream", resolution_configs[k1080pIndex]));
126 auto* second_stream =
127 processor.AddConsumer(std::make_unique<ResourceConsumer>(
128 "SecondStream", resolution_configs[k720pIndex]));
129 // When the first stream is larger.
130 auto next_config = processor.FindNextConfiguration();
131 EXPECT_TRUE(next_config.has_value());
132 EXPECT_EQ(first_stream, next_config->consumer);
133 // When the second stream is larger.
134 first_stream->SetConfiguration(resolution_configs[k720pIndex]);
135 second_stream->SetConfiguration(resolution_configs[k1080pIndex]);
136 next_config = processor.FindNextConfiguration();
137 EXPECT_TRUE(next_config.has_value());
138 EXPECT_EQ(second_stream, next_config->consumer);
139 }
140
TEST(NewResourceAdaptationProcessorPocTest,MultipleStreamsSmallestStreamGetsAdaptedUpOnUnderuse)141 TEST(NewResourceAdaptationProcessorPocTest,
142 MultipleStreamsSmallestStreamGetsAdaptedUpOnUnderuse) {
143 NewResourceAdaptationProcessorPoc processor;
144 processor.AddResource(
145 std::make_unique<FakeResource>(ResourceUsageState::kUnderuse));
146 auto resolution_configs = AddStandardResolutionConfigurations(&processor);
147 auto* first_stream = processor.AddConsumer(std::make_unique<ResourceConsumer>(
148 "FirstStream", resolution_configs[k360pIndex]));
149 auto* second_stream =
150 processor.AddConsumer(std::make_unique<ResourceConsumer>(
151 "SecondStream", resolution_configs[k180pIndex]));
152 // When the first stream is larger.
153 auto next_config = processor.FindNextConfiguration();
154 EXPECT_TRUE(next_config.has_value());
155 EXPECT_EQ(second_stream, next_config->consumer);
156 // When the second stream is larger.
157 first_stream->SetConfiguration(resolution_configs[k180pIndex]);
158 second_stream->SetConfiguration(resolution_configs[k360pIndex]);
159 next_config = processor.FindNextConfiguration();
160 EXPECT_TRUE(next_config.has_value());
161 EXPECT_EQ(first_stream, next_config->consumer);
162 }
163
164 // If both streams are equally valid to adapt down, the first one is preferred.
TEST(NewResourceAdaptationProcessorPocTest,MultipleStreamsAdaptFirstStreamWhenBothStreamsHaveSameCost)165 TEST(NewResourceAdaptationProcessorPocTest,
166 MultipleStreamsAdaptFirstStreamWhenBothStreamsHaveSameCost) {
167 NewResourceAdaptationProcessorPoc processor;
168 processor.AddResource(
169 std::make_unique<FakeResource>(ResourceUsageState::kOveruse));
170 auto resolution_configs = AddStandardResolutionConfigurations(&processor);
171 auto* first_stream = processor.AddConsumer(std::make_unique<ResourceConsumer>(
172 "FirstStream", resolution_configs[k720pIndex]));
173 processor.AddConsumer(std::make_unique<ResourceConsumer>(
174 "SecondStream", resolution_configs[k720pIndex]));
175 auto next_config = processor.FindNextConfiguration();
176 EXPECT_TRUE(next_config.has_value());
177 EXPECT_EQ(first_stream, next_config->consumer);
178 }
179
TEST(NewResourceAdaptationProcessorPocTest,MultipleResourcesAdaptDownIfAnyIsOverused)180 TEST(NewResourceAdaptationProcessorPocTest,
181 MultipleResourcesAdaptDownIfAnyIsOverused) {
182 NewResourceAdaptationProcessorPoc processor;
183 auto* first_resource = processor.AddResource(
184 std::make_unique<FakeResource>(ResourceUsageState::kOveruse));
185 auto* second_resource = processor.AddResource(
186 std::make_unique<FakeResource>(ResourceUsageState::kStable));
187 auto resolution_configs = AddStandardResolutionConfigurations(&processor);
188 processor.AddConsumer(std::make_unique<ResourceConsumer>(
189 "OnlyStream", resolution_configs[k1080pIndex]));
190 // When the first resource is overused.
191 EXPECT_TRUE(processor.FindNextConfiguration().has_value());
192 // When the second resource is overused.
193 first_resource->set_usage_state(ResourceUsageState::kStable);
194 second_resource->set_usage_state(ResourceUsageState::kOveruse);
195 EXPECT_TRUE(processor.FindNextConfiguration().has_value());
196 }
197
TEST(NewResourceAdaptationProcessorPocTest,MultipleResourcesAdaptUpIfAllAreUnderused)198 TEST(NewResourceAdaptationProcessorPocTest,
199 MultipleResourcesAdaptUpIfAllAreUnderused) {
200 NewResourceAdaptationProcessorPoc processor;
201 processor.AddResource(
202 std::make_unique<FakeResource>(ResourceUsageState::kUnderuse));
203 auto* second_resource = processor.AddResource(
204 std::make_unique<FakeResource>(ResourceUsageState::kStable));
205 auto resolution_configs = AddStandardResolutionConfigurations(&processor);
206 processor.AddConsumer(std::make_unique<ResourceConsumer>(
207 "OnlyStream", resolution_configs[k720pIndex]));
208 // When only the first resource is underused.
209 EXPECT_EQ(absl::nullopt, processor.FindNextConfiguration());
210 // When all resources are underused.
211 second_resource->set_usage_state(ResourceUsageState::kUnderuse);
212 EXPECT_TRUE(processor.FindNextConfiguration().has_value());
213 }
214
TEST(NewResourceAdaptationProcessorPocTest,HighestPreferredNeighborIsPickedWhenAdapting)215 TEST(NewResourceAdaptationProcessorPocTest,
216 HighestPreferredNeighborIsPickedWhenAdapting) {
217 NewResourceAdaptationProcessorPoc processor;
218 // Set up the following graph, where (#) is the preference.
219 //
220 // Downward arrows Upward arrows
221 //
222 // a(1) -----> b(2) a(1) <----- b(2)
223 // | ^ | ^ / ^
224 // | / | | / |
225 // v / v | v |
226 // c(1.5) ---> d(2) c(1.5) <--- d(2)
227 //
228 auto* a = processor.AddConfiguration(
229 std::make_unique<FakeResourceConsumerConfiguration>(1, 1, 1, 1.0));
230 auto* b = processor.AddConfiguration(
231 std::make_unique<FakeResourceConsumerConfiguration>(1, 1, 1, 2.0));
232 auto* c = processor.AddConfiguration(
233 std::make_unique<FakeResourceConsumerConfiguration>(1, 1, 1, 1.5));
234 auto* d = processor.AddConfiguration(
235 std::make_unique<FakeResourceConsumerConfiguration>(1, 1, 1, 2.0));
236 ConnectNeighbors(a, b);
237 ConnectNeighbors(a, c);
238 ConnectNeighbors(b, d);
239 ConnectNeighbors(c, b);
240 ConnectNeighbors(c, d);
241
242 auto* resource = processor.AddResource(
243 std::make_unique<FakeResource>(ResourceUsageState::kOveruse));
244 auto* consumer = processor.AddConsumer(
245 std::make_unique<ResourceConsumer>("OnlyStream", a));
246
247 // We should expect adapting down: a -> b -> d
248 EXPECT_EQ(b, processor.FindNextConfiguration()->configuration);
249 consumer->SetConfiguration(b);
250 EXPECT_EQ(d, processor.FindNextConfiguration()->configuration);
251 consumer->SetConfiguration(d);
252
253 // We should expect to adapt up: d -> b -> c -> a
254 resource->set_usage_state(ResourceUsageState::kUnderuse);
255 EXPECT_EQ(b, processor.FindNextConfiguration()->configuration);
256 consumer->SetConfiguration(b);
257 EXPECT_EQ(c, processor.FindNextConfiguration()->configuration);
258 consumer->SetConfiguration(c);
259 EXPECT_EQ(a, processor.FindNextConfiguration()->configuration);
260 }
261
262 } // namespace webrtc
263