2020-04-17 18:36:19 +02:00
|
|
|
/*
|
|
|
|
|
* 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 "call/adaptation/resource_adaptation_processor.h"
|
|
|
|
|
|
2020-05-11 16:29:22 +02:00
|
|
|
#include <algorithm>
|
2020-05-28 16:22:42 +02:00
|
|
|
#include <string>
|
2020-04-17 18:36:19 +02:00
|
|
|
#include <utility>
|
|
|
|
|
|
|
|
|
|
#include "absl/algorithm/container.h"
|
2020-05-28 16:22:42 +02:00
|
|
|
#include "rtc_base/logging.h"
|
|
|
|
|
#include "rtc_base/strings/string_builder.h"
|
2020-04-17 18:36:19 +02:00
|
|
|
|
|
|
|
|
namespace webrtc {
|
|
|
|
|
|
2020-05-28 16:22:42 +02:00
|
|
|
ResourceAdaptationProcessor::MitigationResultAndLogMessage::
|
|
|
|
|
MitigationResultAndLogMessage()
|
|
|
|
|
: result(MitigationResult::kAdaptationApplied), message() {}
|
|
|
|
|
|
|
|
|
|
ResourceAdaptationProcessor::MitigationResultAndLogMessage::
|
|
|
|
|
MitigationResultAndLogMessage(MitigationResult result, std::string message)
|
|
|
|
|
: result(result), message(std::move(message)) {}
|
|
|
|
|
|
2020-04-17 18:36:19 +02:00
|
|
|
ResourceAdaptationProcessor::ResourceAdaptationProcessor(
|
|
|
|
|
VideoStreamInputStateProvider* input_state_provider,
|
|
|
|
|
VideoStreamEncoderObserver* encoder_stats_observer)
|
2020-05-11 16:29:22 +02:00
|
|
|
: sequence_checker_(),
|
|
|
|
|
is_resource_adaptation_enabled_(false),
|
|
|
|
|
input_state_provider_(input_state_provider),
|
2020-04-17 18:36:19 +02:00
|
|
|
encoder_stats_observer_(encoder_stats_observer),
|
|
|
|
|
resources_(),
|
|
|
|
|
degradation_preference_(DegradationPreference::DISABLED),
|
|
|
|
|
effective_degradation_preference_(DegradationPreference::DISABLED),
|
|
|
|
|
is_screenshare_(false),
|
|
|
|
|
stream_adapter_(std::make_unique<VideoStreamAdapter>()),
|
2020-04-28 12:24:33 +02:00
|
|
|
last_reported_source_restrictions_(),
|
2020-05-28 16:22:42 +02:00
|
|
|
previous_mitigation_results_(),
|
2020-05-11 16:29:22 +02:00
|
|
|
processing_in_progress_(false) {
|
|
|
|
|
sequence_checker_.Detach();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ResourceAdaptationProcessor::~ResourceAdaptationProcessor() {
|
|
|
|
|
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
|
|
|
|
RTC_DCHECK(!is_resource_adaptation_enabled_);
|
|
|
|
|
RTC_DCHECK(adaptation_listeners_.empty())
|
|
|
|
|
<< "There are listener(s) depending on a ResourceAdaptationProcessor "
|
|
|
|
|
<< "being destroyed.";
|
|
|
|
|
RTC_DCHECK(resources_.empty())
|
|
|
|
|
<< "There are resource(s) attached to a ResourceAdaptationProcessor "
|
|
|
|
|
<< "being destroyed.";
|
|
|
|
|
}
|
2020-04-17 18:36:19 +02:00
|
|
|
|
2020-05-11 16:29:22 +02:00
|
|
|
void ResourceAdaptationProcessor::InitializeOnResourceAdaptationQueue() {
|
|
|
|
|
// Allows |sequence_checker_| to attach to the resource adaptation queue.
|
|
|
|
|
// The caller is responsible for ensuring that this is the current queue.
|
|
|
|
|
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
|
|
|
|
}
|
2020-04-17 18:36:19 +02:00
|
|
|
|
|
|
|
|
DegradationPreference ResourceAdaptationProcessor::degradation_preference()
|
|
|
|
|
const {
|
2020-05-11 16:29:22 +02:00
|
|
|
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
2020-04-17 18:36:19 +02:00
|
|
|
return degradation_preference_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DegradationPreference
|
|
|
|
|
ResourceAdaptationProcessor::effective_degradation_preference() const {
|
2020-05-11 16:29:22 +02:00
|
|
|
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
2020-04-17 18:36:19 +02:00
|
|
|
return effective_degradation_preference_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ResourceAdaptationProcessor::StartResourceAdaptation() {
|
2020-05-11 16:29:22 +02:00
|
|
|
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
|
|
|
|
if (is_resource_adaptation_enabled_)
|
|
|
|
|
return;
|
|
|
|
|
for (const auto& resource : resources_) {
|
2020-04-20 12:04:12 +02:00
|
|
|
resource->SetResourceListener(this);
|
2020-04-17 18:36:19 +02:00
|
|
|
}
|
2020-05-11 16:29:22 +02:00
|
|
|
is_resource_adaptation_enabled_ = true;
|
2020-04-17 18:36:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ResourceAdaptationProcessor::StopResourceAdaptation() {
|
2020-05-11 16:29:22 +02:00
|
|
|
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
|
|
|
|
if (!is_resource_adaptation_enabled_)
|
|
|
|
|
return;
|
|
|
|
|
for (const auto& resource : resources_) {
|
2020-04-20 12:04:12 +02:00
|
|
|
resource->SetResourceListener(nullptr);
|
2020-04-17 18:36:19 +02:00
|
|
|
}
|
2020-05-11 16:29:22 +02:00
|
|
|
is_resource_adaptation_enabled_ = false;
|
2020-04-17 18:36:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ResourceAdaptationProcessor::AddAdaptationListener(
|
|
|
|
|
ResourceAdaptationProcessorListener* adaptation_listener) {
|
2020-05-11 16:29:22 +02:00
|
|
|
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
|
|
|
|
RTC_DCHECK(std::find(adaptation_listeners_.begin(),
|
|
|
|
|
adaptation_listeners_.end(),
|
|
|
|
|
adaptation_listener) == adaptation_listeners_.end());
|
2020-04-17 18:36:19 +02:00
|
|
|
adaptation_listeners_.push_back(adaptation_listener);
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-11 16:29:22 +02:00
|
|
|
void ResourceAdaptationProcessor::RemoveAdaptationListener(
|
|
|
|
|
ResourceAdaptationProcessorListener* adaptation_listener) {
|
|
|
|
|
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
|
|
|
|
auto it = std::find(adaptation_listeners_.begin(),
|
|
|
|
|
adaptation_listeners_.end(), adaptation_listener);
|
|
|
|
|
RTC_DCHECK(it != adaptation_listeners_.end());
|
|
|
|
|
adaptation_listeners_.erase(it);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ResourceAdaptationProcessor::AddResource(
|
|
|
|
|
rtc::scoped_refptr<Resource> resource) {
|
|
|
|
|
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
|
|
|
|
// TODO(hbos): Allow adding resources while |is_resource_adaptation_enabled_|
|
|
|
|
|
// by registering as a listener of the resource on adding it.
|
|
|
|
|
RTC_DCHECK(!is_resource_adaptation_enabled_);
|
|
|
|
|
RTC_DCHECK(std::find(resources_.begin(), resources_.end(), resource) ==
|
|
|
|
|
resources_.end());
|
2020-04-17 18:36:19 +02:00
|
|
|
resources_.push_back(resource);
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-11 16:29:22 +02:00
|
|
|
void ResourceAdaptationProcessor::RemoveResource(
|
|
|
|
|
rtc::scoped_refptr<Resource> resource) {
|
|
|
|
|
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
|
|
|
|
// TODO(hbos): Allow removing resources while
|
|
|
|
|
// |is_resource_adaptation_enabled_| by unregistering as a listener of the
|
|
|
|
|
// resource on removing it.
|
|
|
|
|
RTC_DCHECK(!is_resource_adaptation_enabled_);
|
|
|
|
|
auto it = std::find(resources_.begin(), resources_.end(), resource);
|
|
|
|
|
RTC_DCHECK(it != resources_.end());
|
|
|
|
|
resources_.erase(it);
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-17 18:36:19 +02:00
|
|
|
void ResourceAdaptationProcessor::SetDegradationPreference(
|
|
|
|
|
DegradationPreference degradation_preference) {
|
2020-05-11 16:29:22 +02:00
|
|
|
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
2020-04-17 18:36:19 +02:00
|
|
|
degradation_preference_ = degradation_preference;
|
|
|
|
|
MaybeUpdateEffectiveDegradationPreference();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ResourceAdaptationProcessor::SetIsScreenshare(bool is_screenshare) {
|
2020-05-11 16:29:22 +02:00
|
|
|
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
2020-04-17 18:36:19 +02:00
|
|
|
is_screenshare_ = is_screenshare;
|
|
|
|
|
MaybeUpdateEffectiveDegradationPreference();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ResourceAdaptationProcessor::MaybeUpdateEffectiveDegradationPreference() {
|
2020-05-11 16:29:22 +02:00
|
|
|
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
2020-04-17 18:36:19 +02:00
|
|
|
effective_degradation_preference_ =
|
|
|
|
|
(is_screenshare_ &&
|
|
|
|
|
degradation_preference_ == DegradationPreference::BALANCED)
|
|
|
|
|
? DegradationPreference::MAINTAIN_RESOLUTION
|
|
|
|
|
: degradation_preference_;
|
|
|
|
|
stream_adapter_->SetDegradationPreference(effective_degradation_preference_);
|
|
|
|
|
MaybeUpdateVideoSourceRestrictions(nullptr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ResourceAdaptationProcessor::ResetVideoSourceRestrictions() {
|
2020-05-11 16:29:22 +02:00
|
|
|
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
2020-05-28 16:22:42 +02:00
|
|
|
RTC_LOG(INFO) << "Resetting restrictions";
|
2020-04-17 18:36:19 +02:00
|
|
|
stream_adapter_->ClearRestrictions();
|
2020-05-07 13:45:14 +02:00
|
|
|
adaptations_counts_by_resource_.clear();
|
2020-04-17 18:36:19 +02:00
|
|
|
MaybeUpdateVideoSourceRestrictions(nullptr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ResourceAdaptationProcessor::MaybeUpdateVideoSourceRestrictions(
|
2020-05-11 16:29:22 +02:00
|
|
|
rtc::scoped_refptr<Resource> reason) {
|
|
|
|
|
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
2020-05-07 13:45:14 +02:00
|
|
|
VideoSourceRestrictions new_source_restrictions =
|
2020-04-17 18:36:19 +02:00
|
|
|
FilterRestrictionsByDegradationPreference(
|
|
|
|
|
stream_adapter_->source_restrictions(),
|
|
|
|
|
effective_degradation_preference_);
|
2020-05-07 13:45:14 +02:00
|
|
|
if (last_reported_source_restrictions_ != new_source_restrictions) {
|
2020-05-28 16:22:42 +02:00
|
|
|
RTC_LOG(INFO) << "Reporting new restrictions (in "
|
|
|
|
|
<< DegradationPreferenceToString(
|
|
|
|
|
effective_degradation_preference_)
|
|
|
|
|
<< "): " << new_source_restrictions.ToString();
|
2020-05-07 13:45:14 +02:00
|
|
|
last_reported_source_restrictions_ = std::move(new_source_restrictions);
|
2020-04-17 18:36:19 +02:00
|
|
|
for (auto* adaptation_listener : adaptation_listeners_) {
|
|
|
|
|
adaptation_listener->OnVideoSourceRestrictionsUpdated(
|
|
|
|
|
last_reported_source_restrictions_,
|
|
|
|
|
stream_adapter_->adaptation_counters(), reason);
|
|
|
|
|
}
|
2020-05-07 13:45:14 +02:00
|
|
|
if (reason) {
|
|
|
|
|
UpdateResourceDegradationCounts(reason);
|
|
|
|
|
}
|
2020-04-17 18:36:19 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-28 12:24:33 +02:00
|
|
|
void ResourceAdaptationProcessor::OnResourceUsageStateMeasured(
|
2020-05-11 16:29:22 +02:00
|
|
|
rtc::scoped_refptr<Resource> resource) {
|
|
|
|
|
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
2020-06-01 17:59:05 +02:00
|
|
|
RTC_DCHECK(resource->UsageState().has_value());
|
|
|
|
|
ResourceUsageState usage_state = resource->UsageState().value();
|
2020-05-28 16:22:42 +02:00
|
|
|
MitigationResultAndLogMessage result_and_message;
|
|
|
|
|
switch (usage_state) {
|
2020-04-17 18:36:19 +02:00
|
|
|
case ResourceUsageState::kOveruse:
|
2020-05-28 16:22:42 +02:00
|
|
|
result_and_message = OnResourceOveruse(resource);
|
2020-04-28 12:24:33 +02:00
|
|
|
break;
|
2020-04-17 18:36:19 +02:00
|
|
|
case ResourceUsageState::kUnderuse:
|
2020-05-28 16:22:42 +02:00
|
|
|
result_and_message = OnResourceUnderuse(resource);
|
2020-04-28 12:24:33 +02:00
|
|
|
break;
|
2020-04-17 18:36:19 +02:00
|
|
|
}
|
2020-05-28 16:22:42 +02:00
|
|
|
// Maybe log the result of the operation.
|
|
|
|
|
auto it = previous_mitigation_results_.find(resource.get());
|
|
|
|
|
if (it != previous_mitigation_results_.end() &&
|
|
|
|
|
it->second == result_and_message.result) {
|
|
|
|
|
// This resource has previously reported the same result and we haven't
|
|
|
|
|
// successfully adapted since - don't log to avoid spam.
|
|
|
|
|
return;
|
|
|
|
|
}
|
2020-06-01 17:59:05 +02:00
|
|
|
RTC_LOG(INFO) << "Resource \"" << resource->Name() << "\" signalled "
|
2020-05-28 16:22:42 +02:00
|
|
|
<< ResourceUsageStateToString(usage_state) << ". "
|
|
|
|
|
<< result_and_message.message;
|
|
|
|
|
if (result_and_message.result == MitigationResult::kAdaptationApplied) {
|
|
|
|
|
previous_mitigation_results_.clear();
|
|
|
|
|
} else {
|
|
|
|
|
previous_mitigation_results_.insert(
|
|
|
|
|
std::make_pair(resource.get(), result_and_message.result));
|
|
|
|
|
}
|
2020-04-17 18:36:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ResourceAdaptationProcessor::HasSufficientInputForAdaptation(
|
|
|
|
|
const VideoStreamInputState& input_state) const {
|
2020-05-11 16:29:22 +02:00
|
|
|
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
2020-04-17 18:36:19 +02:00
|
|
|
return input_state.HasInputFrameSizeAndFramesPerSecond() &&
|
|
|
|
|
(effective_degradation_preference_ !=
|
|
|
|
|
DegradationPreference::MAINTAIN_RESOLUTION ||
|
|
|
|
|
input_state.frames_per_second() >= kMinFrameRateFps);
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-28 16:22:42 +02:00
|
|
|
ResourceAdaptationProcessor::MitigationResultAndLogMessage
|
|
|
|
|
ResourceAdaptationProcessor::OnResourceUnderuse(
|
2020-05-11 16:29:22 +02:00
|
|
|
rtc::scoped_refptr<Resource> reason_resource) {
|
|
|
|
|
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
2020-04-28 12:24:33 +02:00
|
|
|
RTC_DCHECK(!processing_in_progress_);
|
|
|
|
|
processing_in_progress_ = true;
|
2020-04-20 12:04:12 +02:00
|
|
|
// Clear all usage states. In order to re-run adaptation logic, resources need
|
|
|
|
|
// to provide new resource usage measurements.
|
|
|
|
|
// TODO(hbos): Support not unconditionally clearing usage states by having the
|
|
|
|
|
// ResourceAdaptationProcessor check in on its resources at certain intervals.
|
2020-05-11 16:29:22 +02:00
|
|
|
for (const auto& resource : resources_) {
|
2020-04-20 12:04:12 +02:00
|
|
|
resource->ClearUsageState();
|
|
|
|
|
}
|
2020-05-28 16:22:42 +02:00
|
|
|
if (effective_degradation_preference_ == DegradationPreference::DISABLED) {
|
|
|
|
|
processing_in_progress_ = false;
|
|
|
|
|
return MitigationResultAndLogMessage(
|
|
|
|
|
MitigationResult::kDisabled,
|
|
|
|
|
"Not adapting up because DegradationPreference is disabled");
|
|
|
|
|
}
|
2020-04-17 18:36:19 +02:00
|
|
|
VideoStreamInputState input_state = input_state_provider_->InputState();
|
2020-05-28 16:22:42 +02:00
|
|
|
if (!HasSufficientInputForAdaptation(input_state)) {
|
2020-04-28 12:24:33 +02:00
|
|
|
processing_in_progress_ = false;
|
2020-05-28 16:22:42 +02:00
|
|
|
return MitigationResultAndLogMessage(
|
|
|
|
|
MitigationResult::kInsufficientInput,
|
|
|
|
|
"Not adapting up because input is insufficient");
|
2020-04-17 18:36:19 +02:00
|
|
|
}
|
2020-05-11 16:29:22 +02:00
|
|
|
if (!IsResourceAllowedToAdaptUp(reason_resource)) {
|
2020-05-07 13:45:14 +02:00
|
|
|
processing_in_progress_ = false;
|
2020-05-28 16:22:42 +02:00
|
|
|
return MitigationResultAndLogMessage(
|
|
|
|
|
MitigationResult::kRejectedByAdaptationCounts,
|
|
|
|
|
"Not adapting up because this resource has not previously adapted down "
|
|
|
|
|
"(according to adaptation counters)");
|
2020-05-07 13:45:14 +02:00
|
|
|
}
|
2020-04-17 18:36:19 +02:00
|
|
|
// Update video input states and encoder settings for accurate adaptation.
|
|
|
|
|
stream_adapter_->SetInput(input_state);
|
|
|
|
|
// How can this stream be adapted up?
|
|
|
|
|
Adaptation adaptation = stream_adapter_->GetAdaptationUp();
|
2020-04-28 12:24:33 +02:00
|
|
|
if (adaptation.status() != Adaptation::Status::kValid) {
|
|
|
|
|
processing_in_progress_ = false;
|
2020-05-28 16:22:42 +02:00
|
|
|
rtc::StringBuilder message;
|
|
|
|
|
message << "Not adapting up because VideoStreamAdapter returned "
|
|
|
|
|
<< Adaptation::StatusToString(adaptation.status());
|
|
|
|
|
return MitigationResultAndLogMessage(MitigationResult::kRejectedByAdapter,
|
|
|
|
|
message.Release());
|
2020-04-28 12:24:33 +02:00
|
|
|
}
|
2020-04-17 18:36:19 +02:00
|
|
|
// Are all resources OK with this adaptation being applied?
|
|
|
|
|
VideoSourceRestrictions restrictions_before =
|
|
|
|
|
stream_adapter_->source_restrictions();
|
|
|
|
|
VideoSourceRestrictions restrictions_after =
|
|
|
|
|
stream_adapter_->PeekNextRestrictions(adaptation);
|
2020-05-28 16:22:42 +02:00
|
|
|
for (const auto& resource : resources_) {
|
|
|
|
|
if (!resource->IsAdaptationUpAllowed(input_state, restrictions_before,
|
|
|
|
|
restrictions_after, reason_resource)) {
|
|
|
|
|
processing_in_progress_ = false;
|
|
|
|
|
rtc::StringBuilder message;
|
2020-06-01 17:59:05 +02:00
|
|
|
message << "Not adapting up because resource \"" << resource->Name()
|
2020-05-28 16:22:42 +02:00
|
|
|
<< "\" disallowed it";
|
|
|
|
|
return MitigationResultAndLogMessage(
|
|
|
|
|
MitigationResult::kRejectedByResource, message.Release());
|
|
|
|
|
}
|
2020-04-17 18:36:19 +02:00
|
|
|
}
|
|
|
|
|
// Apply adaptation.
|
|
|
|
|
stream_adapter_->ApplyAdaptation(adaptation);
|
2020-05-11 16:29:22 +02:00
|
|
|
for (const auto& resource : resources_) {
|
2020-04-28 12:24:33 +02:00
|
|
|
resource->OnAdaptationApplied(input_state, restrictions_before,
|
|
|
|
|
restrictions_after, reason_resource);
|
|
|
|
|
}
|
2020-04-17 18:36:19 +02:00
|
|
|
// Update VideoSourceRestrictions based on adaptation. This also informs the
|
|
|
|
|
// |adaptation_listeners_|.
|
2020-05-11 16:29:22 +02:00
|
|
|
MaybeUpdateVideoSourceRestrictions(reason_resource);
|
2020-04-28 12:24:33 +02:00
|
|
|
processing_in_progress_ = false;
|
2020-05-28 16:22:42 +02:00
|
|
|
rtc::StringBuilder message;
|
|
|
|
|
message << "Adapted up successfully. Unfiltered adaptations: "
|
|
|
|
|
<< stream_adapter_->adaptation_counters().ToString();
|
|
|
|
|
return MitigationResultAndLogMessage(MitigationResult::kAdaptationApplied,
|
|
|
|
|
message.Release());
|
2020-04-17 18:36:19 +02:00
|
|
|
}
|
|
|
|
|
|
2020-05-28 16:22:42 +02:00
|
|
|
ResourceAdaptationProcessor::MitigationResultAndLogMessage
|
|
|
|
|
ResourceAdaptationProcessor::OnResourceOveruse(
|
2020-05-11 16:29:22 +02:00
|
|
|
rtc::scoped_refptr<Resource> reason_resource) {
|
|
|
|
|
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
2020-04-28 12:24:33 +02:00
|
|
|
RTC_DCHECK(!processing_in_progress_);
|
|
|
|
|
processing_in_progress_ = true;
|
2020-04-20 12:04:12 +02:00
|
|
|
// Clear all usage states. In order to re-run adaptation logic, resources need
|
|
|
|
|
// to provide new resource usage measurements.
|
|
|
|
|
// TODO(hbos): Support not unconditionally clearing usage states by having the
|
|
|
|
|
// ResourceAdaptationProcessor check in on its resources at certain intervals.
|
2020-05-11 16:29:22 +02:00
|
|
|
for (const auto& resource : resources_) {
|
2020-04-20 12:04:12 +02:00
|
|
|
resource->ClearUsageState();
|
|
|
|
|
}
|
2020-05-28 16:22:42 +02:00
|
|
|
if (effective_degradation_preference_ == DegradationPreference::DISABLED) {
|
2020-04-28 12:24:33 +02:00
|
|
|
processing_in_progress_ = false;
|
2020-05-28 16:22:42 +02:00
|
|
|
return MitigationResultAndLogMessage(
|
|
|
|
|
MitigationResult::kDisabled,
|
|
|
|
|
"Not adapting down because DegradationPreference is disabled");
|
2020-04-17 18:36:19 +02:00
|
|
|
}
|
2020-05-28 16:22:42 +02:00
|
|
|
VideoStreamInputState input_state = input_state_provider_->InputState();
|
|
|
|
|
if (!HasSufficientInputForAdaptation(input_state)) {
|
2020-04-28 12:24:33 +02:00
|
|
|
processing_in_progress_ = false;
|
2020-05-28 16:22:42 +02:00
|
|
|
return MitigationResultAndLogMessage(
|
|
|
|
|
MitigationResult::kInsufficientInput,
|
|
|
|
|
"Not adapting down because input is insufficient");
|
2020-04-17 18:36:19 +02:00
|
|
|
}
|
|
|
|
|
// Update video input states and encoder settings for accurate adaptation.
|
|
|
|
|
stream_adapter_->SetInput(input_state);
|
|
|
|
|
// How can this stream be adapted up?
|
|
|
|
|
Adaptation adaptation = stream_adapter_->GetAdaptationDown();
|
2020-05-07 13:45:14 +02:00
|
|
|
if (adaptation.min_pixel_limit_reached()) {
|
2020-04-17 18:36:19 +02:00
|
|
|
encoder_stats_observer_->OnMinPixelLimitReached();
|
2020-05-07 13:45:14 +02:00
|
|
|
}
|
2020-04-28 12:24:33 +02:00
|
|
|
if (adaptation.status() != Adaptation::Status::kValid) {
|
|
|
|
|
processing_in_progress_ = false;
|
2020-05-28 16:22:42 +02:00
|
|
|
rtc::StringBuilder message;
|
|
|
|
|
message << "Not adapting down because VideoStreamAdapter returned "
|
|
|
|
|
<< Adaptation::StatusToString(adaptation.status());
|
|
|
|
|
return MitigationResultAndLogMessage(MitigationResult::kRejectedByAdapter,
|
|
|
|
|
message.Release());
|
2020-04-28 12:24:33 +02:00
|
|
|
}
|
2020-04-17 18:36:19 +02:00
|
|
|
// Apply adaptation.
|
2020-04-28 12:24:33 +02:00
|
|
|
VideoSourceRestrictions restrictions_before =
|
|
|
|
|
stream_adapter_->source_restrictions();
|
|
|
|
|
VideoSourceRestrictions restrictions_after =
|
|
|
|
|
stream_adapter_->PeekNextRestrictions(adaptation);
|
|
|
|
|
stream_adapter_->ApplyAdaptation(adaptation);
|
2020-05-11 16:29:22 +02:00
|
|
|
for (const auto& resource : resources_) {
|
2020-04-28 12:24:33 +02:00
|
|
|
resource->OnAdaptationApplied(input_state, restrictions_before,
|
|
|
|
|
restrictions_after, reason_resource);
|
|
|
|
|
}
|
2020-04-17 18:36:19 +02:00
|
|
|
// Update VideoSourceRestrictions based on adaptation. This also informs the
|
|
|
|
|
// |adaptation_listeners_|.
|
2020-05-11 16:29:22 +02:00
|
|
|
MaybeUpdateVideoSourceRestrictions(reason_resource);
|
2020-04-28 12:24:33 +02:00
|
|
|
processing_in_progress_ = false;
|
2020-05-28 16:22:42 +02:00
|
|
|
rtc::StringBuilder message;
|
|
|
|
|
message << "Adapted down successfully. Unfiltered adaptations: "
|
|
|
|
|
<< stream_adapter_->adaptation_counters().ToString();
|
|
|
|
|
return MitigationResultAndLogMessage(MitigationResult::kAdaptationApplied,
|
|
|
|
|
message.Release());
|
2020-04-17 18:36:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ResourceAdaptationProcessor::TriggerAdaptationDueToFrameDroppedDueToSize(
|
2020-05-11 16:29:22 +02:00
|
|
|
rtc::scoped_refptr<Resource> reason_resource) {
|
|
|
|
|
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
2020-05-28 16:22:42 +02:00
|
|
|
RTC_LOG(INFO) << "TriggerAdaptationDueToFrameDroppedDueToSize called";
|
2020-04-17 18:36:19 +02:00
|
|
|
VideoAdaptationCounters counters_before =
|
|
|
|
|
stream_adapter_->adaptation_counters();
|
|
|
|
|
OnResourceOveruse(reason_resource);
|
|
|
|
|
if (degradation_preference_ == DegradationPreference::BALANCED &&
|
|
|
|
|
stream_adapter_->adaptation_counters().fps_adaptations >
|
|
|
|
|
counters_before.fps_adaptations) {
|
|
|
|
|
// Oops, we adapted frame rate. Adapt again, maybe it will adapt resolution!
|
|
|
|
|
// Though this is not guaranteed...
|
|
|
|
|
OnResourceOveruse(reason_resource);
|
|
|
|
|
}
|
|
|
|
|
if (stream_adapter_->adaptation_counters().resolution_adaptations >
|
|
|
|
|
counters_before.resolution_adaptations) {
|
|
|
|
|
encoder_stats_observer_->OnInitialQualityResolutionAdaptDown();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-07 13:45:14 +02:00
|
|
|
void ResourceAdaptationProcessor::UpdateResourceDegradationCounts(
|
2020-05-11 16:29:22 +02:00
|
|
|
rtc::scoped_refptr<Resource> resource) {
|
|
|
|
|
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
2020-05-07 13:45:14 +02:00
|
|
|
RTC_DCHECK(resource);
|
|
|
|
|
int delta = stream_adapter_->adaptation_counters().Total();
|
|
|
|
|
for (const auto& adaptations : adaptations_counts_by_resource_) {
|
|
|
|
|
delta -= adaptations.second;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Default value is 0, inserts the value if missing.
|
|
|
|
|
adaptations_counts_by_resource_[resource] += delta;
|
|
|
|
|
RTC_DCHECK_GE(adaptations_counts_by_resource_[resource], 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ResourceAdaptationProcessor::IsResourceAllowedToAdaptUp(
|
2020-05-11 16:29:22 +02:00
|
|
|
rtc::scoped_refptr<Resource> resource) const {
|
|
|
|
|
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
2020-05-07 13:45:14 +02:00
|
|
|
RTC_DCHECK(resource);
|
|
|
|
|
const auto& adaptations = adaptations_counts_by_resource_.find(resource);
|
|
|
|
|
return adaptations != adaptations_counts_by_resource_.end() &&
|
|
|
|
|
adaptations->second > 0;
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-17 18:36:19 +02:00
|
|
|
} // namespace webrtc
|