resource_adaptation_processor_unittest.cc (32915B)
1 /* 2 * Copyright (c) 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/resource_adaptation_processor.h" 12 13 #include <cstddef> 14 #include <memory> 15 16 #include "api/adaptation/resource.h" 17 #include "api/rtp_parameters.h" 18 #include "api/scoped_refptr.h" 19 #include "api/sequence_checker.h" 20 #include "api/test/rtc_error_matchers.h" 21 #include "api/units/time_delta.h" 22 #include "api/video/video_adaptation_counters.h" 23 #include "call/adaptation/test/fake_frame_rate_provider.h" 24 #include "call/adaptation/test/fake_resource.h" 25 #include "call/adaptation/video_source_restrictions.h" 26 #include "call/adaptation/video_stream_adapter.h" 27 #include "call/adaptation/video_stream_input_state_provider.h" 28 #include "rtc_base/event.h" 29 #include "rtc_base/task_queue_for_test.h" 30 #include "rtc_base/thread.h" 31 #include "rtc_base/thread_annotations.h" 32 #include "test/create_test_field_trials.h" 33 #include "test/gmock.h" 34 #include "test/gtest.h" 35 #include "test/wait_until.h" 36 37 namespace webrtc { 38 39 namespace { 40 41 using ::testing::Eq; 42 43 constexpr int kDefaultFrameRate = 30; 44 constexpr int kDefaultFrameSize = 1280 * 720; 45 constexpr TimeDelta kDefaultTimeout = TimeDelta::Seconds(5); 46 47 class VideoSourceRestrictionsListenerForTesting 48 : public VideoSourceRestrictionsListener { 49 public: 50 VideoSourceRestrictionsListenerForTesting() 51 : restrictions_updated_count_(0), 52 restrictions_(), 53 adaptation_counters_(), 54 reason_(nullptr) {} 55 ~VideoSourceRestrictionsListenerForTesting() override {} 56 57 size_t restrictions_updated_count() const { 58 RTC_DCHECK_RUN_ON(&sequence_checker_); 59 return restrictions_updated_count_; 60 } 61 VideoSourceRestrictions restrictions() const { 62 RTC_DCHECK_RUN_ON(&sequence_checker_); 63 return restrictions_; 64 } 65 VideoAdaptationCounters adaptation_counters() const { 66 RTC_DCHECK_RUN_ON(&sequence_checker_); 67 return adaptation_counters_; 68 } 69 scoped_refptr<Resource> reason() const { 70 RTC_DCHECK_RUN_ON(&sequence_checker_); 71 return reason_; 72 } 73 74 // VideoSourceRestrictionsListener implementation. 75 void OnVideoSourceRestrictionsUpdated( 76 VideoSourceRestrictions restrictions, 77 const VideoAdaptationCounters& adaptation_counters, 78 scoped_refptr<Resource> reason, 79 const VideoSourceRestrictions& /* unfiltered_restrictions */) override { 80 RTC_DCHECK_RUN_ON(&sequence_checker_); 81 ++restrictions_updated_count_; 82 restrictions_ = restrictions; 83 adaptation_counters_ = adaptation_counters; 84 reason_ = reason; 85 } 86 87 private: 88 SequenceChecker sequence_checker_; 89 size_t restrictions_updated_count_ RTC_GUARDED_BY(&sequence_checker_); 90 VideoSourceRestrictions restrictions_ RTC_GUARDED_BY(&sequence_checker_); 91 VideoAdaptationCounters adaptation_counters_ 92 RTC_GUARDED_BY(&sequence_checker_); 93 scoped_refptr<Resource> reason_ RTC_GUARDED_BY(&sequence_checker_); 94 }; 95 96 class ResourceAdaptationProcessorTest : public ::testing::Test { 97 public: 98 ResourceAdaptationProcessorTest() 99 : frame_rate_provider_(), 100 input_state_provider_(&frame_rate_provider_), 101 resource_(FakeResource::Create("FakeResource")), 102 other_resource_(FakeResource::Create("OtherFakeResource")), 103 video_stream_adapter_( 104 std::make_unique<VideoStreamAdapter>(&input_state_provider_, 105 &frame_rate_provider_, 106 CreateTestFieldTrials())), 107 processor_(std::make_unique<ResourceAdaptationProcessor>( 108 video_stream_adapter_.get())) { 109 video_stream_adapter_->AddRestrictionsListener(&restrictions_listener_); 110 processor_->AddResource(resource_); 111 processor_->AddResource(other_resource_); 112 } 113 ~ResourceAdaptationProcessorTest() override { 114 if (processor_) { 115 DestroyProcessor(); 116 } 117 } 118 119 void SetInputStates(bool has_input, int fps, int frame_size) { 120 input_state_provider_.OnHasInputChanged(has_input); 121 frame_rate_provider_.set_fps(fps); 122 input_state_provider_.OnFrameSizeObserved(frame_size); 123 } 124 125 void RestrictSource(VideoSourceRestrictions restrictions) { 126 SetInputStates( 127 true, restrictions.max_frame_rate().value_or(kDefaultFrameRate), 128 restrictions.target_pixels_per_frame().has_value() 129 ? restrictions.target_pixels_per_frame().value() 130 : restrictions.max_pixels_per_frame().value_or(kDefaultFrameSize)); 131 } 132 133 void DestroyProcessor() { 134 if (resource_) { 135 processor_->RemoveResource(resource_); 136 } 137 if (other_resource_) { 138 processor_->RemoveResource(other_resource_); 139 } 140 video_stream_adapter_->RemoveRestrictionsListener(&restrictions_listener_); 141 processor_.reset(); 142 } 143 144 static void WaitUntilTaskQueueIdle() { 145 ASSERT_TRUE(Thread::Current()->ProcessMessages(0)); 146 } 147 148 protected: 149 AutoThread main_thread_; 150 FakeFrameRateProvider frame_rate_provider_; 151 VideoStreamInputStateProvider input_state_provider_; 152 scoped_refptr<FakeResource> resource_; 153 scoped_refptr<FakeResource> other_resource_; 154 std::unique_ptr<VideoStreamAdapter> video_stream_adapter_; 155 std::unique_ptr<ResourceAdaptationProcessor> processor_; 156 VideoSourceRestrictionsListenerForTesting restrictions_listener_; 157 }; 158 159 } // namespace 160 161 TEST_F(ResourceAdaptationProcessorTest, DisabledByDefault) { 162 SetInputStates(true, kDefaultFrameRate, kDefaultFrameSize); 163 // Adaptation does not happen when disabled. 164 resource_->SetUsageState(ResourceUsageState::kOveruse); 165 EXPECT_EQ(0u, restrictions_listener_.restrictions_updated_count()); 166 } 167 168 TEST_F(ResourceAdaptationProcessorTest, InsufficientInput) { 169 video_stream_adapter_->SetDegradationPreference( 170 DegradationPreference::MAINTAIN_FRAMERATE); 171 // Adaptation does not happen if input is insufficient. 172 // When frame size is missing (OnFrameSizeObserved not called yet). 173 input_state_provider_.OnHasInputChanged(true); 174 resource_->SetUsageState(ResourceUsageState::kOveruse); 175 EXPECT_EQ(0u, restrictions_listener_.restrictions_updated_count()); 176 // When "has input" is missing. 177 SetInputStates(false, kDefaultFrameRate, kDefaultFrameSize); 178 resource_->SetUsageState(ResourceUsageState::kOveruse); 179 EXPECT_EQ(0u, restrictions_listener_.restrictions_updated_count()); 180 // Note: frame rate cannot be missing, if unset it is 0. 181 } 182 183 // These tests verify that restrictions are applied, but not exactly how much 184 // the source is restricted. This ensures that the VideoStreamAdapter is wired 185 // up correctly but not exactly how the VideoStreamAdapter generates 186 // restrictions. For that, see video_stream_adapter_unittest.cc. 187 TEST_F(ResourceAdaptationProcessorTest, 188 OveruseTriggersRestrictingResolutionInMaintainFrameRate) { 189 video_stream_adapter_->SetDegradationPreference( 190 DegradationPreference::MAINTAIN_FRAMERATE); 191 SetInputStates(true, kDefaultFrameRate, kDefaultFrameSize); 192 resource_->SetUsageState(ResourceUsageState::kOveruse); 193 EXPECT_EQ(1u, restrictions_listener_.restrictions_updated_count()); 194 EXPECT_TRUE( 195 restrictions_listener_.restrictions().max_pixels_per_frame().has_value()); 196 } 197 198 TEST_F(ResourceAdaptationProcessorTest, 199 OveruseTriggersRestrictingFrameRateInMaintainResolution) { 200 video_stream_adapter_->SetDegradationPreference( 201 DegradationPreference::MAINTAIN_RESOLUTION); 202 SetInputStates(true, kDefaultFrameRate, kDefaultFrameSize); 203 resource_->SetUsageState(ResourceUsageState::kOveruse); 204 EXPECT_EQ(1u, restrictions_listener_.restrictions_updated_count()); 205 EXPECT_TRUE( 206 restrictions_listener_.restrictions().max_frame_rate().has_value()); 207 } 208 209 TEST_F(ResourceAdaptationProcessorTest, 210 OveruseTriggersRestrictingFrameRateAndResolutionInBalanced) { 211 video_stream_adapter_->SetDegradationPreference( 212 DegradationPreference::BALANCED); 213 SetInputStates(true, kDefaultFrameRate, kDefaultFrameSize); 214 // Adapting multiple times eventually resticts both frame rate and 215 // resolution. Exactly many times we need to adapt depends on 216 // BalancedDegradationSettings, VideoStreamAdapter and default input 217 // states. This test requires it to be achieved within 4 adaptations. 218 for (size_t i = 0; i < 4; ++i) { 219 resource_->SetUsageState(ResourceUsageState::kOveruse); 220 EXPECT_EQ(i + 1, restrictions_listener_.restrictions_updated_count()); 221 RestrictSource(restrictions_listener_.restrictions()); 222 } 223 EXPECT_TRUE( 224 restrictions_listener_.restrictions().max_pixels_per_frame().has_value()); 225 EXPECT_TRUE( 226 restrictions_listener_.restrictions().max_frame_rate().has_value()); 227 } 228 229 TEST_F(ResourceAdaptationProcessorTest, AwaitingPreviousAdaptation) { 230 video_stream_adapter_->SetDegradationPreference( 231 DegradationPreference::MAINTAIN_FRAMERATE); 232 SetInputStates(true, kDefaultFrameRate, kDefaultFrameSize); 233 resource_->SetUsageState(ResourceUsageState::kOveruse); 234 EXPECT_EQ(1u, restrictions_listener_.restrictions_updated_count()); 235 // If we don't restrict the source then adaptation will not happen again 236 // due to "awaiting previous adaptation". This prevents "double-adapt". 237 resource_->SetUsageState(ResourceUsageState::kOveruse); 238 EXPECT_EQ(1u, restrictions_listener_.restrictions_updated_count()); 239 } 240 241 TEST_F(ResourceAdaptationProcessorTest, CannotAdaptUpWhenUnrestricted) { 242 video_stream_adapter_->SetDegradationPreference( 243 DegradationPreference::MAINTAIN_FRAMERATE); 244 SetInputStates(true, kDefaultFrameRate, kDefaultFrameSize); 245 resource_->SetUsageState(ResourceUsageState::kUnderuse); 246 EXPECT_EQ(0u, restrictions_listener_.restrictions_updated_count()); 247 } 248 249 TEST_F(ResourceAdaptationProcessorTest, UnderuseTakesUsBackToUnrestricted) { 250 video_stream_adapter_->SetDegradationPreference( 251 DegradationPreference::MAINTAIN_FRAMERATE); 252 SetInputStates(true, kDefaultFrameRate, kDefaultFrameSize); 253 resource_->SetUsageState(ResourceUsageState::kOveruse); 254 EXPECT_EQ(1u, restrictions_listener_.restrictions_updated_count()); 255 RestrictSource(restrictions_listener_.restrictions()); 256 resource_->SetUsageState(ResourceUsageState::kUnderuse); 257 EXPECT_EQ(2u, restrictions_listener_.restrictions_updated_count()); 258 EXPECT_EQ(VideoSourceRestrictions(), restrictions_listener_.restrictions()); 259 } 260 261 TEST_F(ResourceAdaptationProcessorTest, 262 ResourcesCanNotAdaptUpIfNeverAdaptedDown) { 263 video_stream_adapter_->SetDegradationPreference( 264 DegradationPreference::MAINTAIN_FRAMERATE); 265 SetInputStates(true, kDefaultFrameRate, kDefaultFrameSize); 266 resource_->SetUsageState(ResourceUsageState::kOveruse); 267 EXPECT_EQ(1u, restrictions_listener_.restrictions_updated_count()); 268 RestrictSource(restrictions_listener_.restrictions()); 269 270 // Other resource signals under-use 271 other_resource_->SetUsageState(ResourceUsageState::kUnderuse); 272 EXPECT_EQ(1u, restrictions_listener_.restrictions_updated_count()); 273 } 274 275 TEST_F(ResourceAdaptationProcessorTest, 276 ResourcesCanNotAdaptUpIfNotAdaptedDownAfterReset) { 277 video_stream_adapter_->SetDegradationPreference( 278 DegradationPreference::MAINTAIN_FRAMERATE); 279 SetInputStates(true, kDefaultFrameRate, kDefaultFrameSize); 280 resource_->SetUsageState(ResourceUsageState::kOveruse); 281 EXPECT_EQ(1u, restrictions_listener_.restrictions_updated_count()); 282 283 video_stream_adapter_->ClearRestrictions(); 284 EXPECT_EQ(0, restrictions_listener_.adaptation_counters().Total()); 285 other_resource_->SetUsageState(ResourceUsageState::kOveruse); 286 EXPECT_EQ(1, restrictions_listener_.adaptation_counters().Total()); 287 RestrictSource(restrictions_listener_.restrictions()); 288 289 // resource_ did not overuse after we reset the restrictions, so adapt 290 // up should be disallowed. 291 resource_->SetUsageState(ResourceUsageState::kUnderuse); 292 EXPECT_EQ(1, restrictions_listener_.adaptation_counters().Total()); 293 } 294 295 TEST_F(ResourceAdaptationProcessorTest, OnlyMostLimitedResourceMayAdaptUp) { 296 video_stream_adapter_->SetDegradationPreference( 297 DegradationPreference::MAINTAIN_FRAMERATE); 298 SetInputStates(true, kDefaultFrameRate, kDefaultFrameSize); 299 resource_->SetUsageState(ResourceUsageState::kOveruse); 300 EXPECT_EQ(1, restrictions_listener_.adaptation_counters().Total()); 301 RestrictSource(restrictions_listener_.restrictions()); 302 other_resource_->SetUsageState(ResourceUsageState::kOveruse); 303 EXPECT_EQ(2, restrictions_listener_.adaptation_counters().Total()); 304 RestrictSource(restrictions_listener_.restrictions()); 305 306 // `other_resource_` is most limited, resource_ can't adapt up. 307 resource_->SetUsageState(ResourceUsageState::kUnderuse); 308 EXPECT_EQ(2, restrictions_listener_.adaptation_counters().Total()); 309 RestrictSource(restrictions_listener_.restrictions()); 310 other_resource_->SetUsageState(ResourceUsageState::kUnderuse); 311 EXPECT_EQ(1, restrictions_listener_.adaptation_counters().Total()); 312 RestrictSource(restrictions_listener_.restrictions()); 313 314 // `resource_` and `other_resource_` are now most limited, so both must 315 // signal underuse to adapt up. 316 other_resource_->SetUsageState(ResourceUsageState::kUnderuse); 317 EXPECT_EQ(1, restrictions_listener_.adaptation_counters().Total()); 318 RestrictSource(restrictions_listener_.restrictions()); 319 resource_->SetUsageState(ResourceUsageState::kUnderuse); 320 EXPECT_EQ(0, restrictions_listener_.adaptation_counters().Total()); 321 RestrictSource(restrictions_listener_.restrictions()); 322 } 323 324 TEST_F(ResourceAdaptationProcessorTest, 325 MultipleResourcesCanTriggerMultipleAdaptations) { 326 video_stream_adapter_->SetDegradationPreference( 327 DegradationPreference::MAINTAIN_FRAMERATE); 328 SetInputStates(true, kDefaultFrameRate, kDefaultFrameSize); 329 resource_->SetUsageState(ResourceUsageState::kOveruse); 330 EXPECT_EQ(1, restrictions_listener_.adaptation_counters().Total()); 331 RestrictSource(restrictions_listener_.restrictions()); 332 other_resource_->SetUsageState(ResourceUsageState::kOveruse); 333 EXPECT_EQ(2, restrictions_listener_.adaptation_counters().Total()); 334 RestrictSource(restrictions_listener_.restrictions()); 335 other_resource_->SetUsageState(ResourceUsageState::kOveruse); 336 EXPECT_EQ(3, restrictions_listener_.adaptation_counters().Total()); 337 RestrictSource(restrictions_listener_.restrictions()); 338 339 // resource_ is not most limited so can't adapt from underuse. 340 resource_->SetUsageState(ResourceUsageState::kUnderuse); 341 EXPECT_EQ(3, restrictions_listener_.adaptation_counters().Total()); 342 RestrictSource(restrictions_listener_.restrictions()); 343 other_resource_->SetUsageState(ResourceUsageState::kUnderuse); 344 EXPECT_EQ(2, restrictions_listener_.adaptation_counters().Total()); 345 RestrictSource(restrictions_listener_.restrictions()); 346 // resource_ is still not most limited so can't adapt from underuse. 347 resource_->SetUsageState(ResourceUsageState::kUnderuse); 348 EXPECT_EQ(2, restrictions_listener_.adaptation_counters().Total()); 349 RestrictSource(restrictions_listener_.restrictions()); 350 351 // However it will be after overuse 352 resource_->SetUsageState(ResourceUsageState::kOveruse); 353 EXPECT_EQ(3, restrictions_listener_.adaptation_counters().Total()); 354 RestrictSource(restrictions_listener_.restrictions()); 355 356 // Now other_resource_ can't adapt up as it is not most restricted. 357 other_resource_->SetUsageState(ResourceUsageState::kUnderuse); 358 EXPECT_EQ(3, restrictions_listener_.adaptation_counters().Total()); 359 RestrictSource(restrictions_listener_.restrictions()); 360 361 // resource_ is limited at 3 adaptations and other_resource_ 2. 362 // With the most limited resource signalling underuse in the following 363 // order we get back to unrestricted video. 364 resource_->SetUsageState(ResourceUsageState::kUnderuse); 365 EXPECT_EQ(2, restrictions_listener_.adaptation_counters().Total()); 366 RestrictSource(restrictions_listener_.restrictions()); 367 // Both resource_ and other_resource_ are most limited. 368 other_resource_->SetUsageState(ResourceUsageState::kUnderuse); 369 EXPECT_EQ(2, restrictions_listener_.adaptation_counters().Total()); 370 RestrictSource(restrictions_listener_.restrictions()); 371 resource_->SetUsageState(ResourceUsageState::kUnderuse); 372 EXPECT_EQ(1, restrictions_listener_.adaptation_counters().Total()); 373 RestrictSource(restrictions_listener_.restrictions()); 374 // Again both are most limited. 375 resource_->SetUsageState(ResourceUsageState::kUnderuse); 376 EXPECT_EQ(1, restrictions_listener_.adaptation_counters().Total()); 377 RestrictSource(restrictions_listener_.restrictions()); 378 other_resource_->SetUsageState(ResourceUsageState::kUnderuse); 379 EXPECT_EQ(0, restrictions_listener_.adaptation_counters().Total()); 380 } 381 382 TEST_F(ResourceAdaptationProcessorTest, 383 MostLimitedResourceAdaptationWorksAfterChangingDegradataionPreference) { 384 video_stream_adapter_->SetDegradationPreference( 385 DegradationPreference::MAINTAIN_FRAMERATE); 386 SetInputStates(true, kDefaultFrameRate, kDefaultFrameSize); 387 // Adapt down until we can't anymore. 388 resource_->SetUsageState(ResourceUsageState::kOveruse); 389 RestrictSource(restrictions_listener_.restrictions()); 390 resource_->SetUsageState(ResourceUsageState::kOveruse); 391 RestrictSource(restrictions_listener_.restrictions()); 392 resource_->SetUsageState(ResourceUsageState::kOveruse); 393 RestrictSource(restrictions_listener_.restrictions()); 394 resource_->SetUsageState(ResourceUsageState::kOveruse); 395 RestrictSource(restrictions_listener_.restrictions()); 396 resource_->SetUsageState(ResourceUsageState::kOveruse); 397 RestrictSource(restrictions_listener_.restrictions()); 398 int last_total = restrictions_listener_.adaptation_counters().Total(); 399 400 video_stream_adapter_->SetDegradationPreference( 401 DegradationPreference::MAINTAIN_RESOLUTION); 402 // resource_ can not adapt up since we have never reduced FPS. 403 resource_->SetUsageState(ResourceUsageState::kUnderuse); 404 EXPECT_EQ(last_total, restrictions_listener_.adaptation_counters().Total()); 405 406 other_resource_->SetUsageState(ResourceUsageState::kOveruse); 407 EXPECT_EQ(last_total + 1, 408 restrictions_listener_.adaptation_counters().Total()); 409 RestrictSource(restrictions_listener_.restrictions()); 410 // other_resource_ is most limited so should be able to adapt up. 411 other_resource_->SetUsageState(ResourceUsageState::kUnderuse); 412 EXPECT_EQ(last_total, restrictions_listener_.adaptation_counters().Total()); 413 } 414 415 TEST_F(ResourceAdaptationProcessorTest, 416 AdaptsDownWhenOtherResourceIsAlwaysUnderused) { 417 video_stream_adapter_->SetDegradationPreference( 418 DegradationPreference::MAINTAIN_FRAMERATE); 419 SetInputStates(true, kDefaultFrameRate, kDefaultFrameSize); 420 other_resource_->SetUsageState(ResourceUsageState::kUnderuse); 421 // Does not trigger adapataion because there's no restriction. 422 EXPECT_EQ(0, restrictions_listener_.adaptation_counters().Total()); 423 424 RestrictSource(restrictions_listener_.restrictions()); 425 resource_->SetUsageState(ResourceUsageState::kOveruse); 426 // Adapts down even if other resource asked for adapting up. 427 EXPECT_EQ(1, restrictions_listener_.adaptation_counters().Total()); 428 429 RestrictSource(restrictions_listener_.restrictions()); 430 other_resource_->SetUsageState(ResourceUsageState::kUnderuse); 431 // Doesn't adapt up because adaptation is due to another resource. 432 EXPECT_EQ(1, restrictions_listener_.adaptation_counters().Total()); 433 RestrictSource(restrictions_listener_.restrictions()); 434 } 435 436 TEST_F(ResourceAdaptationProcessorTest, 437 TriggerOveruseNotOnAdaptationTaskQueue) { 438 video_stream_adapter_->SetDegradationPreference( 439 DegradationPreference::MAINTAIN_FRAMERATE); 440 SetInputStates(true, kDefaultFrameRate, kDefaultFrameSize); 441 442 TaskQueueForTest resource_task_queue("ResourceTaskQueue"); 443 resource_task_queue.PostTask( 444 [&]() { resource_->SetUsageState(ResourceUsageState::kOveruse); }); 445 446 EXPECT_THAT( 447 WaitUntil( 448 [&] { return restrictions_listener_.restrictions_updated_count(); }, 449 Eq(1u)), 450 IsRtcOk()); 451 } 452 453 TEST_F(ResourceAdaptationProcessorTest, 454 DestroyProcessorWhileResourceListenerDelegateHasTaskInFlight) { 455 video_stream_adapter_->SetDegradationPreference( 456 DegradationPreference::MAINTAIN_FRAMERATE); 457 SetInputStates(true, kDefaultFrameRate, kDefaultFrameSize); 458 459 // Wait for `resource_` to signal oversue first so we know that the delegate 460 // has passed it on to the processor's task queue. 461 Event resource_event; 462 TaskQueueForTest resource_task_queue("ResourceTaskQueue"); 463 resource_task_queue.PostTask([&]() { 464 resource_->SetUsageState(ResourceUsageState::kOveruse); 465 resource_event.Set(); 466 }); 467 468 EXPECT_TRUE(resource_event.Wait(kDefaultTimeout)); 469 // Now destroy the processor while handling the overuse is in flight. 470 DestroyProcessor(); 471 472 // Because the processor was destroyed by the time the delegate's task ran, 473 // the overuse signal must not have been handled. 474 EXPECT_EQ(0u, restrictions_listener_.restrictions_updated_count()); 475 } 476 477 TEST_F(ResourceAdaptationProcessorTest, 478 ResourceOveruseIgnoredWhenSignalledDuringRemoval) { 479 video_stream_adapter_->SetDegradationPreference( 480 DegradationPreference::MAINTAIN_FRAMERATE); 481 SetInputStates(true, kDefaultFrameRate, kDefaultFrameSize); 482 483 Event overuse_event; 484 TaskQueueForTest resource_task_queue("ResourceTaskQueue"); 485 // Queues task for `resource_` overuse while `processor_` is still listening. 486 resource_task_queue.PostTask([&]() { 487 resource_->SetUsageState(ResourceUsageState::kOveruse); 488 overuse_event.Set(); 489 }); 490 EXPECT_TRUE(overuse_event.Wait(kDefaultTimeout)); 491 // Once we know the overuse task is queued, remove `resource_` so that 492 // `processor_` is not listening to it. 493 processor_->RemoveResource(resource_); 494 495 // Runs the queued task so `processor_` gets signalled kOveruse from 496 // `resource_` even though `processor_` was not listening. 497 WaitUntilTaskQueueIdle(); 498 499 // No restrictions should change even though `resource_` signaled `kOveruse`. 500 EXPECT_EQ(0u, restrictions_listener_.restrictions_updated_count()); 501 502 // Delete `resource_` for cleanup. 503 resource_ = nullptr; 504 } 505 506 TEST_F(ResourceAdaptationProcessorTest, 507 RemovingOnlyAdaptedResourceResetsAdaptation) { 508 video_stream_adapter_->SetDegradationPreference( 509 DegradationPreference::MAINTAIN_FRAMERATE); 510 SetInputStates(true, kDefaultFrameRate, kDefaultFrameSize); 511 512 resource_->SetUsageState(ResourceUsageState::kOveruse); 513 EXPECT_EQ(1, restrictions_listener_.adaptation_counters().Total()); 514 RestrictSource(restrictions_listener_.restrictions()); 515 516 processor_->RemoveResource(resource_); 517 EXPECT_EQ(0, restrictions_listener_.adaptation_counters().Total()); 518 519 // Delete `resource_` for cleanup. 520 resource_ = nullptr; 521 } 522 523 TEST_F(ResourceAdaptationProcessorTest, 524 RemovingMostLimitedResourceSetsAdaptationToNextLimitedLevel) { 525 video_stream_adapter_->SetDegradationPreference( 526 DegradationPreference::BALANCED); 527 SetInputStates(true, kDefaultFrameRate, kDefaultFrameSize); 528 529 other_resource_->SetUsageState(ResourceUsageState::kOveruse); 530 RestrictSource(restrictions_listener_.restrictions()); 531 EXPECT_EQ(1, restrictions_listener_.adaptation_counters().Total()); 532 VideoSourceRestrictions next_limited_restrictions = 533 restrictions_listener_.restrictions(); 534 VideoAdaptationCounters next_limited_counters = 535 restrictions_listener_.adaptation_counters(); 536 537 resource_->SetUsageState(ResourceUsageState::kOveruse); 538 RestrictSource(restrictions_listener_.restrictions()); 539 EXPECT_EQ(2, restrictions_listener_.adaptation_counters().Total()); 540 541 // Removing most limited `resource_` should revert us back to 542 processor_->RemoveResource(resource_); 543 EXPECT_EQ(1, restrictions_listener_.adaptation_counters().Total()); 544 EXPECT_EQ(next_limited_restrictions, restrictions_listener_.restrictions()); 545 EXPECT_EQ(next_limited_counters, 546 restrictions_listener_.adaptation_counters()); 547 548 // Delete `resource_` for cleanup. 549 resource_ = nullptr; 550 } 551 552 TEST_F(ResourceAdaptationProcessorTest, 553 RemovingMostLimitedResourceSetsAdaptationIfInputStateUnchanged) { 554 video_stream_adapter_->SetDegradationPreference( 555 DegradationPreference::MAINTAIN_FRAMERATE); 556 SetInputStates(true, kDefaultFrameRate, kDefaultFrameSize); 557 558 other_resource_->SetUsageState(ResourceUsageState::kOveruse); 559 RestrictSource(restrictions_listener_.restrictions()); 560 EXPECT_EQ(1, restrictions_listener_.adaptation_counters().Total()); 561 VideoSourceRestrictions next_limited_restrictions = 562 restrictions_listener_.restrictions(); 563 VideoAdaptationCounters next_limited_counters = 564 restrictions_listener_.adaptation_counters(); 565 566 // Overuse twice and underuse once. After the underuse we don't restrict the 567 // source. Normally this would block future underuses. 568 resource_->SetUsageState(ResourceUsageState::kOveruse); 569 RestrictSource(restrictions_listener_.restrictions()); 570 resource_->SetUsageState(ResourceUsageState::kOveruse); 571 RestrictSource(restrictions_listener_.restrictions()); 572 resource_->SetUsageState(ResourceUsageState::kUnderuse); 573 EXPECT_EQ(2, restrictions_listener_.adaptation_counters().Total()); 574 575 // Removing most limited `resource_` should revert us back to, even though we 576 // did not call RestrictSource() after `resource_` was overused. Normally 577 // adaptation for MAINTAIN_FRAMERATE would be blocked here but for removal we 578 // allow this anyways. 579 processor_->RemoveResource(resource_); 580 EXPECT_EQ(1, restrictions_listener_.adaptation_counters().Total()); 581 EXPECT_EQ(next_limited_restrictions, restrictions_listener_.restrictions()); 582 EXPECT_EQ(next_limited_counters, 583 restrictions_listener_.adaptation_counters()); 584 585 // Delete `resource_` for cleanup. 586 resource_ = nullptr; 587 } 588 589 TEST_F(ResourceAdaptationProcessorTest, 590 RemovingResourceNotMostLimitedHasNoEffectOnLimitations) { 591 video_stream_adapter_->SetDegradationPreference( 592 DegradationPreference::BALANCED); 593 SetInputStates(true, kDefaultFrameRate, kDefaultFrameSize); 594 595 other_resource_->SetUsageState(ResourceUsageState::kOveruse); 596 RestrictSource(restrictions_listener_.restrictions()); 597 EXPECT_EQ(1, restrictions_listener_.adaptation_counters().Total()); 598 599 resource_->SetUsageState(ResourceUsageState::kOveruse); 600 RestrictSource(restrictions_listener_.restrictions()); 601 VideoSourceRestrictions current_restrictions = 602 restrictions_listener_.restrictions(); 603 VideoAdaptationCounters current_counters = 604 restrictions_listener_.adaptation_counters(); 605 EXPECT_EQ(2, restrictions_listener_.adaptation_counters().Total()); 606 607 // Removing most limited `resource_` should revert us back to 608 processor_->RemoveResource(other_resource_); 609 EXPECT_EQ(current_restrictions, restrictions_listener_.restrictions()); 610 EXPECT_EQ(current_counters, restrictions_listener_.adaptation_counters()); 611 612 // Delete `other_resource_` for cleanup. 613 other_resource_ = nullptr; 614 } 615 616 TEST_F(ResourceAdaptationProcessorTest, 617 RemovingMostLimitedResourceAfterSwitchingDegradationPreferences) { 618 video_stream_adapter_->SetDegradationPreference( 619 DegradationPreference::MAINTAIN_FRAMERATE); 620 SetInputStates(true, kDefaultFrameRate, kDefaultFrameSize); 621 622 other_resource_->SetUsageState(ResourceUsageState::kOveruse); 623 RestrictSource(restrictions_listener_.restrictions()); 624 EXPECT_EQ(1, restrictions_listener_.adaptation_counters().Total()); 625 VideoSourceRestrictions next_limited_restrictions = 626 restrictions_listener_.restrictions(); 627 VideoAdaptationCounters next_limited_counters = 628 restrictions_listener_.adaptation_counters(); 629 630 video_stream_adapter_->SetDegradationPreference( 631 DegradationPreference::MAINTAIN_RESOLUTION); 632 resource_->SetUsageState(ResourceUsageState::kOveruse); 633 RestrictSource(restrictions_listener_.restrictions()); 634 EXPECT_EQ(2, restrictions_listener_.adaptation_counters().Total()); 635 636 // Revert to `other_resource_` when removing `resource_` even though the 637 // degradation preference was different when it was overused. 638 processor_->RemoveResource(resource_); 639 EXPECT_EQ(next_limited_counters, 640 restrictions_listener_.adaptation_counters()); 641 642 // After switching back to MAINTAIN_FRAMERATE, the next most limited settings 643 // are restored. 644 video_stream_adapter_->SetDegradationPreference( 645 DegradationPreference::MAINTAIN_FRAMERATE); 646 EXPECT_EQ(next_limited_restrictions, restrictions_listener_.restrictions()); 647 648 // Delete `resource_` for cleanup. 649 resource_ = nullptr; 650 } 651 652 TEST_F(ResourceAdaptationProcessorTest, 653 RemovingMostLimitedResourceSetsNextLimitationsInDisabled) { 654 video_stream_adapter_->SetDegradationPreference( 655 DegradationPreference::MAINTAIN_FRAMERATE); 656 SetInputStates(true, kDefaultFrameRate, kDefaultFrameSize); 657 658 other_resource_->SetUsageState(ResourceUsageState::kOveruse); 659 RestrictSource(restrictions_listener_.restrictions()); 660 VideoSourceRestrictions next_limited_restrictions = 661 restrictions_listener_.restrictions(); 662 VideoAdaptationCounters next_limited_counters = 663 restrictions_listener_.adaptation_counters(); 664 EXPECT_EQ(1, restrictions_listener_.adaptation_counters().Total()); 665 resource_->SetUsageState(ResourceUsageState::kOveruse); 666 RestrictSource(restrictions_listener_.restrictions()); 667 EXPECT_EQ(2, restrictions_listener_.adaptation_counters().Total()); 668 669 video_stream_adapter_->SetDegradationPreference( 670 DegradationPreference::DISABLED); 671 672 // Revert to `other_resource_` when removing `resource_` even though the 673 // current degradataion preference is disabled. 674 processor_->RemoveResource(resource_); 675 676 // After switching back to MAINTAIN_FRAMERATE, the next most limited settings 677 // are restored. 678 video_stream_adapter_->SetDegradationPreference( 679 DegradationPreference::MAINTAIN_FRAMERATE); 680 EXPECT_EQ(next_limited_restrictions, restrictions_listener_.restrictions()); 681 EXPECT_EQ(next_limited_counters, 682 restrictions_listener_.adaptation_counters()); 683 684 // Delete `resource_` for cleanup. 685 resource_ = nullptr; 686 } 687 688 TEST_F(ResourceAdaptationProcessorTest, 689 RemovedResourceSignalsIgnoredByProcessor) { 690 video_stream_adapter_->SetDegradationPreference( 691 DegradationPreference::MAINTAIN_FRAMERATE); 692 SetInputStates(true, kDefaultFrameRate, kDefaultFrameSize); 693 694 processor_->RemoveResource(resource_); 695 resource_->SetUsageState(ResourceUsageState::kOveruse); 696 EXPECT_EQ(0u, restrictions_listener_.restrictions_updated_count()); 697 698 // Delete `resource_` for cleanup. 699 resource_ = nullptr; 700 } 701 702 TEST_F(ResourceAdaptationProcessorTest, 703 RemovingResourceWhenMultipleMostLimtedHasNoEffect) { 704 video_stream_adapter_->SetDegradationPreference( 705 DegradationPreference::MAINTAIN_FRAMERATE); 706 SetInputStates(true, kDefaultFrameRate, kDefaultFrameSize); 707 708 other_resource_->SetUsageState(ResourceUsageState::kOveruse); 709 RestrictSource(restrictions_listener_.restrictions()); 710 EXPECT_EQ(1, restrictions_listener_.adaptation_counters().Total()); 711 // Adapt `resource_` up and then down so that both resource's are most 712 // limited at 1 adaptation. 713 resource_->SetUsageState(ResourceUsageState::kOveruse); 714 RestrictSource(restrictions_listener_.restrictions()); 715 resource_->SetUsageState(ResourceUsageState::kUnderuse); 716 RestrictSource(restrictions_listener_.restrictions()); 717 EXPECT_EQ(1, restrictions_listener_.adaptation_counters().Total()); 718 719 // Removing `resource_` has no effect since both `resource_` and 720 // `other_resource_` are most limited. 721 processor_->RemoveResource(resource_); 722 EXPECT_EQ(1, restrictions_listener_.adaptation_counters().Total()); 723 724 // Delete `resource_` for cleanup. 725 resource_ = nullptr; 726 } 727 728 TEST_F(ResourceAdaptationProcessorTest, 729 ResourceOverusedAtLimitReachedWillShareMostLimited) { 730 video_stream_adapter_->SetDegradationPreference( 731 DegradationPreference::MAINTAIN_FRAMERATE); 732 SetInputStates(true, kDefaultFrameRate, kDefaultFrameSize); 733 734 bool has_reached_min_pixels = false; 735 ON_CALL(frame_rate_provider_, OnMinPixelLimitReached()) 736 .WillByDefault(testing::Assign(&has_reached_min_pixels, true)); 737 738 // Adapt 10 times, which should make us hit the limit. 739 for (int i = 0; i < 10; ++i) { 740 resource_->SetUsageState(ResourceUsageState::kOveruse); 741 RestrictSource(restrictions_listener_.restrictions()); 742 } 743 EXPECT_TRUE(has_reached_min_pixels); 744 auto last_update_count = restrictions_listener_.restrictions_updated_count(); 745 other_resource_->SetUsageState(ResourceUsageState::kOveruse); 746 // Now both `resource_` and `other_resource_` are most limited. Underuse of 747 // `resource_` will not adapt up. 748 resource_->SetUsageState(ResourceUsageState::kUnderuse); 749 EXPECT_EQ(last_update_count, 750 restrictions_listener_.restrictions_updated_count()); 751 } 752 753 } // namespace webrtc