Change BitrateStats to more generalized RateStatistics

BUG=2656
R=holmer@google.com, mflodman@webrtc.org, stefan@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/4559004

git-svn-id: http://webrtc.googlecode.com/svn/trunk/webrtc@5202 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/modules/modules.gyp b/modules/modules.gyp
index 65c4827..5c2f77f 100644
--- a/modules/modules.gyp
+++ b/modules/modules.gyp
@@ -173,7 +173,7 @@
             'module_common_types_unittest.cc',
             'pacing/paced_sender_unittest.cc',
             'remote_bitrate_estimator/include/mock/mock_remote_bitrate_observer.h',
-            'remote_bitrate_estimator/bitrate_estimator_unittest.cc',
+            'remote_bitrate_estimator/rate_statistics_unittest.cc',
             'remote_bitrate_estimator/remote_bitrate_estimator_single_stream_unittest.cc',
             'remote_bitrate_estimator/remote_bitrate_estimator_unittest_helper.cc',
             'remote_bitrate_estimator/remote_bitrate_estimator_unittest_helper.h',
diff --git a/modules/remote_bitrate_estimator/bitrate_estimator.cc b/modules/remote_bitrate_estimator/bitrate_estimator.cc
deleted file mode 100644
index 8934d43..0000000
--- a/modules/remote_bitrate_estimator/bitrate_estimator.cc
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- *  Copyright (c) 2012 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 "webrtc/modules/remote_bitrate_estimator/bitrate_estimator.h"
-
-namespace webrtc {
-
-const int kBitrateAverageWindowMs = 500;
-
-BitRateStats::BitRateStats()
-    : num_buckets_(kBitrateAverageWindowMs + 1),  // N ms in (N+1) buckets.
-      buckets_(new uint32_t[num_buckets_]()),
-      accumulated_bytes_(0),
-      oldest_time_(0),
-      oldest_index_(0),
-      bps_coefficient_(8.f * 1000.f / (num_buckets_ - 1)) {
-}
-
-BitRateStats::~BitRateStats() {
-}
-
-void BitRateStats::Init() {
-  accumulated_bytes_ = 0;
-  oldest_time_ = 0;
-  oldest_index_ = 0;
-  for (int i = 0; i < num_buckets_; i++) {
-    buckets_[i] = 0;
-  }
-}
-
-void BitRateStats::Update(uint32_t packet_size_bytes, int64_t now_ms) {
-  if (now_ms < oldest_time_) {
-    // Too old data is ignored.
-    return;
-  }
-
-  EraseOld(now_ms);
-
-  int now_offset = static_cast<int>(now_ms - oldest_time_);
-  assert(now_offset < num_buckets_);
-  int index = oldest_index_ + now_offset;
-  if (index >= num_buckets_) {
-    index -= num_buckets_;
-  }
-  buckets_[index] += packet_size_bytes;
-  accumulated_bytes_ += packet_size_bytes;
-}
-
-uint32_t BitRateStats::BitRate(int64_t now_ms) {
-  EraseOld(now_ms);
-  return static_cast<uint32_t>(accumulated_bytes_ * bps_coefficient_ + 0.5f);
-}
-
-void BitRateStats::EraseOld(int64_t now_ms) {
-  int64_t new_oldest_time = now_ms - num_buckets_ + 1;
-  if (new_oldest_time <= oldest_time_) {
-    return;
-  }
-
-  while (oldest_time_ < new_oldest_time) {
-    uint32_t num_bytes_in_oldest_bucket = buckets_[oldest_index_];
-    assert(accumulated_bytes_ >= num_bytes_in_oldest_bucket);
-    accumulated_bytes_ -= num_bytes_in_oldest_bucket;
-    buckets_[oldest_index_] = 0;
-    if (++oldest_index_ >= num_buckets_) {
-      oldest_index_ = 0;
-    }
-    ++oldest_time_;
-    if (accumulated_bytes_ == 0) {
-      // This guarantees we go through all the buckets at most once, even if
-      // |new_oldest_time| is far greater than |oldest_time_|.
-      break;
-    }
-  }
-  oldest_time_ = new_oldest_time;
-}
-}  // namespace webrtc
diff --git a/modules/remote_bitrate_estimator/bitrate_estimator.h b/modules/remote_bitrate_estimator/bitrate_estimator.h
deleted file mode 100644
index 9ee31eb..0000000
--- a/modules/remote_bitrate_estimator/bitrate_estimator.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- *  Copyright (c) 2012 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 WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_BITRATE_ESTIMATOR_H_
-#define WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_BITRATE_ESTIMATOR_H_
-
-#include "webrtc/system_wrappers/interface/scoped_ptr.h"
-#include "webrtc/typedefs.h"
-
-namespace webrtc {
-
-class BitRateStats {
- public:
-  BitRateStats();
-  ~BitRateStats();
-
-  void Init();
-  void Update(uint32_t packet_size_bytes, int64_t now_ms);
-  uint32_t BitRate(int64_t now_ms);
-
- private:
-  void EraseOld(int64_t now_ms);
-
-  // Numbers of bytes are kept in buckets (circular buffer), with one bucket
-  // per millisecond.
-  const int num_buckets_;
-  scoped_array<uint32_t> buckets_;
-
-  // Total number of bytes recorded in buckets.
-  uint32_t accumulated_bytes_;
-
-  // Oldest time recorded in buckets.
-  int64_t oldest_time_;
-
-  // Bucket index of oldest bytes recorded in buckets.
-  int oldest_index_;
-
-  // To convert number of bytes in bits/second.
-  const float bps_coefficient_;
-};
-}  // namespace webrtc
-
-#endif  // WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_BITRATE_ESTIMATOR_H_
diff --git a/modules/remote_bitrate_estimator/rate_statistics.cc b/modules/remote_bitrate_estimator/rate_statistics.cc
new file mode 100644
index 0000000..4a9b448
--- /dev/null
+++ b/modules/remote_bitrate_estimator/rate_statistics.cc
@@ -0,0 +1,83 @@
+/*
+ *  Copyright (c) 2013 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 "webrtc/modules/remote_bitrate_estimator/rate_statistics.h"
+
+namespace webrtc {
+
+RateStatistics::RateStatistics(uint32_t window_size_ms, float scale)
+    : num_buckets_(window_size_ms + 1),  // N ms in (N+1) buckets.
+      buckets_(new uint32_t[num_buckets_]()),
+      accumulated_count_(0),
+      oldest_time_(0),
+      oldest_index_(0),
+      scale_(scale / (num_buckets_ - 1)) {
+}
+
+RateStatistics::~RateStatistics() {
+}
+
+void RateStatistics::Reset() {
+  accumulated_count_ = 0;
+  oldest_time_ = 0;
+  oldest_index_ = 0;
+  for (int i = 0; i < num_buckets_; i++) {
+    buckets_[i] = 0;
+  }
+}
+
+void RateStatistics::Update(uint32_t count, int64_t now_ms) {
+  if (now_ms < oldest_time_) {
+    // Too old data is ignored.
+    return;
+  }
+
+  EraseOld(now_ms);
+
+  int now_offset = static_cast<int>(now_ms - oldest_time_);
+  assert(now_offset < num_buckets_);
+  int index = oldest_index_ + now_offset;
+  if (index >= num_buckets_) {
+    index -= num_buckets_;
+  }
+  buckets_[index] += count;
+  accumulated_count_ += count;
+}
+
+uint32_t RateStatistics::Rate(int64_t now_ms) {
+  EraseOld(now_ms);
+  return static_cast<uint32_t>(accumulated_count_ * scale_ + 0.5f);
+}
+
+void RateStatistics::EraseOld(int64_t now_ms) {
+  int64_t new_oldest_time = now_ms - num_buckets_ + 1;
+  if (new_oldest_time <= oldest_time_) {
+    return;
+  }
+
+  while (oldest_time_ < new_oldest_time) {
+    uint32_t count_in_oldest_bucket = buckets_[oldest_index_];
+    assert(accumulated_count_ >= count_in_oldest_bucket);
+    accumulated_count_ -= count_in_oldest_bucket;
+    buckets_[oldest_index_] = 0;
+    if (++oldest_index_ >= num_buckets_) {
+      oldest_index_ = 0;
+    }
+    ++oldest_time_;
+    if (accumulated_count_ == 0) {
+      // This guarantees we go through all the buckets at most once, even if
+      // |new_oldest_time| is far greater than |oldest_time_|.
+      break;
+    }
+  }
+  oldest_time_ = new_oldest_time;
+}
+
+}  // namespace webrtc
diff --git a/modules/remote_bitrate_estimator/rate_statistics.h b/modules/remote_bitrate_estimator/rate_statistics.h
new file mode 100644
index 0000000..4296690
--- /dev/null
+++ b/modules/remote_bitrate_estimator/rate_statistics.h
@@ -0,0 +1,53 @@
+/*
+ *  Copyright (c) 2013 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 WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_RATE_STATISTICS_H_
+#define WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_RATE_STATISTICS_H_
+
+#include "webrtc/system_wrappers/interface/scoped_ptr.h"
+#include "webrtc/typedefs.h"
+
+namespace webrtc {
+
+class RateStatistics {
+ public:
+  // window_size = window size in ms for the rate estimation
+  // scale = coefficient to convert counts/ms to desired units,
+  //         ex: if counts represents bytes, use 8*1000 to go to bits/s
+  RateStatistics(uint32_t window_size_ms, float scale);
+  ~RateStatistics();
+
+  void Reset();
+  void Update(uint32_t count, int64_t now_ms);
+  uint32_t Rate(int64_t now_ms);
+
+ private:
+  void EraseOld(int64_t now_ms);
+
+  // Counters are kept in buckets (circular buffer), with one bucket
+  // per millisecond.
+  const int num_buckets_;
+  scoped_array<uint32_t> buckets_;
+
+  // Total count recorded in buckets.
+  uint32_t accumulated_count_;
+
+  // Oldest time recorded in buckets.
+  int64_t oldest_time_;
+
+  // Bucket index of oldest counter recorded in buckets.
+  int oldest_index_;
+
+  // To convert counts/ms to desired units
+  const float scale_;
+};
+}  // namespace webrtc
+
+#endif  // WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_RATE_STATISTICS_H_
diff --git a/modules/remote_bitrate_estimator/bitrate_estimator_unittest.cc b/modules/remote_bitrate_estimator/rate_statistics_unittest.cc
similarity index 74%
rename from modules/remote_bitrate_estimator/bitrate_estimator_unittest.cc
rename to modules/remote_bitrate_estimator/rate_statistics_unittest.cc
index 3d49ca4..0cbab30 100644
--- a/modules/remote_bitrate_estimator/bitrate_estimator_unittest.cc
+++ b/modules/remote_bitrate_estimator/rate_statistics_unittest.cc
@@ -9,28 +9,28 @@
  */
 
 #include "testing/gtest/include/gtest/gtest.h"
-#include "webrtc/modules/remote_bitrate_estimator/bitrate_estimator.h"
+#include "webrtc/modules/remote_bitrate_estimator/rate_statistics.h"
 
 namespace {
 
-using webrtc::BitRateStats;
+using webrtc::RateStatistics;
 
-class BitRateStatsTest : public ::testing::Test {
+class RateStatisticsTest : public ::testing::Test {
  protected:
-  BitRateStatsTest() {}
-  BitRateStats stats_;
+  RateStatisticsTest() : stats_(500, 8000) {}
+  RateStatistics stats_;
 };
 
-TEST_F(BitRateStatsTest, TestStrictMode) {
+TEST_F(RateStatisticsTest, TestStrictMode) {
   int64_t now_ms = 0;
   // Should be initialized to 0.
-  EXPECT_EQ(0u, stats_.BitRate(now_ms));
+  EXPECT_EQ(0u, stats_.Rate(now_ms));
   stats_.Update(1500, now_ms);
   // Expecting 24 kbps given a 500 ms window with one 1500 bytes packet.
-  EXPECT_EQ(24000u, stats_.BitRate(now_ms));
-  stats_.Init();
+  EXPECT_EQ(24000u, stats_.Rate(now_ms));
+  stats_.Reset();
   // Expecting 0 after init.
-  EXPECT_EQ(0u, stats_.BitRate(now_ms));
+  EXPECT_EQ(0u, stats_.Rate(now_ms));
   for (int i = 0; i < 100000; ++i) {
     if (now_ms % 10 == 0) {
       stats_.Update(1500, now_ms);
@@ -38,26 +38,26 @@
     // Approximately 1200 kbps expected. Not exact since when packets
     // are removed we will jump 10 ms to the next packet.
     if (now_ms > 0 && now_ms % 500 == 0) {
-      EXPECT_NEAR(1200000u, stats_.BitRate(now_ms), 24000u);
+      EXPECT_NEAR(1200000u, stats_.Rate(now_ms), 24000u);
     }
     now_ms += 1;
   }
   now_ms += 500;
   // The window is 2 seconds. If nothing has been received for that time
   // the estimate should be 0.
-  EXPECT_EQ(0u, stats_.BitRate(now_ms));
+  EXPECT_EQ(0u, stats_.Rate(now_ms));
 }
 
-TEST_F(BitRateStatsTest, IncreasingThenDecreasingBitrate) {
+TEST_F(RateStatisticsTest, IncreasingThenDecreasingBitrate) {
   int64_t now_ms = 0;
-  stats_.Init();
+  stats_.Reset();
   // Expecting 0 after init.
-  uint32_t bitrate = stats_.BitRate(now_ms);
+  uint32_t bitrate = stats_.Rate(now_ms);
   EXPECT_EQ(0u, bitrate);
   // 1000 bytes per millisecond until plateau is reached.
   while (++now_ms < 10000) {
     stats_.Update(1000, now_ms);
-    uint32_t new_bitrate = stats_.BitRate(now_ms);
+    uint32_t new_bitrate = stats_.Rate(now_ms);
     if (new_bitrate != bitrate) {
       // New bitrate must be higher than previous one.
       EXPECT_GT(new_bitrate, bitrate);
@@ -71,13 +71,13 @@
   // 1000 bytes per millisecond until 10-second mark, 8000 kbps expected.
   while (++now_ms < 10000) {
     stats_.Update(1000, now_ms);
-    bitrate = stats_.BitRate(now_ms);
+    bitrate = stats_.Rate(now_ms);
     EXPECT_NEAR(8000000u, bitrate, 80000u);
   }
   // Zero bytes per millisecond until 0 is reached.
   while (++now_ms < 20000) {
     stats_.Update(0, now_ms);
-    uint32_t new_bitrate = stats_.BitRate(now_ms);
+    uint32_t new_bitrate = stats_.Rate(now_ms);
     if (new_bitrate != bitrate) {
       // New bitrate must be lower than previous one.
       EXPECT_LT(new_bitrate, bitrate);
@@ -91,7 +91,7 @@
   // Zero bytes per millisecond until 20-second mark, 0 kbps expected.
   while (++now_ms < 20000) {
     stats_.Update(0, now_ms);
-    EXPECT_EQ(0u, stats_.BitRate(now_ms));
+    EXPECT_EQ(0u, stats_.Rate(now_ms));
   }
 }
 }  // namespace
diff --git a/modules/remote_bitrate_estimator/remote_bitrate_estimator.gypi b/modules/remote_bitrate_estimator/remote_bitrate_estimator.gypi
index f8f7e43..bbd353f 100644
--- a/modules/remote_bitrate_estimator/remote_bitrate_estimator.gypi
+++ b/modules/remote_bitrate_estimator/remote_bitrate_estimator.gypi
@@ -22,8 +22,8 @@
         'include/bwe_defines.h',
         'include/remote_bitrate_estimator.h',
         'include/rtp_to_ntp.h',
-        'bitrate_estimator.cc',
-        'bitrate_estimator.h',
+        'rate_statistics.cc',
+        'rate_statistics.h',
         'rtp_to_ntp.cc',
       ], # source
     },
diff --git a/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream.cc b/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream.cc
index 8eec342..69ebab4 100644
--- a/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream.cc
+++ b/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream.cc
@@ -10,7 +10,7 @@
 
 #include <map>
 
-#include "webrtc/modules/remote_bitrate_estimator/bitrate_estimator.h"
+#include "webrtc/modules/remote_bitrate_estimator/rate_statistics.h"
 #include "webrtc/modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h"
 #include "webrtc/modules/remote_bitrate_estimator/overuse_detector.h"
 #include "webrtc/modules/remote_bitrate_estimator/remote_rate_control.h"
@@ -63,7 +63,7 @@
 
   Clock* clock_;
   SsrcOveruseDetectorMap overuse_detectors_;
-  BitRateStats incoming_bitrate_;
+  RateStatistics incoming_bitrate_;
   RemoteRateControl remote_rate_;
   RemoteBitrateObserver* observer_;
   scoped_ptr<CriticalSectionWrapper> crit_sect_;
@@ -74,6 +74,7 @@
     RemoteBitrateObserver* observer,
     Clock* clock)
     : clock_(clock),
+      incoming_bitrate_(500, 8000),
       observer_(observer),
       crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
       last_process_time_(-1) {
@@ -106,7 +107,7 @@
   const BandwidthUsage prior_state = overuse_detector->State();
   overuse_detector->Update(payload_size, -1, rtp_timestamp, arrival_time_ms);
   if (overuse_detector->State() == kBwOverusing) {
-    unsigned int incoming_bitrate = incoming_bitrate_.BitRate(arrival_time_ms);
+    unsigned int incoming_bitrate = incoming_bitrate_.Rate(arrival_time_ms);
     if (prior_state != kBwOverusing ||
         remote_rate_.TimeToReduceFurther(arrival_time_ms, incoming_bitrate)) {
       // The first overuse should immediately trigger a new estimate.
@@ -164,7 +165,7 @@
   double mean_noise_var = sum_noise_var /
       static_cast<double>(overuse_detectors_.size());
   const RateControlInput input(bw_state,
-                               incoming_bitrate_.BitRate(time_now),
+                               incoming_bitrate_.Rate(time_now),
                                mean_noise_var);
   const RateControlRegion region = remote_rate_.Update(&input, time_now);
   unsigned int target_bitrate = remote_rate_.UpdateBandwidthEstimate(time_now);