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.cc b/call/bitrate_allocator.cc
index 2692c00..004262e 100644
--- a/call/bitrate_allocator.cc
+++ b/call/bitrate_allocator.cc
@@ -12,6 +12,7 @@
 #include "call/bitrate_allocator.h"
 
 #include <algorithm>
+#include <cmath>
 #include <memory>
 #include <utility>
 
@@ -48,7 +49,6 @@
 
 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 @@
                                    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 @@
     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 @@
   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 @@
   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 @@
   }
   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
diff --git a/call/bitrate_allocator.h b/call/bitrate_allocator.h
index cf518f6..73258ad 100644
--- a/call/bitrate_allocator.h
+++ b/call/bitrate_allocator.h
@@ -86,7 +86,11 @@
                    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 @@
           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 @@
           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 @@
 
   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 @@
   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 @@
   std::unique_ptr<rtc::BitrateAllocationStrategy> bitrate_allocation_strategy_
       RTC_GUARDED_BY(&sequenced_checker_);
 };
+
 }  // namespace webrtc
 #endif  // CALL_BITRATE_ALLOCATOR_H_
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