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 "video/adaptation/pixel_limit_resource.h"
12
13 #include "api/sequence_checker.h"
14 #include "api/units/time_delta.h"
15 #include "call/adaptation/video_stream_adapter.h"
16 #include "rtc_base/checks.h"
17
18 namespace webrtc {
19
20 namespace {
21
22 constexpr TimeDelta kResourceUsageCheckIntervalMs = TimeDelta::Seconds(5);
23
24 } // namespace
25
26 // static
Create(TaskQueueBase * task_queue,VideoStreamInputStateProvider * input_state_provider)27 rtc::scoped_refptr<PixelLimitResource> PixelLimitResource::Create(
28 TaskQueueBase* task_queue,
29 VideoStreamInputStateProvider* input_state_provider) {
30 return rtc::make_ref_counted<PixelLimitResource>(task_queue,
31 input_state_provider);
32 }
33
PixelLimitResource(TaskQueueBase * task_queue,VideoStreamInputStateProvider * input_state_provider)34 PixelLimitResource::PixelLimitResource(
35 TaskQueueBase* task_queue,
36 VideoStreamInputStateProvider* input_state_provider)
37 : task_queue_(task_queue),
38 input_state_provider_(input_state_provider),
39 max_pixels_(absl::nullopt) {
40 RTC_DCHECK(task_queue_);
41 RTC_DCHECK(input_state_provider_);
42 }
43
~PixelLimitResource()44 PixelLimitResource::~PixelLimitResource() {
45 RTC_DCHECK(!listener_);
46 RTC_DCHECK(!repeating_task_.Running());
47 }
48
SetMaxPixels(int max_pixels)49 void PixelLimitResource::SetMaxPixels(int max_pixels) {
50 RTC_DCHECK_RUN_ON(task_queue_);
51 max_pixels_ = max_pixels;
52 }
53
SetResourceListener(ResourceListener * listener)54 void PixelLimitResource::SetResourceListener(ResourceListener* listener) {
55 RTC_DCHECK_RUN_ON(task_queue_);
56 listener_ = listener;
57 if (listener_) {
58 repeating_task_.Stop();
59 repeating_task_ = RepeatingTaskHandle::Start(task_queue_, [&] {
60 RTC_DCHECK_RUN_ON(task_queue_);
61 if (!listener_) {
62 // We don't have a listener so resource adaptation must not be running,
63 // try again later.
64 return kResourceUsageCheckIntervalMs;
65 }
66 if (!max_pixels_.has_value()) {
67 // No pixel limit configured yet, try again later.
68 return kResourceUsageCheckIntervalMs;
69 }
70 absl::optional<int> frame_size_pixels =
71 input_state_provider_->InputState().frame_size_pixels();
72 if (!frame_size_pixels.has_value()) {
73 // We haven't observed a frame yet so we don't know if it's going to be
74 // too big or too small, try again later.
75 return kResourceUsageCheckIntervalMs;
76 }
77 int current_pixels = frame_size_pixels.value();
78 int target_pixel_upper_bounds = max_pixels_.value();
79 // To avoid toggling, we allow any resolutions between
80 // `target_pixel_upper_bounds` and video_stream_adapter.h's
81 // GetLowerResolutionThan(). This is the pixels we end up if we adapt down
82 // from `target_pixel_upper_bounds`.
83 int target_pixels_lower_bounds =
84 GetLowerResolutionThan(target_pixel_upper_bounds);
85 if (current_pixels > target_pixel_upper_bounds) {
86 listener_->OnResourceUsageStateMeasured(
87 rtc::scoped_refptr<Resource>(this), ResourceUsageState::kOveruse);
88 } else if (current_pixels < target_pixels_lower_bounds) {
89 listener_->OnResourceUsageStateMeasured(
90 rtc::scoped_refptr<Resource>(this), ResourceUsageState::kUnderuse);
91 }
92 return kResourceUsageCheckIntervalMs;
93 });
94 } else {
95 repeating_task_.Stop();
96 }
97 // The task must be running if we have a listener.
98 RTC_DCHECK(repeating_task_.Running() || !listener_);
99 }
100
101 } // namespace webrtc
102