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