BWE allocation strategy allows controlling of bitrate allocation with WEBRTC external logic.

This CL implements the main logic and IOS appRTC integration.

Unit tests and Android appRTC will be in separate CL.

Bug: webrtc:8243
Change-Id: If8e5195294046a47316e9fade1b0dfec211155e1
Reviewed-on: https://webrtc-review.googlesource.com/4860
Commit-Queue: Alex Narest <alexnarest@webrtc.org>
Reviewed-by: Niels Moller <nisse@webrtc.org>
Reviewed-by: Stefan Holmer <stefan@webrtc.org>
Reviewed-by: Taylor Brandstetter <deadbeef@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#20329}
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_