/* * Copyright 2020 The WebRTC Project Authors. All rights reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "video/adaptation/pixel_limit_resource.h" #include "api/sequence_checker.h" #include "api/units/time_delta.h" #include "call/adaptation/video_stream_adapter.h" #include "rtc_base/checks.h" #include "rtc_base/ref_counted_object.h" namespace webrtc { namespace { constexpr TimeDelta kResourceUsageCheckIntervalMs = TimeDelta::Seconds(5); } // namespace // static rtc::scoped_refptr PixelLimitResource::Create( TaskQueueBase* task_queue, VideoStreamInputStateProvider* input_state_provider) { return rtc::make_ref_counted(task_queue, input_state_provider); } PixelLimitResource::PixelLimitResource( TaskQueueBase* task_queue, VideoStreamInputStateProvider* input_state_provider) : task_queue_(task_queue), input_state_provider_(input_state_provider), max_pixels_(absl::nullopt) { RTC_DCHECK(task_queue_); RTC_DCHECK(input_state_provider_); } PixelLimitResource::~PixelLimitResource() { RTC_DCHECK(!listener_); RTC_DCHECK(!repeating_task_.Running()); } void PixelLimitResource::SetMaxPixels(int max_pixels) { RTC_DCHECK_RUN_ON(task_queue_); max_pixels_ = max_pixels; } void PixelLimitResource::SetResourceListener(ResourceListener* listener) { RTC_DCHECK_RUN_ON(task_queue_); listener_ = listener; if (listener_) { repeating_task_.Stop(); repeating_task_ = RepeatingTaskHandle::Start(task_queue_, [&] { RTC_DCHECK_RUN_ON(task_queue_); if (!listener_) { // We don't have a listener so resource adaptation must not be running, // try again later. return kResourceUsageCheckIntervalMs; } if (!max_pixels_.has_value()) { // No pixel limit configured yet, try again later. return kResourceUsageCheckIntervalMs; } absl::optional frame_size_pixels = input_state_provider_->InputState().frame_size_pixels(); if (!frame_size_pixels.has_value()) { // We haven't observed a frame yet so we don't know if it's going to be // too big or too small, try again later. return kResourceUsageCheckIntervalMs; } int current_pixels = frame_size_pixels.value(); int target_pixel_upper_bounds = max_pixels_.value(); // To avoid toggling, we allow any resolutions between // `target_pixel_upper_bounds` and video_stream_adapter.h's // GetLowerResolutionThan(). This is the pixels we end up if we adapt down // from `target_pixel_upper_bounds`. int target_pixels_lower_bounds = GetLowerResolutionThan(target_pixel_upper_bounds); if (current_pixels > target_pixel_upper_bounds) { listener_->OnResourceUsageStateMeasured(this, ResourceUsageState::kOveruse); } else if (current_pixels < target_pixels_lower_bounds) { listener_->OnResourceUsageStateMeasured(this, ResourceUsageState::kUnderuse); } return kResourceUsageCheckIntervalMs; }); } else { repeating_task_.Stop(); } // The task must be running if we have a listener. RTC_DCHECK(repeating_task_.Running() || !listener_); } } // namespace webrtc