BWE allocation strategy

This is reland of https://webrtc-review.googlesource.com/c/src/+/4860 with the fixed RampUpTest test

Bug: webrtc:8243
Change-Id: I4b90a449b00dd05feee974001e08fb40710b59ac
Reviewed-on: https://webrtc-review.googlesource.com/13124
Commit-Queue: Alex Narest <alexnarest@webrtc.org>
Reviewed-by: Stefan Holmer <stefan@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#20345}
diff --git a/api/peerconnectioninterface.h b/api/peerconnectioninterface.h
index dd1f87c..f4ef859 100644
--- a/api/peerconnectioninterface.h
+++ b/api/peerconnectioninterface.h
@@ -786,6 +786,13 @@
   // to the provided value.
   virtual RTCError SetBitrate(const BitrateParameters& bitrate) = 0;
 
+  // Sets current strategy. If not set default WebRTC allocator will be used.
+  // May be changed during an active session. The strategy
+  // ownership is passed with std::unique_ptr
+  virtual void SetBitrateAllocationStrategy(
+      std::unique_ptr<rtc::BitrateAllocationStrategy>
+          bitrate_allocation_strategy) = 0;
+
   // Returns the current SignalingState.
   virtual SignalingState signaling_state() = 0;
   virtual IceConnectionState ice_connection_state() = 0;
diff --git a/api/peerconnectionproxy.h b/api/peerconnectionproxy.h
index c490b8f..a8ea3fa3 100644
--- a/api/peerconnectionproxy.h
+++ b/api/peerconnectionproxy.h
@@ -102,6 +102,9 @@
                 const std::vector<cricket::Candidate>&);
   PROXY_METHOD1(void, RegisterUMAObserver, UMAObserver*)
   PROXY_METHOD1(RTCError, SetBitrate, const BitrateParameters&);
+  PROXY_METHOD1(void,
+                SetBitrateAllocationStrategy,
+                std::unique_ptr<rtc::BitrateAllocationStrategy>);
   PROXY_METHOD0(SignalingState, signaling_state)
   PROXY_METHOD0(IceConnectionState, ice_connection_state)
   PROXY_METHOD0(IceGatheringState, ice_gathering_state)
diff --git a/audio/audio_send_stream.cc b/audio/audio_send_stream.cc
index 1cfc0ba..7895af3 100644
--- a/audio/audio_send_stream.cc
+++ b/audio/audio_send_stream.cc
@@ -236,6 +236,8 @@
 void AudioSendStream::Start() {
   RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
   if (config_.min_bitrate_bps != -1 && config_.max_bitrate_bps != -1) {
+    // Audio BWE is enabled.
+    transport_->packet_sender()->SetAccountForAudioPackets(true);
     ConfigureBitrateObserver(config_.min_bitrate_bps, config_.max_bitrate_bps);
   }
 
diff --git a/call/bitrate_allocator.cc b/call/bitrate_allocator.cc
index b379f7f..e186380 100644
--- a/call/bitrate_allocator.cc
+++ b/call/bitrate_allocator.cc
@@ -12,6 +12,7 @@
 #include "call/bitrate_allocator.h"
 
 #include <algorithm>
+#include <memory>
 #include <utility>
 
 #include "modules/bitrate_controller/include/bitrate_controller.h"
@@ -56,7 +57,8 @@
       clock_(Clock::GetRealTimeClock()),
       last_bwe_log_time_(0),
       total_requested_padding_bitrate_(0),
-      total_requested_min_bitrate_(0) {
+      total_requested_min_bitrate_(0),
+      bitrate_allocation_strategy_(nullptr) {
   sequenced_checker_.Detach();
 }
 
@@ -199,6 +201,7 @@
 
 void BitrateAllocator::RemoveObserver(BitrateAllocatorObserver* observer) {
   RTC_DCHECK_CALLED_SEQUENTIALLY(&sequenced_checker_);
+
   auto it = FindObserverConfig(observer);
   if (it != bitrate_observer_configs_.end()) {
     bitrate_observer_configs_.erase(it);
@@ -224,6 +227,13 @@
   }
 }
 
+void BitrateAllocator::SetBitrateAllocationStrategy(
+    std::unique_ptr<rtc::BitrateAllocationStrategy>
+        bitrate_allocation_strategy) {
+  RTC_DCHECK_CALLED_SEQUENTIALLY(&sequenced_checker_);
+  bitrate_allocation_strategy_ = std::move(bitrate_allocation_strategy);
+}
+
 BitrateAllocator::ObserverConfigs::iterator
 BitrateAllocator::FindObserverConfig(const BitrateAllocatorObserver* observer) {
   RTC_DCHECK_CALLED_SEQUENTIALLY(&sequenced_checker_);
@@ -241,6 +251,25 @@
   if (bitrate_observer_configs_.empty())
     return ObserverAllocation();
 
+  if (bitrate_allocation_strategy_ != nullptr) {
+    std::vector<const rtc::BitrateAllocationStrategy::TrackConfig*>
+        track_configs(bitrate_observer_configs_.size());
+    int i = 0;
+    for (const auto& c : bitrate_observer_configs_) {
+      track_configs[i++] = &c;
+    }
+    std::vector<uint32_t> track_allocations =
+        bitrate_allocation_strategy_->AllocateBitrates(bitrate, track_configs);
+    // The strategy should return allocation for all tracks.
+    RTC_CHECK(track_allocations.size() == bitrate_observer_configs_.size());
+    ObserverAllocation allocation;
+    auto track_allocations_it = track_allocations.begin();
+    for (const auto& observer_config : bitrate_observer_configs_) {
+      allocation[observer_config.observer] = *track_allocations_it++;
+    }
+    return allocation;
+  }
+
   if (bitrate == 0)
     return ZeroRateAllocation();
 
diff --git a/call/bitrate_allocator.h b/call/bitrate_allocator.h
index d51740c..cf518f6 100644
--- a/call/bitrate_allocator.h
+++ b/call/bitrate_allocator.h
@@ -14,10 +14,12 @@
 #include <stdint.h>
 
 #include <map>
+#include <memory>
 #include <string>
 #include <utility>
 #include <vector>
 
+#include "rtc_base/bitrateallocationstrategy.h"
 #include "rtc_base/sequenced_task_checker.h"
 
 namespace webrtc {
@@ -94,32 +96,35 @@
   // the list of added observers, a best guess is returned.
   int GetStartBitrate(BitrateAllocatorObserver* observer);
 
+  // Sets external allocation strategy. If strategy is not set default WebRTC
+  // allocation mechanism will be used. The strategy may be changed during call.
+  // Setting NULL value will restore default WEBRTC allocation strategy.
+  void SetBitrateAllocationStrategy(
+      std::unique_ptr<rtc::BitrateAllocationStrategy>
+          bitrate_allocation_strategy);
+
  private:
   // Note: All bitrates for member variables and methods are in bps.
-  struct ObserverConfig {
+  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)
-        : observer(observer),
-          min_bitrate_bps(min_bitrate_bps),
-          max_bitrate_bps(max_bitrate_bps),
+        : TrackConfig(min_bitrate_bps,
+                      max_bitrate_bps,
+                      enforce_min_bitrate,
+                      track_id),
+          observer(observer),
           pad_up_bitrate_bps(pad_up_bitrate_bps),
-          enforce_min_bitrate(enforce_min_bitrate),
           allocated_bitrate_bps(-1),
-          media_ratio(1.0),
-          track_id(track_id) {}
+          media_ratio(1.0) {}
 
     BitrateAllocatorObserver* observer;
-    uint32_t min_bitrate_bps;
-    uint32_t max_bitrate_bps;
     uint32_t pad_up_bitrate_bps;
-    bool enforce_min_bitrate;
     int64_t allocated_bitrate_bps;
     double media_ratio;  // Part of the total bitrate used for media [0.0, 1.0].
-    std::string track_id;
   };
 
   // Calculates the minimum requested send bitrate and max padding bitrate and
@@ -172,6 +177,8 @@
   int64_t last_bwe_log_time_ RTC_GUARDED_BY(&sequenced_checker_);
   uint32_t total_requested_padding_bitrate_ RTC_GUARDED_BY(&sequenced_checker_);
   uint32_t total_requested_min_bitrate_ RTC_GUARDED_BY(&sequenced_checker_);
+  std::unique_ptr<rtc::BitrateAllocationStrategy> bitrate_allocation_strategy_
+      RTC_GUARDED_BY(&sequenced_checker_);
 };
 }  // namespace webrtc
 #endif  // CALL_BITRATE_ALLOCATOR_H_
diff --git a/call/call.cc b/call/call.cc
index 215c103..90aaba3 100644
--- a/call/call.cc
+++ b/call/call.cc
@@ -214,6 +214,10 @@
   void SetBitrateConfigMask(
       const webrtc::Call::Config::BitrateConfigMask& bitrate_config) override;
 
+  void SetBitrateAllocationStrategy(
+      std::unique_ptr<rtc::BitrateAllocationStrategy>
+          bitrate_allocation_strategy) override;
+
   void SignalChannelNetworkState(MediaType media, NetworkState state) override;
 
   void OnTransportOverheadChanged(MediaType media,
@@ -1007,6 +1011,24 @@
   config_.bitrate_config = updated;
 }
 
+void Call::SetBitrateAllocationStrategy(
+    std::unique_ptr<rtc::BitrateAllocationStrategy>
+        bitrate_allocation_strategy) {
+  if (!worker_queue_.IsCurrent()) {
+    rtc::BitrateAllocationStrategy* strategy_raw =
+        bitrate_allocation_strategy.release();
+    auto functor = [this, strategy_raw]() {
+      SetBitrateAllocationStrategy(
+          rtc::WrapUnique<rtc::BitrateAllocationStrategy>(strategy_raw));
+    };
+    worker_queue_.PostTask([functor] { functor(); });
+    return;
+  }
+  RTC_DCHECK_RUN_ON(&worker_queue_);
+  bitrate_allocator_->SetBitrateAllocationStrategy(
+      std::move(bitrate_allocation_strategy));
+}
+
 void Call::SignalChannelNetworkState(MediaType media, NetworkState state) {
   RTC_DCHECK_CALLED_SEQUENTIALLY(&configuration_sequence_checker_);
   switch (media) {
diff --git a/call/call.h b/call/call.h
index f26d9d6..4de5b55 100644
--- a/call/call.h
+++ b/call/call.h
@@ -24,6 +24,7 @@
 #include "call/video_receive_stream.h"
 #include "call/video_send_stream.h"
 #include "common_types.h"  // NOLINT(build/include)
+#include "rtc_base/bitrateallocationstrategy.h"
 #include "rtc_base/networkroute.h"
 #include "rtc_base/platform_file.h"
 #include "rtc_base/socket.h"
@@ -183,6 +184,10 @@
   virtual void SetBitrateConfigMask(
       const Config::BitrateConfigMask& bitrate_mask) = 0;
 
+  virtual void SetBitrateAllocationStrategy(
+      std::unique_ptr<rtc::BitrateAllocationStrategy>
+          bitrate_allocation_strategy) = 0;
+
   // TODO(skvlad): When the unbundled case with multiple streams for the same
   // media type going over different networks is supported, track the state
   // for each stream separately. Right now it's global per media type.
diff --git a/call/rampup_tests.cc b/call/rampup_tests.cc
index 85346b74..1d58419 100644
--- a/call/rampup_tests.cc
+++ b/call/rampup_tests.cc
@@ -418,19 +418,21 @@
 
 void RampUpDownUpTester::PollStats() {
   do {
-    if (send_stream_) {
+    int transmit_bitrate_bps = 0;
+    bool suspended = false;
+    if (num_video_streams_ > 0) {
       webrtc::VideoSendStream::Stats stats = send_stream_->GetStats();
-      int transmit_bitrate_bps = 0;
       for (auto it : stats.substreams) {
         transmit_bitrate_bps += it.second.total_bitrate_bps;
       }
-      EvolveTestState(transmit_bitrate_bps, stats.suspended);
-    } else if (num_audio_streams_ > 0 && sender_call_ != nullptr) {
+      suspended = stats.suspended;
+    }
+    if (num_audio_streams_ > 0 && sender_call_ != nullptr) {
       // An audio send stream doesn't have bitrate stats, so the call send BW is
       // currently used instead.
-      int transmit_bitrate_bps = sender_call_->GetStats().send_bandwidth_bps;
-      EvolveTestState(transmit_bitrate_bps, false);
+      transmit_bitrate_bps = sender_call_->GetStats().send_bandwidth_bps;
     }
+    EvolveTestState(transmit_bitrate_bps, suspended);
   } while (!stop_event_.Wait(kPollIntervalMs));
 }
 
diff --git a/examples/BUILD.gn b/examples/BUILD.gn
index 0041d04..b7474d6 100644
--- a/examples/BUILD.gn
+++ b/examples/BUILD.gn
@@ -176,6 +176,7 @@
     if (is_ios) {
       deps = [
         ":AppRTCMobile_ios_frameworks",
+        "../rtc_base:rtc_base",
       ]
     } else {
       deps = [
@@ -206,6 +207,8 @@
       "objc/AppRTCMobile/ARDAppClient.m",
       "objc/AppRTCMobile/ARDAppEngineClient.h",
       "objc/AppRTCMobile/ARDAppEngineClient.m",
+      "objc/AppRTCMobile/ARDBitrateAllocationStrategy.h",
+      "objc/AppRTCMobile/ARDBitrateAllocationStrategy.mm",
       "objc/AppRTCMobile/ARDBitrateTracker.h",
       "objc/AppRTCMobile/ARDBitrateTracker.m",
       "objc/AppRTCMobile/ARDCaptureController.h",
@@ -249,6 +252,7 @@
     deps = [
       ":apprtc_common",
       ":socketrocket",
+      "../rtc_base:rtc_base",
     ]
     if (is_ios) {
       deps += [ ":AppRTCMobile_ios_frameworks" ]
diff --git a/examples/objc/AppRTCMobile/ARDAppClient.m b/examples/objc/AppRTCMobile/ARDAppClient.m
index 8e933b9..f606de0 100644
--- a/examples/objc/AppRTCMobile/ARDAppClient.m
+++ b/examples/objc/AppRTCMobile/ARDAppClient.m
@@ -25,6 +25,7 @@
 #import "WebRTC/RTCVideoTrack.h"
 
 #import "ARDAppEngineClient.h"
+#import "ARDBitrateAllocationStrategy.h"
 #import "ARDJoinResponse.h"
 #import "ARDMessageResponse.h"
 #import "ARDSettingsModel.h"
@@ -50,6 +51,7 @@
 static NSString * const kARDAudioTrackId = @"ARDAMSa0";
 static NSString * const kARDVideoTrackId = @"ARDAMSv0";
 static NSString * const kARDVideoTrackKind = @"video";
+static uint32_t const kSufficientAudioBitrate = 16000;
 
 // TODO(tkchin): Add these as UI options.
 static BOOL const kARDAppClientEnableTracing = NO;
@@ -104,6 +106,7 @@
   ARDTimerProxy *_statsTimer;
   ARDSettingsModel *_settings;
   RTCVideoTrack *_localVideoTrack;
+  ARDBitrateAllocationStrategy *_bitrateAllocationStrategy;
 }
 
 @synthesize shouldGetStats = _shouldGetStats;
@@ -306,12 +309,14 @@
   _hasReceivedSdp = NO;
   _messageQueue = [NSMutableArray array];
   _localVideoTrack = nil;
+
 #if defined(WEBRTC_IOS)
   [_factory stopAecDump];
   [_peerConnection stopRtcEventLog];
 #endif
   [_peerConnection close];
   _peerConnection = nil;
+  _bitrateAllocationStrategy = nil;
   self.state = kARDAppClientStateDisconnected;
 #if defined(WEBRTC_IOS)
   if (kARDAppClientEnableTracing) {
@@ -533,8 +538,14 @@
   _peerConnection = [_factory peerConnectionWithConfiguration:config
                                                   constraints:constraints
                                                      delegate:self];
+  _bitrateAllocationStrategy = [ARDBitrateAllocationStrategy
+      createAudioPriorityBitrateAllocationStrategyForPeerConnection:_peerConnection
+                                                     withAudioTrack:kARDAudioTrackId
+                                             sufficientAudioBitrate:kSufficientAudioBitrate];
+
   // Create AV senders.
   [self createMediaSenders];
+
   if (_isInitiator) {
     // Send offer.
     __weak ARDAppClient *weakSelf = self;
diff --git a/examples/objc/AppRTCMobile/ARDBitrateAllocationStrategy.h b/examples/objc/AppRTCMobile/ARDBitrateAllocationStrategy.h
new file mode 100644
index 0000000..18f83ea
--- /dev/null
+++ b/examples/objc/AppRTCMobile/ARDBitrateAllocationStrategy.h
@@ -0,0 +1,23 @@
+/*
+ *  Copyright 2017 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.
+ */
+
+#import <Foundation/Foundation.h>
+#import "WebRTC/RTCPeerConnection.h"
+
+@interface ARDBitrateAllocationStrategy : NSObject
+
++ (ARDBitrateAllocationStrategy*)
+    createAudioPriorityBitrateAllocationStrategyForPeerConnection:(RTCPeerConnection*)peerConnection
+                                                   withAudioTrack:(NSString*)audioTrackID
+                                           sufficientAudioBitrate:(uint32_t)sufficientAudioBitrate;
+
+- (instancetype)init NS_UNAVAILABLE;
+
+@end
diff --git a/examples/objc/AppRTCMobile/ARDBitrateAllocationStrategy.mm b/examples/objc/AppRTCMobile/ARDBitrateAllocationStrategy.mm
new file mode 100644
index 0000000..5901f8c
--- /dev/null
+++ b/examples/objc/AppRTCMobile/ARDBitrateAllocationStrategy.mm
@@ -0,0 +1,40 @@
+/*
+ *  Copyright 2017 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.
+ */
+
+#import "ARDBitrateAllocationStrategy.h"
+#import "WebRTC/RTCBitrateAllocationStrategy.h"
+
+#include "rtc_base/bitrateallocationstrategy.h"
+
+@implementation ARDBitrateAllocationStrategy
+
++ (ARDBitrateAllocationStrategy*)
+    createAudioPriorityBitrateAllocationStrategyForPeerConnection:(RTCPeerConnection*)peerConnection
+                                                   withAudioTrack:(NSString*)audioTrackID
+                                           sufficientAudioBitrate:(uint32_t)sufficientAudioBitrate {
+  return [[ARDBitrateAllocationStrategy alloc] initWithPeerCoonnection:peerConnection
+                                                        withAudioTrack:audioTrackID
+                                                sufficientAudioBitrate:sufficientAudioBitrate];
+}
+
+- (instancetype)initWithPeerCoonnection:(RTCPeerConnection*)peerConnection
+                         withAudioTrack:(NSString*)audioTrackID
+                 sufficientAudioBitrate:(uint32_t)sufficientAudioBitrate {
+  if (self = [super init]) {
+    [peerConnection
+        setBitrateAllocationStrategy:[[RTCBitrateAllocationStrategy alloc]
+                                         initWith:new rtc::AudioPriorityBitrateAllocationStrategy(
+                                                      std::string(audioTrackID.UTF8String),
+                                                      sufficientAudioBitrate)]];
+  }
+  return self;
+}
+
+@end
diff --git a/examples/objc/AppRTCMobile/ios/ARDAppDelegate.m b/examples/objc/AppRTCMobile/ios/ARDAppDelegate.m
index 07c83a0..20ae170 100644
--- a/examples/objc/AppRTCMobile/ios/ARDAppDelegate.m
+++ b/examples/objc/AppRTCMobile/ios/ARDAppDelegate.m
@@ -26,7 +26,8 @@
 - (BOOL)application:(UIApplication *)application
     didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
   NSDictionary *fieldTrials = @{
-    kRTCFieldTrialH264HighProfileKey: kRTCFieldTrialEnabledValue,
+    kRTCFieldTrialH264HighProfileKey : kRTCFieldTrialEnabledValue,
+    kRTCFieldTrialAudioSendSideBweKey : kRTCFieldTrialEnabledValue
   };
   RTCInitFieldTrialDictionary(fieldTrials);
   RTCInitializeSSL();
diff --git a/media/engine/fakewebrtccall.cc b/media/engine/fakewebrtccall.cc
index 8556cc7..d43c7ba 100644
--- a/media/engine/fakewebrtccall.cc
+++ b/media/engine/fakewebrtccall.cc
@@ -595,6 +595,12 @@
   // TODO(zstein): not implemented
 }
 
+void FakeCall::SetBitrateAllocationStrategy(
+    std::unique_ptr<rtc::BitrateAllocationStrategy>
+        bitrate_allocation_strategy){
+    // TODO(alexnarest): not implemented
+};
+
 void FakeCall::SignalChannelNetworkState(webrtc::MediaType media,
                                          webrtc::NetworkState state) {
   switch (media) {
diff --git a/media/engine/fakewebrtccall.h b/media/engine/fakewebrtccall.h
index 04dc5d9..3d0825d 100644
--- a/media/engine/fakewebrtccall.h
+++ b/media/engine/fakewebrtccall.h
@@ -296,6 +296,9 @@
       const webrtc::Call::Config::BitrateConfig& bitrate_config) override;
   void SetBitrateConfigMask(
       const webrtc::Call::Config::BitrateConfigMask& mask) override;
+  void SetBitrateAllocationStrategy(
+      std::unique_ptr<rtc::BitrateAllocationStrategy>
+          bitrate_allocation_strategy) override;
   void OnNetworkRouteChanged(const std::string& transport_name,
                              const rtc::NetworkRoute& network_route) override {}
   void SignalChannelNetworkState(webrtc::MediaType media,
diff --git a/modules/pacing/paced_sender.cc b/modules/pacing/paced_sender.cc
index e6b781e..ffc8cf3 100644
--- a/modules/pacing/paced_sender.cc
+++ b/modules/pacing/paced_sender.cc
@@ -62,7 +62,8 @@
       packets_(new PacketQueue(clock)),
       packet_counter_(0),
       pacing_factor_(kDefaultPaceMultiplier),
-      queue_time_limit(kMaxQueueLengthMs) {
+      queue_time_limit(kMaxQueueLengthMs),
+      account_for_audio_(false) {
   UpdateBudgetWithElapsedTime(kMinPacketLimitMs);
 }
 
@@ -153,6 +154,11 @@
                                      retransmission, packet_counter_++));
 }
 
+void PacedSender::SetAccountForAudioPackets(bool account_for_audio) {
+  rtc::CritScope cs(&critsect_);
+  account_for_audio_ = account_for_audio;
+}
+
 int64_t PacedSender::ExpectedQueueTimeMs() const {
   rtc::CritScope cs(&critsect_);
   RTC_DCHECK_GT(pacing_bitrate_kbps_, 0);
@@ -317,9 +323,7 @@
   critsect_.Enter();
 
   if (success) {
-    // TODO(holmer): High priority packets should only be accounted for if we
-    // are allocating bandwidth for audio.
-    if (packet.priority != kHighPriority) {
+    if (packet.priority != kHighPriority || account_for_audio_) {
       // Update media bytes sent.
       // TODO(eladalon): TimeToSendPacket() can also return |true| in some
       // situations where nothing actually ended up being sent to the network,
diff --git a/modules/pacing/paced_sender.h b/modules/pacing/paced_sender.h
index 458efb4..d8381ca 100644
--- a/modules/pacing/paced_sender.h
+++ b/modules/pacing/paced_sender.h
@@ -107,6 +107,12 @@
                     size_t bytes,
                     bool retransmission) override;
 
+  // Currently audio traffic is not accounted by pacer and passed through.
+  // With the introduction of audio BWE audio traffic will be accounted for
+  // the pacer budget calculation. The audio traffic still will be injected
+  // at high priority.
+  void SetAccountForAudioPackets(bool account_for_audio) override;
+
   // Returns the time since the oldest queued packet was enqueued.
   virtual int64_t QueueInMs() const;
 
@@ -190,6 +196,7 @@
 
   float pacing_factor_ RTC_GUARDED_BY(critsect_);
   int64_t queue_time_limit RTC_GUARDED_BY(critsect_);
+  bool account_for_audio_ RTC_GUARDED_BY(critsect_);
 };
 }  // namespace webrtc
 #endif  // MODULES_PACING_PACED_SENDER_H_
diff --git a/modules/remote_bitrate_estimator/test/bbr_paced_sender.h b/modules/remote_bitrate_estimator/test/bbr_paced_sender.h
index 6cb45e3..096f9d6 100644
--- a/modules/remote_bitrate_estimator/test/bbr_paced_sender.h
+++ b/modules/remote_bitrate_estimator/test/bbr_paced_sender.h
@@ -68,6 +68,7 @@
                     int64_t capture_time_ms,
                     size_t bytes,
                     bool retransmission) override;
+  void SetAccountForAudioPackets(bool account_for_audio) override {}
   int64_t TimeUntilNextProcess() override;
   void OnBytesAcked(size_t bytes) override;
   void Process() override;
diff --git a/modules/rtp_rtcp/include/rtp_rtcp_defines.h b/modules/rtp_rtcp/include/rtp_rtcp_defines.h
index 1e25f28..9023d68 100644
--- a/modules/rtp_rtcp/include/rtp_rtcp_defines.h
+++ b/modules/rtp_rtcp/include/rtp_rtcp_defines.h
@@ -498,6 +498,14 @@
                             int64_t capture_time_ms,
                             size_t bytes,
                             bool retransmission) = 0;
+
+  // Currently audio traffic is not accounted by pacer and passed through.
+  // With the introduction of audio BWE audio traffic will be accounted for
+  // the pacer budget calculation. The audio traffic still will be injected
+  // at high priority.
+  // TODO(alexnarest): Make it pure virtual after rtp_sender_unittest will be
+  // updated to support it
+  virtual void SetAccountForAudioPackets(bool account_for_audio) {}
 };
 
 class TransportSequenceNumberAllocator {
diff --git a/pc/peerconnection.cc b/pc/peerconnection.cc
index a78c290..9eb12d6 100644
--- a/pc/peerconnection.cc
+++ b/pc/peerconnection.cc
@@ -1293,6 +1293,24 @@
   return RTCError::OK();
 }
 
+void PeerConnection::SetBitrateAllocationStrategy(
+    std::unique_ptr<rtc::BitrateAllocationStrategy>
+        bitrate_allocation_strategy) {
+  rtc::Thread* worker_thread = factory_->worker_thread();
+  if (!worker_thread->IsCurrent()) {
+    rtc::BitrateAllocationStrategy* strategy_raw =
+        bitrate_allocation_strategy.release();
+    auto functor = [this, strategy_raw]() {
+      call_->SetBitrateAllocationStrategy(
+          rtc::WrapUnique<rtc::BitrateAllocationStrategy>(strategy_raw));
+    };
+    worker_thread->Invoke<void>(RTC_FROM_HERE, functor);
+    return;
+  }
+  RTC_DCHECK(call_.get());
+  call_->SetBitrateAllocationStrategy(std::move(bitrate_allocation_strategy));
+}
+
 std::unique_ptr<rtc::SSLCertificate>
 PeerConnection::GetRemoteAudioSSLCertificate() {
   if (!session_) {
diff --git a/pc/peerconnection.h b/pc/peerconnection.h
index 7d0be4d..116b249 100644
--- a/pc/peerconnection.h
+++ b/pc/peerconnection.h
@@ -145,6 +145,10 @@
 
   RTCError SetBitrate(const BitrateParameters& bitrate) override;
 
+  void SetBitrateAllocationStrategy(
+      std::unique_ptr<rtc::BitrateAllocationStrategy>
+          bitrate_allocation_strategy) override;
+
   RTC_DEPRECATED bool StartRtcEventLog(rtc::PlatformFile file,
                                        int64_t max_size_bytes) override;
   bool StartRtcEventLog(std::unique_ptr<RtcEventLogOutput> output) override;
diff --git a/rtc_base/BUILD.gn b/rtc_base/BUILD.gn
index 0646fb3..65b16e5 100644
--- a/rtc_base/BUILD.gn
+++ b/rtc_base/BUILD.gn
@@ -113,6 +113,8 @@
     "bind.h",
     "bitbuffer.cc",
     "bitbuffer.h",
+    "bitrateallocationstrategy.cc",
+    "bitrateallocationstrategy.h",
     "buffer.h",
     "bufferqueue.cc",
     "bufferqueue.h",
diff --git a/rtc_base/bitrateallocationstrategy.cc b/rtc_base/bitrateallocationstrategy.cc
new file mode 100644
index 0000000..66528d75
--- /dev/null
+++ b/rtc_base/bitrateallocationstrategy.cc
@@ -0,0 +1,125 @@
+/*
+ *  Copyright 2017 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 "rtc_base/bitrateallocationstrategy.h"
+#include <algorithm>
+#include <utility>
+
+namespace rtc {
+
+std::vector<uint32_t> BitrateAllocationStrategy::SetAllBitratesToMinimum(
+    const ArrayView<const TrackConfig*> track_configs) {
+  std::vector<uint32_t> track_allocations;
+  for (const auto* track_config : track_configs) {
+    track_allocations.push_back(track_config->min_bitrate_bps);
+  }
+  return track_allocations;
+}
+
+std::vector<uint32_t> BitrateAllocationStrategy::DistributeBitratesEvenly(
+    const ArrayView<const TrackConfig*> track_configs,
+    uint32_t available_bitrate) {
+  std::vector<uint32_t> track_allocations =
+      SetAllBitratesToMinimum(track_configs);
+  uint32_t sum_min_bitrates = 0;
+  uint32_t sum_max_bitrates = 0;
+  for (const auto* track_config : track_configs) {
+    sum_min_bitrates += track_config->min_bitrate_bps;
+    sum_max_bitrates += track_config->max_bitrate_bps;
+  }
+  if (sum_min_bitrates >= available_bitrate) {
+    return track_allocations;
+  } else if (available_bitrate >= sum_max_bitrates) {
+    auto track_allocations_it = track_allocations.begin();
+    for (const auto* track_config : track_configs) {
+      *track_allocations_it++ = track_config->max_bitrate_bps;
+    }
+    return track_allocations;
+  } else {
+    // If sum_min_bitrates < available_bitrate < sum_max_bitrates allocate
+    // bitrates evenly up to max_bitrate_bps starting from the track with the
+    // lowest max_bitrate_bps. Remainder of available bitrate split evenly among
+    // remaining tracks.
+    std::multimap<uint32_t, size_t> max_bitrate_sorted_configs;
+    for (const TrackConfig** track_configs_it = track_configs.begin();
+         track_configs_it != track_configs.end(); ++track_configs_it) {
+      max_bitrate_sorted_configs.insert(
+          std::make_pair((*track_configs_it)->max_bitrate_bps,
+                         track_configs_it - track_configs.begin()));
+    }
+    uint32_t total_available_increase = available_bitrate - sum_min_bitrates;
+    int processed_configs = 0;
+    for (const auto& track_config_pair : max_bitrate_sorted_configs) {
+      uint32_t available_increase =
+          total_available_increase /
+          (static_cast<uint32_t>(track_configs.size() - processed_configs));
+      uint32_t consumed_increase =
+          std::min(track_configs[track_config_pair.second]->max_bitrate_bps -
+                       track_configs[track_config_pair.second]->min_bitrate_bps,
+                   available_increase);
+      track_allocations[track_config_pair.second] += consumed_increase;
+      total_available_increase -= consumed_increase;
+      ++processed_configs;
+    }
+    return track_allocations;
+  }
+}
+
+AudioPriorityBitrateAllocationStrategy::AudioPriorityBitrateAllocationStrategy(
+    std::string audio_track_id,
+    uint32_t sufficient_audio_bitrate)
+    : audio_track_id_(audio_track_id),
+      sufficient_audio_bitrate_(sufficient_audio_bitrate) {}
+
+std::vector<uint32_t> AudioPriorityBitrateAllocationStrategy::AllocateBitrates(
+    uint32_t available_bitrate,
+    const ArrayView<const TrackConfig*> track_configs) {
+  const TrackConfig* audio_track_config = NULL;
+  size_t audio_config_index = 0;
+  uint32_t sum_min_bitrates = 0;
+
+  for (const auto*& track_config : track_configs) {
+    sum_min_bitrates += track_config->min_bitrate_bps;
+    if (track_config->track_id == audio_track_id_) {
+      audio_track_config = track_config;
+      audio_config_index = &track_config - &track_configs[0];
+    }
+  }
+  if (audio_track_config == nullptr) {
+    return DistributeBitratesEvenly(track_configs, available_bitrate);
+  }
+  auto safe_sufficient_audio_bitrate = std::min(
+      std::max(audio_track_config->min_bitrate_bps, sufficient_audio_bitrate_),
+      audio_track_config->max_bitrate_bps);
+  if (available_bitrate <= sum_min_bitrates) {
+    return SetAllBitratesToMinimum(track_configs);
+  } else {
+    if (available_bitrate <= sum_min_bitrates + safe_sufficient_audio_bitrate -
+                                 audio_track_config->min_bitrate_bps) {
+      std::vector<uint32_t> track_allocations =
+          SetAllBitratesToMinimum(track_configs);
+      track_allocations[audio_config_index] +=
+          available_bitrate - sum_min_bitrates;
+      return track_allocations;
+    } else {
+      // Setting audio track minimum to safe_sufficient_audio_bitrate will
+      // allow using DistributeBitratesEvenly to allocate at least sufficient
+      // bitrate for audio and the rest evenly.
+      TrackConfig sufficient_track_config(*track_configs[audio_config_index]);
+      sufficient_track_config.min_bitrate_bps = safe_sufficient_audio_bitrate;
+      track_configs[audio_config_index] = &sufficient_track_config;
+      std::vector<uint32_t> track_allocations =
+          DistributeBitratesEvenly(track_configs, available_bitrate);
+      return track_allocations;
+    }
+  }
+}
+
+}  // namespace rtc
diff --git a/rtc_base/bitrateallocationstrategy.h b/rtc_base/bitrateallocationstrategy.h
new file mode 100644
index 0000000..f711d1f
--- /dev/null
+++ b/rtc_base/bitrateallocationstrategy.h
@@ -0,0 +1,101 @@
+/*
+ *  Copyright 2017 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.
+ */
+
+#ifndef RTC_BASE_BITRATEALLOCATIONSTRATEGY_H_
+#define RTC_BASE_BITRATEALLOCATIONSTRATEGY_H_
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+#include "api/array_view.h"
+#include "rtc_base/checks.h"
+
+namespace rtc {
+
+// Pluggable strategy allows configuration of bitrate allocation per media
+// track.
+//
+// The strategy should provide allocation for every track passed with
+// track_configs in AllocateBitrates. The allocations are constrained by
+// max_bitrate_bps, min_bitrate_bps defining the track supported range and
+// enforce_min_bitrate indicating if the track my be paused by allocating 0
+// bitrate.
+class BitrateAllocationStrategy {
+ public:
+  struct TrackConfig {
+    TrackConfig(uint32_t min_bitrate_bps,
+                uint32_t max_bitrate_bps,
+                bool enforce_min_bitrate,
+                std::string track_id)
+        : min_bitrate_bps(min_bitrate_bps),
+          max_bitrate_bps(max_bitrate_bps),
+          enforce_min_bitrate(enforce_min_bitrate),
+          track_id(track_id) {}
+    TrackConfig(const TrackConfig& track_config) = default;
+    virtual ~TrackConfig() = default;
+    TrackConfig() {}
+
+    // Minimum bitrate supported by track.
+    uint32_t min_bitrate_bps;
+
+    // Maximum bitrate supported by track.
+    uint32_t max_bitrate_bps;
+
+    // True means track may not be paused by allocating 0 bitrate.
+    bool enforce_min_bitrate;
+
+    // MediaStreamTrack ID as defined by application. May be empty.
+    std::string track_id;
+  };
+
+  static std::vector<uint32_t> SetAllBitratesToMinimum(
+      const ArrayView<const TrackConfig*> track_configs);
+  static std::vector<uint32_t> DistributeBitratesEvenly(
+      const ArrayView<const TrackConfig*> track_configs,
+      uint32_t available_bitrate);
+
+  // Strategy is expected to allocate all available_bitrate up to the sum of
+  // max_bitrate_bps of all tracks. If available_bitrate is less than the sum of
+  // min_bitrate_bps of all tracks, tracks having enforce_min_bitrate set to
+  // false may get 0 allocation and are suppoused to pause, tracks with
+  // enforce_min_bitrate set to true are expecting to get min_bitrate_bps.
+  //
+  // If the strategy will allocate more than available_bitrate it may cause
+  // overuse of the currently available network capacity and may cause increase
+  // in RTT and packet loss. Allocating less than available bitrate may cause
+  // available_bitrate decrease.
+  virtual std::vector<uint32_t> AllocateBitrates(
+      uint32_t available_bitrate,
+      const ArrayView<const TrackConfig*> track_configs) = 0;
+
+  virtual ~BitrateAllocationStrategy() = default;
+};
+
+// Simple allocation strategy giving priority to audio until
+// sufficient_audio_bitrate is reached. Bitrate is distributed evenly between
+// the tracks after sufficient_audio_bitrate is reached. This implementation
+// does not pause tracks even if enforce_min_bitrate is false.
+class AudioPriorityBitrateAllocationStrategy
+    : public BitrateAllocationStrategy {
+ public:
+  AudioPriorityBitrateAllocationStrategy(std::string audio_track_id,
+                                         uint32_t sufficient_audio_bitrate);
+  std::vector<uint32_t> AllocateBitrates(
+      uint32_t available_bitrate,
+      const ArrayView<const TrackConfig*> track_configs) override;
+
+ private:
+  std::string audio_track_id_;
+  uint32_t sufficient_audio_bitrate_;
+};
+}  // namespace rtc
+
+#endif  // RTC_BASE_BITRATEALLOCATIONSTRATEGY_H_
diff --git a/sdk/BUILD.gn b/sdk/BUILD.gn
index 1401132..d415158 100644
--- a/sdk/BUILD.gn
+++ b/sdk/BUILD.gn
@@ -386,6 +386,7 @@
         "objc/Framework/Classes/PeerConnection/RTCAudioSource.mm",
         "objc/Framework/Classes/PeerConnection/RTCAudioTrack+Private.h",
         "objc/Framework/Classes/PeerConnection/RTCAudioTrack.mm",
+        "objc/Framework/Classes/PeerConnection/RTCBitrateAllocationStrategy.mm",
         "objc/Framework/Classes/PeerConnection/RTCConfiguration+Private.h",
         "objc/Framework/Classes/PeerConnection/RTCConfiguration.mm",
         "objc/Framework/Classes/PeerConnection/RTCDataChannel+Private.h",
@@ -453,6 +454,7 @@
         "objc/Framework/Headers/WebRTC/RTCAVFoundationVideoSource.h",
         "objc/Framework/Headers/WebRTC/RTCAudioSource.h",
         "objc/Framework/Headers/WebRTC/RTCAudioTrack.h",
+        "objc/Framework/Headers/WebRTC/RTCBitrateAllocationStrategy.h",
         "objc/Framework/Headers/WebRTC/RTCConfiguration.h",
         "objc/Framework/Headers/WebRTC/RTCDataChannel.h",
         "objc/Framework/Headers/WebRTC/RTCDataChannelConfiguration.h",
diff --git a/sdk/objc/Framework/Classes/PeerConnection/RTCBitrateAllocationStrategy.mm b/sdk/objc/Framework/Classes/PeerConnection/RTCBitrateAllocationStrategy.mm
new file mode 100644
index 0000000..bc99767
--- /dev/null
+++ b/sdk/objc/Framework/Classes/PeerConnection/RTCBitrateAllocationStrategy.mm
@@ -0,0 +1,28 @@
+/*
+ *  Copyright 2017 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.
+ */
+
+#import "WebRTC/RTCBitrateAllocationStrategy.h"
+
+#include "rtc_base/bitrateallocationstrategy.h"
+#include "rtc_base/checks.h"
+
+@implementation RTCBitrateAllocationStrategy
+
+@synthesize strategy = _strategy;
+
+- (instancetype)initWith:(rtc::BitrateAllocationStrategy*)strategy {
+  RTC_DCHECK(strategy);
+  if (self = [super init]) {
+    _strategy = strategy;
+  }
+  return self;
+}
+
+@end
diff --git a/sdk/objc/Framework/Classes/PeerConnection/RTCConfiguration.mm b/sdk/objc/Framework/Classes/PeerConnection/RTCConfiguration.mm
index b9a9e4b..17aed85 100644
--- a/sdk/objc/Framework/Classes/PeerConnection/RTCConfiguration.mm
+++ b/sdk/objc/Framework/Classes/PeerConnection/RTCConfiguration.mm
@@ -178,7 +178,6 @@
     nativeConfig->ice_regather_interval_range =
         rtc::Optional<rtc::IntervalRange>(*nativeIntervalRange);
   }
-
   return nativeConfig.release();
 }
 
diff --git a/sdk/objc/Framework/Classes/PeerConnection/RTCPeerConnection.mm b/sdk/objc/Framework/Classes/PeerConnection/RTCPeerConnection.mm
index e443e85..4fcc634 100644
--- a/sdk/objc/Framework/Classes/PeerConnection/RTCPeerConnection.mm
+++ b/sdk/objc/Framework/Classes/PeerConnection/RTCPeerConnection.mm
@@ -21,6 +21,7 @@
 #import "RTCRtpReceiver+Private.h"
 #import "RTCRtpSender+Private.h"
 #import "RTCSessionDescription+Private.h"
+#import "WebRTC/RTCBitrateAllocationStrategy.h"
 #import "WebRTC/RTCLogging.h"
 
 #include <memory>
@@ -385,6 +386,15 @@
   return _peerConnection->SetBitrate(params).ok();
 }
 
+- (void)setBitrateAllocationStrategy:
+        (RTCBitrateAllocationStrategy *_Nullable)bitrateAllocationStrategy {
+  if (bitrateAllocationStrategy)
+    _peerConnection->SetBitrateAllocationStrategy(
+        std::unique_ptr<rtc::BitrateAllocationStrategy>(bitrateAllocationStrategy.strategy));
+  else
+    _peerConnection->SetBitrateAllocationStrategy(nullptr);
+}
+
 - (BOOL)startRtcEventLogWithFilePath:(NSString *)filePath
                       maxSizeInBytes:(int64_t)maxSizeInBytes {
   RTC_DCHECK(filePath.length);
diff --git a/sdk/objc/Framework/Headers/WebRTC/RTCBitrateAllocationStrategy.h b/sdk/objc/Framework/Headers/WebRTC/RTCBitrateAllocationStrategy.h
new file mode 100644
index 0000000..c510008
--- /dev/null
+++ b/sdk/objc/Framework/Headers/WebRTC/RTCBitrateAllocationStrategy.h
@@ -0,0 +1,32 @@
+/*
+ *  Copyright 2017 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.
+ */
+
+#import <WebRTC/RTCMacros.h>
+#import <WebRTC/RTCMediaStreamTrack.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+namespace rtc {
+
+class BitrateAllocationStrategy;
+}
+
+RTC_EXPORT
+@interface RTCBitrateAllocationStrategy : NSObject
+
+- (instancetype)init NS_UNAVAILABLE;
+- (instancetype)initWith:(rtc::BitrateAllocationStrategy*)strategy;
+
+/** Native bitrate allocation strategy. */
+@property(nonatomic, readonly) rtc::BitrateAllocationStrategy* strategy;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/Framework/Headers/WebRTC/RTCPeerConnection.h b/sdk/objc/Framework/Headers/WebRTC/RTCPeerConnection.h
index 7b0c449..c74af13 100644
--- a/sdk/objc/Framework/Headers/WebRTC/RTCPeerConnection.h
+++ b/sdk/objc/Framework/Headers/WebRTC/RTCPeerConnection.h
@@ -24,6 +24,7 @@
 @class RTCRtpSender;
 @class RTCSessionDescription;
 @class RTCLegacyStatsReport;
+@class RTCBitrateAllocationStrategy;
 
 NS_ASSUME_NONNULL_BEGIN
 
@@ -193,6 +194,13 @@
           currentBitrateBps:(nullable NSNumber *)currentBitrateBps
               maxBitrateBps:(nullable NSNumber *)maxBitrateBps;
 
+/** Sets current strategy. If not set default WebRTC allocator will be used.
+ *   May be changed during an active session. The strategy
+ *   ownership is passed with std::unique_ptr
+ */
+- (void)setBitrateAllocationStrategy:
+        (RTCBitrateAllocationStrategy *_Nullable)bitrateAllocationStrategy;
+
 /** Start or stop recording an Rtc EventLog. */
 - (BOOL)startRtcEventLogWithFilePath:(NSString *)filePath
                       maxSizeInBytes:(int64_t)maxSizeInBytes;
diff --git a/voice_engine/channel.cc b/voice_engine/channel.cc
index 542ea2d..0130d42 100644
--- a/voice_engine/channel.cc
+++ b/voice_engine/channel.cc
@@ -215,6 +215,10 @@
     }
   }
 
+  void SetAccountForAudioPackets(bool account_for_audio) override {
+    RTC_NOTREACHED();
+  }
+
  private:
   rtc::ThreadChecker thread_checker_;
   rtc::CriticalSection crit_;