blob: e4f209fe9db1955347cc85545fffeaf72d99b5e1 [file] [log] [blame]
/*
* Copyright 2019 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"
#include <limits>
#include <utility>
#include "rtc_base/checks.h"
namespace webrtc {
namespace {
ResourceConsumerConfiguration* FindMostPreferredConfiguration(
const std::vector<ResourceConsumerConfiguration*>& configurations) {
if (configurations.empty())
return nullptr;
ResourceConsumerConfiguration* most_preferred_configuration =
configurations[0];
double most_preferred_configuration_preference =
most_preferred_configuration->Preference();
RTC_DCHECK_GE(most_preferred_configuration_preference, 0.0);
for (size_t i = 1; i < configurations.size(); ++i) {
auto* configuration = configurations[i];
double preference = configuration->Preference();
RTC_DCHECK_GE(preference, 0.0);
if (most_preferred_configuration_preference < preference) {
most_preferred_configuration = configuration;
most_preferred_configuration_preference = preference;
}
}
return most_preferred_configuration;
}
} // namespace
ConsumerConfigurationPair::ConsumerConfigurationPair(
ResourceConsumer* consumer,
ResourceConsumerConfiguration* configuration)
: consumer(consumer), configuration(configuration) {}
absl::optional<ConsumerConfigurationPair>
ResourceAdaptationProcessor::FindNextConfiguration() {
ResourceUsageState overall_usage = ResourceUsageState::kUnderuse;
for (auto& resource : resources_) {
ResourceUsageState resource_usage = resource->CurrentUsageState();
if (resource_usage == ResourceUsageState::kStable) {
// If any resource is "stable", we are not underusing.
if (overall_usage == ResourceUsageState::kUnderuse)
overall_usage = ResourceUsageState::kStable;
} else if (resource_usage == ResourceUsageState::kOveruse) {
// If any resource is "overuse", we are overusing.
overall_usage = ResourceUsageState::kOveruse;
break;
}
}
// If we are stable we should neither adapt up or down: stay where we are.
if (overall_usage == ResourceUsageState::kStable)
return absl::nullopt;
if (overall_usage == ResourceUsageState::kOveruse) {
// If we are overusing, we adapt down the most expensive consumer to its
// most preferred lower neighbor.
ResourceConsumer* max_cost_consumer =
FindMostExpensiveConsumerThatCanBeAdaptedDown();
if (!max_cost_consumer)
return absl::nullopt;
ResourceConsumerConfiguration* next_configuration =
FindMostPreferredConfiguration(
max_cost_consumer->configuration()->lower_neighbors());
RTC_DCHECK(next_configuration);
return ConsumerConfigurationPair(max_cost_consumer, next_configuration);
} else {
RTC_DCHECK_EQ(overall_usage, ResourceUsageState::kUnderuse);
// If we are underusing, we adapt up the least expensive consumer to its
// most preferred upper neighbor.
ResourceConsumer* min_cost_consumer =
FindLeastExpensiveConsumerThatCanBeAdaptedUp();
if (!min_cost_consumer)
return absl::nullopt;
ResourceConsumerConfiguration* next_configuration =
FindMostPreferredConfiguration(
min_cost_consumer->configuration()->upper_neighbors());
RTC_DCHECK(next_configuration);
return ConsumerConfigurationPair(min_cost_consumer, next_configuration);
}
}
ResourceConsumer*
ResourceAdaptationProcessor::FindMostExpensiveConsumerThatCanBeAdaptedDown() {
ResourceConsumer* max_cost_consumer = nullptr;
double max_cost = -1.0;
for (auto& consumer : consumers_) {
if (consumer->configuration()->lower_neighbors().empty())
continue;
double cost = consumer->configuration()->Cost();
if (max_cost < cost) {
max_cost_consumer = consumer.get();
max_cost = cost;
}
}
return max_cost_consumer;
}
ResourceConsumer*
ResourceAdaptationProcessor::FindLeastExpensiveConsumerThatCanBeAdaptedUp() {
ResourceConsumer* min_cost_consumer = nullptr;
double min_cost = std::numeric_limits<double>::infinity();
for (auto& consumer : consumers_) {
if (consumer->configuration()->upper_neighbors().empty())
continue;
double cost = consumer->configuration()->Cost();
if (min_cost > cost) {
min_cost_consumer = consumer.get();
min_cost = cost;
}
}
return min_cost_consumer;
}
} // namespace webrtc