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@5202 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
sprang@webrtc.org 2013-12-03 10:31:59 +00:00
parent b613b5ab2b
commit 37968a9be7
7 changed files with 100 additions and 97 deletions

View File

@ -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',

View File

@ -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_

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
* 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
@ -8,26 +8,24 @@
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/modules/remote_bitrate_estimator/bitrate_estimator.h"
#include "webrtc/modules/remote_bitrate_estimator/rate_statistics.h"
namespace webrtc {
const int kBitrateAverageWindowMs = 500;
BitRateStats::BitRateStats()
: num_buckets_(kBitrateAverageWindowMs + 1), // N ms in (N+1) buckets.
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_bytes_(0),
accumulated_count_(0),
oldest_time_(0),
oldest_index_(0),
bps_coefficient_(8.f * 1000.f / (num_buckets_ - 1)) {
scale_(scale / (num_buckets_ - 1)) {
}
BitRateStats::~BitRateStats() {
RateStatistics::~RateStatistics() {
}
void BitRateStats::Init() {
accumulated_bytes_ = 0;
void RateStatistics::Reset() {
accumulated_count_ = 0;
oldest_time_ = 0;
oldest_index_ = 0;
for (int i = 0; i < num_buckets_; i++) {
@ -35,7 +33,7 @@ void BitRateStats::Init() {
}
}
void BitRateStats::Update(uint32_t packet_size_bytes, int64_t now_ms) {
void RateStatistics::Update(uint32_t count, int64_t now_ms) {
if (now_ms < oldest_time_) {
// Too old data is ignored.
return;
@ -49,31 +47,31 @@ void BitRateStats::Update(uint32_t packet_size_bytes, int64_t now_ms) {
if (index >= num_buckets_) {
index -= num_buckets_;
}
buckets_[index] += packet_size_bytes;
accumulated_bytes_ += packet_size_bytes;
buckets_[index] += count;
accumulated_count_ += count;
}
uint32_t BitRateStats::BitRate(int64_t now_ms) {
uint32_t RateStatistics::Rate(int64_t now_ms) {
EraseOld(now_ms);
return static_cast<uint32_t>(accumulated_bytes_ * bps_coefficient_ + 0.5f);
return static_cast<uint32_t>(accumulated_count_ * scale_ + 0.5f);
}
void BitRateStats::EraseOld(int64_t now_ms) {
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 num_bytes_in_oldest_bucket = buckets_[oldest_index_];
assert(accumulated_bytes_ >= num_bytes_in_oldest_bucket);
accumulated_bytes_ -= num_bytes_in_oldest_bucket;
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_bytes_ == 0) {
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;
@ -81,4 +79,5 @@ void BitRateStats::EraseOld(int64_t now_ms) {
}
oldest_time_ = new_oldest_time;
}
} // namespace webrtc

View File

@ -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_

View File

@ -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 @@ TEST_F(BitRateStatsTest, TestStrictMode) {
// 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 @@ TEST_F(BitRateStatsTest, IncreasingThenDecreasingBitrate) {
// 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 @@ TEST_F(BitRateStatsTest, IncreasingThenDecreasingBitrate) {
// 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

View File

@ -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
},

View File

@ -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 @@ class RemoteBitrateEstimatorSingleStream : public RemoteBitrateEstimator {
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 @@ RemoteBitrateEstimatorSingleStream::RemoteBitrateEstimatorSingleStream(
RemoteBitrateObserver* observer,
Clock* clock)
: clock_(clock),
incoming_bitrate_(500, 8000),
observer_(observer),
crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
last_process_time_(-1) {
@ -106,7 +107,7 @@ void RemoteBitrateEstimatorSingleStream::IncomingPacket(
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 @@ void RemoteBitrateEstimatorSingleStream::UpdateEstimate(int64_t time_now) {
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);