Extended the bitrate allocator to allow allocation to tracks based upon priorities which are planned to be defined as a relative bitrate in the RTCRtpEncodingParameters.
Bug: None Change-Id: I80bc6c1e36b03537eb08f53df8c21d540e7408be Reviewed-on: https://webrtc-review.googlesource.com/16262 Commit-Queue: Seth Hampson <shampson@webrtc.org> Reviewed-by: Stefan Holmer <stefan@webrtc.org> Reviewed-by: Elad Alon <eladalon@webrtc.org> Cr-Commit-Position: refs/heads/master@{#20680}
This commit is contained in:
@ -12,6 +12,7 @@
|
||||
#include "call/bitrate_allocator.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
@ -48,7 +49,6 @@ double MediaRatio(uint32_t allocated_bitrate, uint32_t protection_bitrate) {
|
||||
|
||||
BitrateAllocator::BitrateAllocator(LimitObserver* limit_observer)
|
||||
: limit_observer_(limit_observer),
|
||||
bitrate_observer_configs_(),
|
||||
last_bitrate_bps_(0),
|
||||
last_non_zero_bitrate_bps_(kDefaultBitrateBps),
|
||||
last_fraction_loss_(0),
|
||||
@ -128,8 +128,11 @@ void BitrateAllocator::AddObserver(BitrateAllocatorObserver* observer,
|
||||
uint32_t max_bitrate_bps,
|
||||
uint32_t pad_up_bitrate_bps,
|
||||
bool enforce_min_bitrate,
|
||||
std::string track_id) {
|
||||
std::string track_id,
|
||||
double bitrate_priority) {
|
||||
RTC_DCHECK_CALLED_SEQUENTIALLY(&sequenced_checker_);
|
||||
RTC_DCHECK_GT(bitrate_priority, 0);
|
||||
RTC_DCHECK(std::isnormal(bitrate_priority));
|
||||
auto it = FindObserverConfig(observer);
|
||||
|
||||
// Update settings if the observer already exists, create a new one otherwise.
|
||||
@ -138,10 +141,11 @@ void BitrateAllocator::AddObserver(BitrateAllocatorObserver* observer,
|
||||
it->max_bitrate_bps = max_bitrate_bps;
|
||||
it->pad_up_bitrate_bps = pad_up_bitrate_bps;
|
||||
it->enforce_min_bitrate = enforce_min_bitrate;
|
||||
it->bitrate_priority = bitrate_priority;
|
||||
} else {
|
||||
bitrate_observer_configs_.push_back(
|
||||
ObserverConfig(observer, min_bitrate_bps, max_bitrate_bps,
|
||||
pad_up_bitrate_bps, enforce_min_bitrate, track_id));
|
||||
bitrate_observer_configs_.push_back(ObserverConfig(
|
||||
observer, min_bitrate_bps, max_bitrate_bps, pad_up_bitrate_bps,
|
||||
enforce_min_bitrate, track_id, bitrate_priority));
|
||||
}
|
||||
|
||||
ObserverAllocation allocation;
|
||||
@ -287,7 +291,8 @@ BitrateAllocator::ObserverAllocation BitrateAllocator::AllocateBitrates(
|
||||
if (!EnoughBitrateForAllObservers(bitrate, sum_min_bitrates))
|
||||
return LowRateAllocation(bitrate);
|
||||
|
||||
// All observers will get their min bitrate plus an even share of the rest.
|
||||
// All observers will get their min bitrate plus a share of the rest. This
|
||||
// share is allocated to each observer based on its bitrate_priority.
|
||||
if (bitrate <= sum_max_bitrates)
|
||||
return NormalRateAllocation(bitrate, sum_min_bitrates);
|
||||
|
||||
@ -357,17 +362,30 @@ BitrateAllocator::ObserverAllocation BitrateAllocator::LowRateAllocation(
|
||||
return allocation;
|
||||
}
|
||||
|
||||
// Allocates the bitrate based on the bitrate priority of each observer. This
|
||||
// bitrate priority defines the priority for bitrate to be allocated to that
|
||||
// observer in relation to other observers. For example with two observers, if
|
||||
// observer 1 had a bitrate_priority = 1.0, and observer 2 has a
|
||||
// bitrate_priority = 2.0, the expected behavior is that observer 2 will be
|
||||
// allocated twice the bitrate as observer 1 above the each observer's
|
||||
// min_bitrate_bps values, until one of the observers hits its max_bitrate_bps.
|
||||
BitrateAllocator::ObserverAllocation BitrateAllocator::NormalRateAllocation(
|
||||
uint32_t bitrate,
|
||||
uint32_t sum_min_bitrates) {
|
||||
RTC_DCHECK_CALLED_SEQUENTIALLY(&sequenced_checker_);
|
||||
ObserverAllocation allocation;
|
||||
for (const auto& observer_config : bitrate_observer_configs_)
|
||||
ObserverAllocation observers_capacities;
|
||||
for (const auto& observer_config : bitrate_observer_configs_) {
|
||||
allocation[observer_config.observer] = observer_config.min_bitrate_bps;
|
||||
observers_capacities[observer_config.observer] =
|
||||
observer_config.max_bitrate_bps - observer_config.min_bitrate_bps;
|
||||
}
|
||||
|
||||
bitrate -= sum_min_bitrates;
|
||||
// From the remaining bitrate, allocate a proportional amount to each observer
|
||||
// above the min bitrate already allocated.
|
||||
if (bitrate > 0)
|
||||
DistributeBitrateEvenly(bitrate, true, 1, &allocation);
|
||||
DistributeBitrateRelatively(bitrate, observers_capacities, &allocation);
|
||||
|
||||
return allocation;
|
||||
}
|
||||
@ -468,4 +486,80 @@ bool BitrateAllocator::EnoughBitrateForAllObservers(uint32_t bitrate,
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void BitrateAllocator::DistributeBitrateRelatively(
|
||||
uint32_t remaining_bitrate,
|
||||
const ObserverAllocation& observers_capacities,
|
||||
ObserverAllocation* allocation) {
|
||||
RTC_DCHECK_CALLED_SEQUENTIALLY(&sequenced_checker_);
|
||||
RTC_DCHECK_EQ(allocation->size(), bitrate_observer_configs_.size());
|
||||
RTC_DCHECK_EQ(observers_capacities.size(), bitrate_observer_configs_.size());
|
||||
|
||||
struct PriorityRateObserverConfig {
|
||||
PriorityRateObserverConfig(BitrateAllocatorObserver* allocation_key,
|
||||
uint32_t capacity_bps,
|
||||
double bitrate_priority)
|
||||
: allocation_key(allocation_key),
|
||||
capacity_bps(capacity_bps),
|
||||
bitrate_priority(bitrate_priority) {}
|
||||
|
||||
BitrateAllocatorObserver* allocation_key;
|
||||
// The amount of bitrate bps that can be allocated to this observer.
|
||||
uint32_t capacity_bps;
|
||||
double bitrate_priority;
|
||||
|
||||
// We want to sort by which observers will be allocated their full capacity
|
||||
// first. By dividing each observer's capacity by its bitrate priority we
|
||||
// are "normalizing" the capacity of an observer by the rate it will be
|
||||
// filled. This is because the amount allocated is based upon bitrate
|
||||
// priority. We allocate twice as much bitrate to an observer with twice the
|
||||
// bitrate priority of another.
|
||||
bool operator<(const PriorityRateObserverConfig& other) const {
|
||||
return capacity_bps / bitrate_priority <
|
||||
other.capacity_bps / other.bitrate_priority;
|
||||
}
|
||||
};
|
||||
|
||||
double bitrate_priority_sum = 0;
|
||||
std::vector<PriorityRateObserverConfig> priority_rate_observers;
|
||||
for (const auto& observer_config : bitrate_observer_configs_) {
|
||||
uint32_t capacity_bps = observers_capacities.at(observer_config.observer);
|
||||
priority_rate_observers.emplace_back(observer_config.observer, capacity_bps,
|
||||
observer_config.bitrate_priority);
|
||||
bitrate_priority_sum += observer_config.bitrate_priority;
|
||||
}
|
||||
|
||||
// Iterate in the order observers can be allocated their full capacity.
|
||||
std::sort(priority_rate_observers.begin(), priority_rate_observers.end());
|
||||
size_t i;
|
||||
for (i = 0; i < priority_rate_observers.size(); ++i) {
|
||||
const auto& priority_rate_observer = priority_rate_observers[i];
|
||||
// We allocate the full capacity to an observer only if its relative
|
||||
// portion from the remaining bitrate is sufficient to allocate its full
|
||||
// capacity. This means we aren't greedily allocating the full capacity, but
|
||||
// that it is only done when there is also enough bitrate to allocate the
|
||||
// proportional amounts to all other observers.
|
||||
double observer_share =
|
||||
priority_rate_observer.bitrate_priority / bitrate_priority_sum;
|
||||
double allocation_bps = observer_share * remaining_bitrate;
|
||||
bool enough_bitrate = allocation_bps >= priority_rate_observer.capacity_bps;
|
||||
if (!enough_bitrate)
|
||||
break;
|
||||
allocation->at(priority_rate_observer.allocation_key) +=
|
||||
priority_rate_observer.capacity_bps;
|
||||
remaining_bitrate -= priority_rate_observer.capacity_bps;
|
||||
bitrate_priority_sum -= priority_rate_observer.bitrate_priority;
|
||||
}
|
||||
|
||||
// From the remaining bitrate, allocate the proportional amounts to the
|
||||
// observers that aren't allocated their max capacity.
|
||||
for (; i < priority_rate_observers.size(); ++i) {
|
||||
const auto& priority_rate_observer = priority_rate_observers[i];
|
||||
double fraction_allocated =
|
||||
priority_rate_observer.bitrate_priority / bitrate_priority_sum;
|
||||
allocation->at(priority_rate_observer.allocation_key) +=
|
||||
fraction_allocated * remaining_bitrate;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
@ -86,7 +86,11 @@ class BitrateAllocator {
|
||||
uint32_t max_bitrate_bps,
|
||||
uint32_t pad_up_bitrate_bps,
|
||||
bool enforce_min_bitrate,
|
||||
std::string track_id);
|
||||
std::string track_id,
|
||||
// TODO(shampson): Take out default value and wire the
|
||||
// bitrate_priority up to the AudioSendStream::Config and
|
||||
// VideoSendStream::Config.
|
||||
double bitrate_priority = 1.0);
|
||||
|
||||
// Removes a previously added observer, but will not trigger a new bitrate
|
||||
// allocation.
|
||||
@ -104,14 +108,14 @@ class BitrateAllocator {
|
||||
bitrate_allocation_strategy);
|
||||
|
||||
private:
|
||||
// Note: All bitrates for member variables and methods are in bps.
|
||||
struct ObserverConfig : rtc::BitrateAllocationStrategy::TrackConfig {
|
||||
ObserverConfig(BitrateAllocatorObserver* observer,
|
||||
uint32_t min_bitrate_bps,
|
||||
uint32_t max_bitrate_bps,
|
||||
uint32_t pad_up_bitrate_bps,
|
||||
bool enforce_min_bitrate,
|
||||
std::string track_id)
|
||||
std::string track_id,
|
||||
double bitrate_priority)
|
||||
: TrackConfig(min_bitrate_bps,
|
||||
max_bitrate_bps,
|
||||
enforce_min_bitrate,
|
||||
@ -119,12 +123,17 @@ class BitrateAllocator {
|
||||
observer(observer),
|
||||
pad_up_bitrate_bps(pad_up_bitrate_bps),
|
||||
allocated_bitrate_bps(-1),
|
||||
media_ratio(1.0) {}
|
||||
media_ratio(1.0),
|
||||
bitrate_priority(bitrate_priority) {}
|
||||
|
||||
BitrateAllocatorObserver* observer;
|
||||
uint32_t pad_up_bitrate_bps;
|
||||
int64_t allocated_bitrate_bps;
|
||||
double media_ratio; // Part of the total bitrate used for media [0.0, 1.0].
|
||||
// The amount of bitrate allocated to this observer relative to all other
|
||||
// observers. If an observer has twice the bitrate_priority of other
|
||||
// observers, it should be allocated twice the bitrate above its min.
|
||||
double bitrate_priority;
|
||||
};
|
||||
|
||||
// Calculates the minimum requested send bitrate and max padding bitrate and
|
||||
@ -140,10 +149,18 @@ class BitrateAllocator {
|
||||
|
||||
ObserverAllocation AllocateBitrates(uint32_t bitrate);
|
||||
|
||||
// Allocates zero bitrate to all observers.
|
||||
ObserverAllocation ZeroRateAllocation();
|
||||
// Allocates bitrate to observers when there isn't enough to allocate the
|
||||
// minimum to all observers.
|
||||
ObserverAllocation LowRateAllocation(uint32_t bitrate);
|
||||
// Allocates bitrate to all observers when the available bandwidth is enough
|
||||
// to allocate the minimum to all observers but not enough to allocate the
|
||||
// max bitrate of each observer.
|
||||
ObserverAllocation NormalRateAllocation(uint32_t bitrate,
|
||||
uint32_t sum_min_bitrates);
|
||||
// Allocates bitrate to observers when there is enough available bandwidth
|
||||
// for all observers to be allocated their max bitrate.
|
||||
ObserverAllocation MaxRateAllocation(uint32_t bitrate,
|
||||
uint32_t sum_max_bitrates);
|
||||
|
||||
@ -162,6 +179,17 @@ class BitrateAllocator {
|
||||
bool EnoughBitrateForAllObservers(uint32_t bitrate,
|
||||
uint32_t sum_min_bitrates);
|
||||
|
||||
// From the available |bitrate|, each observer will be allocated a
|
||||
// proportional amount based upon its bitrate priority. If that amount is
|
||||
// more than the observer's capacity, it will be allocated its capacity, and
|
||||
// the excess bitrate is still allocated proportionally to other observers.
|
||||
// Allocating the proportional amount means an observer with twice the
|
||||
// bitrate_priority of another will be allocated twice the bitrate.
|
||||
void DistributeBitrateRelatively(
|
||||
uint32_t bitrate,
|
||||
const ObserverAllocation& observers_capacities,
|
||||
ObserverAllocation* allocation);
|
||||
|
||||
rtc::SequencedTaskChecker sequenced_checker_;
|
||||
LimitObserver* const limit_observer_ RTC_GUARDED_BY(&sequenced_checker_);
|
||||
// Stored in a list to keep track of the insertion order.
|
||||
@ -180,5 +208,6 @@ class BitrateAllocator {
|
||||
std::unique_ptr<rtc::BitrateAllocationStrategy> bitrate_allocation_strategy_
|
||||
RTC_GUARDED_BY(&sequenced_checker_);
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
#endif // CALL_BITRATE_ALLOCATOR_H_
|
||||
|
||||
@ -17,7 +17,8 @@
|
||||
#include "test/gmock.h"
|
||||
#include "test/gtest.h"
|
||||
|
||||
using testing::NiceMock;
|
||||
using ::testing::NiceMock;
|
||||
using ::testing::_;
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
@ -518,4 +519,259 @@ TEST_F(BitrateAllocatorTest, PassProbingInterval) {
|
||||
allocator_->RemoveObserver(&observer);
|
||||
}
|
||||
|
||||
TEST_F(BitrateAllocatorTest, PriorityRateOneObserverBasic) {
|
||||
TestBitrateObserver observer;
|
||||
const uint32_t kMinSendBitrateBps = 10;
|
||||
const uint32_t kMaxSendBitrateBps = 60;
|
||||
const uint32_t kNetworkBandwidthBps = 30;
|
||||
|
||||
allocator_->AddObserver(&observer, kMinSendBitrateBps, kMaxSendBitrateBps, 0,
|
||||
true, "", 2.0);
|
||||
allocator_->OnNetworkChanged(kNetworkBandwidthBps, 0, 0,
|
||||
kDefaultProbingIntervalMs);
|
||||
|
||||
EXPECT_EQ(kNetworkBandwidthBps, observer.last_bitrate_bps_);
|
||||
|
||||
allocator_->RemoveObserver(&observer);
|
||||
}
|
||||
|
||||
// Tests that two observers with the same bitrate priority are allocated
|
||||
// their bitrate evenly.
|
||||
TEST_F(BitrateAllocatorTest, PriorityRateTwoObserversBasic) {
|
||||
TestBitrateObserver observer_low_1;
|
||||
TestBitrateObserver observer_low_2;
|
||||
const uint32_t kMinSendBitrateBps = 10;
|
||||
const uint32_t kMaxSendBitrateBps = 60;
|
||||
const uint32_t kNetworkBandwidthBps = 60;
|
||||
allocator_->AddObserver(&observer_low_1, kMinSendBitrateBps,
|
||||
kMaxSendBitrateBps, 0, false, "low1", 2.0);
|
||||
allocator_->AddObserver(&observer_low_2, kMinSendBitrateBps,
|
||||
kMaxSendBitrateBps, 0, false, "low2", 2.0);
|
||||
allocator_->OnNetworkChanged(kNetworkBandwidthBps, 0, 0,
|
||||
kDefaultProbingIntervalMs);
|
||||
|
||||
EXPECT_EQ(kNetworkBandwidthBps / 2, observer_low_1.last_bitrate_bps_);
|
||||
EXPECT_EQ(kNetworkBandwidthBps / 2, observer_low_2.last_bitrate_bps_);
|
||||
|
||||
allocator_->RemoveObserver(&observer_low_1);
|
||||
allocator_->RemoveObserver(&observer_low_2);
|
||||
}
|
||||
|
||||
// Tests that there is no difference in functionality when the min bitrate is
|
||||
// enforced.
|
||||
TEST_F(BitrateAllocatorTest, PriorityRateTwoObserversBasicMinEnforced) {
|
||||
TestBitrateObserver observer_low_1;
|
||||
TestBitrateObserver observer_low_2;
|
||||
const uint32_t kMinSendBitrateBps = 0;
|
||||
const uint32_t kMaxSendBitrateBps = 60;
|
||||
const uint32_t kNetworkBandwidthBps = 60;
|
||||
allocator_->AddObserver(&observer_low_1, kMinSendBitrateBps,
|
||||
kMaxSendBitrateBps, 0, true, "low1", 2.0);
|
||||
allocator_->AddObserver(&observer_low_2, kMinSendBitrateBps,
|
||||
kMaxSendBitrateBps, 0, true, "low2", 2.0);
|
||||
allocator_->OnNetworkChanged(kNetworkBandwidthBps, 0, 0,
|
||||
kDefaultProbingIntervalMs);
|
||||
|
||||
EXPECT_EQ(kNetworkBandwidthBps / 2, observer_low_1.last_bitrate_bps_);
|
||||
EXPECT_EQ(kNetworkBandwidthBps / 2, observer_low_2.last_bitrate_bps_);
|
||||
|
||||
allocator_->RemoveObserver(&observer_low_1);
|
||||
allocator_->RemoveObserver(&observer_low_2);
|
||||
}
|
||||
|
||||
// Tests that if the available bandwidth is the sum of the max bitrate
|
||||
// of all observers, they will be allocated their max.
|
||||
TEST_F(BitrateAllocatorTest, PriorityRateTwoObserversBothAllocatedMax) {
|
||||
TestBitrateObserver observer_low;
|
||||
TestBitrateObserver observer_mid;
|
||||
const uint32_t kMinSendBitrateBps = 0;
|
||||
const uint32_t kMaxSendBitrateBps = 60;
|
||||
const uint32_t kNetworkBandwidthBps = kMaxSendBitrateBps * 2;
|
||||
allocator_->AddObserver(&observer_low, kMinSendBitrateBps, kMaxSendBitrateBps,
|
||||
0, true, "low", 2.0);
|
||||
allocator_->AddObserver(&observer_mid, kMinSendBitrateBps, kMaxSendBitrateBps,
|
||||
0, true, "mid", 4.0);
|
||||
allocator_->OnNetworkChanged(kNetworkBandwidthBps, 0, 0,
|
||||
kDefaultProbingIntervalMs);
|
||||
|
||||
EXPECT_EQ(kMaxSendBitrateBps, observer_low.last_bitrate_bps_);
|
||||
EXPECT_EQ(kMaxSendBitrateBps, observer_mid.last_bitrate_bps_);
|
||||
|
||||
allocator_->RemoveObserver(&observer_low);
|
||||
allocator_->RemoveObserver(&observer_mid);
|
||||
}
|
||||
|
||||
// Tests that after a higher bitrate priority observer has been allocated its
|
||||
// max bitrate the lower priority observer will then be allocated the remaining
|
||||
// bitrate.
|
||||
TEST_F(BitrateAllocatorTest, PriorityRateTwoObserversOneAllocatedToMax) {
|
||||
TestBitrateObserver observer_low;
|
||||
TestBitrateObserver observer_mid;
|
||||
allocator_->AddObserver(&observer_low, 10, 50, 0, false, "low", 2.0);
|
||||
allocator_->AddObserver(&observer_mid, 10, 50, 0, false, "mid", 4.0);
|
||||
allocator_->OnNetworkChanged(90, 0, 0, kDefaultProbingIntervalMs);
|
||||
|
||||
EXPECT_EQ(40u, observer_low.last_bitrate_bps_);
|
||||
EXPECT_EQ(50u, observer_mid.last_bitrate_bps_);
|
||||
|
||||
allocator_->RemoveObserver(&observer_low);
|
||||
allocator_->RemoveObserver(&observer_mid);
|
||||
}
|
||||
|
||||
// Tests that three observers with three different bitrate priorities will all
|
||||
// be allocated bitrate according to their relative bitrate priority.
|
||||
TEST_F(BitrateAllocatorTest,
|
||||
PriorityRateThreeObserversAllocatedRelativeAmounts) {
|
||||
TestBitrateObserver observer_low;
|
||||
TestBitrateObserver observer_mid;
|
||||
TestBitrateObserver observer_high;
|
||||
const uint32_t kMaxBitrate = 100;
|
||||
// Not enough bandwidth to fill any observer's max bitrate.
|
||||
const uint32_t kNetworkBandwidthBps = 70;
|
||||
const double kLowBitratePriority = 2.0;
|
||||
const double kMidBitratePriority = 4.0;
|
||||
const double kHighBitratePriority = 8.0;
|
||||
const double kTotalBitratePriority =
|
||||
kLowBitratePriority + kMidBitratePriority + kHighBitratePriority;
|
||||
allocator_->AddObserver(&observer_low, 0, kMaxBitrate, 0, false, "low",
|
||||
kLowBitratePriority);
|
||||
allocator_->AddObserver(&observer_mid, 0, kMaxBitrate, 0, false, "mid",
|
||||
kMidBitratePriority);
|
||||
allocator_->AddObserver(&observer_high, 0, kMaxBitrate, 0, false, "high",
|
||||
kHighBitratePriority);
|
||||
allocator_->OnNetworkChanged(kNetworkBandwidthBps, 0, 0,
|
||||
kDefaultProbingIntervalMs);
|
||||
|
||||
const double kLowFractionAllocated =
|
||||
kLowBitratePriority / kTotalBitratePriority;
|
||||
const double kMidFractionAllocated =
|
||||
kMidBitratePriority / kTotalBitratePriority;
|
||||
const double kHighFractionAllocated =
|
||||
kHighBitratePriority / kTotalBitratePriority;
|
||||
EXPECT_EQ(kLowFractionAllocated * kNetworkBandwidthBps,
|
||||
observer_low.last_bitrate_bps_);
|
||||
EXPECT_EQ(kMidFractionAllocated * kNetworkBandwidthBps,
|
||||
observer_mid.last_bitrate_bps_);
|
||||
EXPECT_EQ(kHighFractionAllocated * kNetworkBandwidthBps,
|
||||
observer_high.last_bitrate_bps_);
|
||||
|
||||
allocator_->RemoveObserver(&observer_low);
|
||||
allocator_->RemoveObserver(&observer_mid);
|
||||
allocator_->RemoveObserver(&observer_high);
|
||||
}
|
||||
|
||||
// Tests that after the high priority observer has been allocated its maximum
|
||||
// bitrate, the other two observers are still allocated bitrate according to
|
||||
// their relative bitrate priority.
|
||||
TEST_F(BitrateAllocatorTest, PriorityRateThreeObserversHighAllocatedToMax) {
|
||||
TestBitrateObserver observer_low;
|
||||
const double kLowBitratePriority = 2.0;
|
||||
TestBitrateObserver observer_mid;
|
||||
const double kMidBitratePriority = 4.0;
|
||||
TestBitrateObserver observer_high;
|
||||
const double kHighBitratePriority = 8.0;
|
||||
|
||||
const uint32_t kAvailableBitrate = 90;
|
||||
const uint32_t kMaxBitrate = 40;
|
||||
const uint32_t kMinBitrate = 10;
|
||||
// Remaining bitrate after allocating to all mins and knowing that the high
|
||||
// priority observer will have its max bitrate allocated.
|
||||
const uint32_t kRemainingBitrate =
|
||||
kAvailableBitrate - kMaxBitrate - (2 * kMinBitrate);
|
||||
|
||||
allocator_->AddObserver(&observer_low, kMinBitrate, kMaxBitrate, 0, false,
|
||||
"low", kLowBitratePriority);
|
||||
allocator_->AddObserver(&observer_mid, kMinBitrate, kMaxBitrate, 0, false,
|
||||
"mid", kMidBitratePriority);
|
||||
allocator_->AddObserver(&observer_high, kMinBitrate, kMaxBitrate, 0, false,
|
||||
"high", kHighBitratePriority);
|
||||
allocator_->OnNetworkChanged(kAvailableBitrate, 0, 0,
|
||||
kDefaultProbingIntervalMs);
|
||||
|
||||
const double kLowFractionAllocated =
|
||||
kLowBitratePriority / (kLowBitratePriority + kMidBitratePriority);
|
||||
const double kMidFractionAllocated =
|
||||
kMidBitratePriority / (kLowBitratePriority + kMidBitratePriority);
|
||||
EXPECT_EQ(kMinBitrate + (kRemainingBitrate * kLowFractionAllocated),
|
||||
observer_low.last_bitrate_bps_);
|
||||
EXPECT_EQ(kMinBitrate + (kRemainingBitrate * kMidFractionAllocated),
|
||||
observer_mid.last_bitrate_bps_);
|
||||
EXPECT_EQ(40u, observer_high.last_bitrate_bps_);
|
||||
|
||||
allocator_->RemoveObserver(&observer_low);
|
||||
allocator_->RemoveObserver(&observer_mid);
|
||||
allocator_->RemoveObserver(&observer_high);
|
||||
}
|
||||
|
||||
// Tests that after the low priority observer has been allocated its maximum
|
||||
// bitrate, the other two observers are still allocated bitrate according to
|
||||
// their relative bitrate priority.
|
||||
TEST_F(BitrateAllocatorTest, PriorityRateThreeObserversLowAllocatedToMax) {
|
||||
TestBitrateObserver observer_low;
|
||||
const double kLowBitratePriority = 2.0;
|
||||
const uint32_t kLowMaxBitrate = 10;
|
||||
TestBitrateObserver observer_mid;
|
||||
const double kMidBitratePriority = 4.0;
|
||||
TestBitrateObserver observer_high;
|
||||
const double kHighBitratePriority = 8.0;
|
||||
|
||||
const uint32_t kMinBitrate = 0;
|
||||
const uint32_t kMaxBitrate = 60;
|
||||
const uint32_t kAvailableBitrate = 100;
|
||||
// Remaining bitrate knowing that the low priority observer is allocated its
|
||||
// max bitrate. We know this because it is allocated 2.0/14.0 (1/7) of the
|
||||
// available bitrate, so 70 bps would be sufficient network bandwidth.
|
||||
const uint32_t kRemainingBitrate = kAvailableBitrate - kLowMaxBitrate;
|
||||
|
||||
allocator_->AddObserver(&observer_low, kMinBitrate, kLowMaxBitrate, 0, false,
|
||||
"low", kLowBitratePriority);
|
||||
allocator_->AddObserver(&observer_mid, kMinBitrate, kMaxBitrate, 0, false,
|
||||
"mid", kMidBitratePriority);
|
||||
allocator_->AddObserver(&observer_high, kMinBitrate, kMaxBitrate, 0, false,
|
||||
"high", kHighBitratePriority);
|
||||
allocator_->OnNetworkChanged(kAvailableBitrate, 0, 0,
|
||||
kDefaultProbingIntervalMs);
|
||||
|
||||
const double kMidFractionAllocated =
|
||||
kMidBitratePriority / (kMidBitratePriority + kHighBitratePriority);
|
||||
const double kHighFractionAllocated =
|
||||
kHighBitratePriority / (kMidBitratePriority + kHighBitratePriority);
|
||||
EXPECT_EQ(kLowMaxBitrate, observer_low.last_bitrate_bps_);
|
||||
EXPECT_EQ(kMinBitrate + (kRemainingBitrate * kMidFractionAllocated),
|
||||
observer_mid.last_bitrate_bps_);
|
||||
EXPECT_EQ(kMinBitrate + (kRemainingBitrate * kHighFractionAllocated),
|
||||
observer_high.last_bitrate_bps_);
|
||||
|
||||
allocator_->RemoveObserver(&observer_low);
|
||||
allocator_->RemoveObserver(&observer_mid);
|
||||
allocator_->RemoveObserver(&observer_high);
|
||||
}
|
||||
|
||||
// Tests that after two observers are allocated bitrate to their max, the
|
||||
// the remaining observer is allocated what's left appropriately. This test
|
||||
// handles an edge case where the medium and high observer reach their
|
||||
// "relative" max allocation at the same time. The high has 40 to allocate
|
||||
// above its min, and the mid has 20 to allocate above its min, which scaled
|
||||
// by their bitrate priority is the same for each.
|
||||
TEST_F(BitrateAllocatorTest, PriorityRateThreeObserversTwoAllocatedToMax) {
|
||||
TestBitrateObserver observer_low;
|
||||
TestBitrateObserver observer_mid;
|
||||
TestBitrateObserver observer_high;
|
||||
allocator_->AddObserver(&observer_low, 10, 40, 0, false, "low", 2.0);
|
||||
// Scaled allocation above the min allocation is the same for these two,
|
||||
// meaning they will get allocated their max at the same time.
|
||||
// Scaled (target allocation) = (max - min) / bitrate priority
|
||||
allocator_->AddObserver(&observer_mid, 10, 30, 0, false, "mid", 4.0);
|
||||
allocator_->AddObserver(&observer_high, 10, 50, 0, false, "high", 8.0);
|
||||
allocator_->OnNetworkChanged(110, 0, 0, kDefaultProbingIntervalMs);
|
||||
|
||||
EXPECT_EQ(30u, observer_low.last_bitrate_bps_);
|
||||
EXPECT_EQ(30u, observer_mid.last_bitrate_bps_);
|
||||
EXPECT_EQ(50u, observer_high.last_bitrate_bps_);
|
||||
|
||||
allocator_->RemoveObserver(&observer_low);
|
||||
allocator_->RemoveObserver(&observer_mid);
|
||||
allocator_->RemoveObserver(&observer_high);
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
Reference in New Issue
Block a user