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}diff --git a/call/bitrate_allocator_unittest.cc b/call/bitrate_allocator_unittest.cc
index 31828b6..c0786a0 100644
--- a/call/bitrate_allocator_unittest.cc
+++ b/call/bitrate_allocator_unittest.cc
@@ -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 @@
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