Introduce a send time history class, keeping track of packet send times.

BUG=4308
R=stefan@webrtc.org

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

Cr-Commit-Position: refs/heads/master@{#8546}
git-svn-id: http://webrtc.googlecode.com/svn/trunk@8546 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
sprang@webrtc.org 2015-03-02 09:05:47 +00:00
parent 59ae5ff310
commit f35e4bc694
6 changed files with 259 additions and 0 deletions

View File

@ -17,6 +17,8 @@ source_set("bitrate_controller") {
"remb_suppressor.h", "remb_suppressor.h",
"send_side_bandwidth_estimation.cc", "send_side_bandwidth_estimation.cc",
"send_side_bandwidth_estimation.h", "send_side_bandwidth_estimation.h",
"send_time_history.cc",
"send_time_history.h",
] ]
if (is_win) { if (is_win) {

View File

@ -22,6 +22,8 @@
'remb_suppressor.h', 'remb_suppressor.h',
'send_side_bandwidth_estimation.cc', 'send_side_bandwidth_estimation.cc',
'send_side_bandwidth_estimation.h', 'send_side_bandwidth_estimation.h',
'send_time_history.cc',
'send_time_history.h',
], ],
# TODO(jschuh): Bug 1348: fix size_t to int truncations. # TODO(jschuh): Bug 1348: fix size_t to int truncations.
'msvs_disabled_warnings': [ 4267, ], 'msvs_disabled_warnings': [ 4267, ],

View File

@ -0,0 +1,83 @@
/*
* Copyright (c) 2015 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 <assert.h>
#include "webrtc/modules/bitrate_controller/send_time_history.h"
namespace webrtc {
SendTimeHistory::SendTimeHistory(int64_t packet_age_limit)
: packet_age_limit_(packet_age_limit), oldest_sequence_number_(0) {
}
SendTimeHistory::~SendTimeHistory() {
}
void SendTimeHistory::Clear() {
history_.clear();
}
void SendTimeHistory::AddAndRemoveOldSendTimes(uint16_t sequence_number,
int64_t timestamp) {
EraseOld(timestamp - packet_age_limit_);
if (history_.empty())
oldest_sequence_number_ = sequence_number;
history_[sequence_number] = timestamp;
}
void SendTimeHistory::EraseOld(int64_t limit) {
while (!history_.empty()) {
auto it = history_.find(oldest_sequence_number_);
assert(it != history_.end());
if (it->second <= limit) {
// Packet too old, remove it.
history_.erase(it);
// TODO(sprang): Warn if erasing (too many) old items?
} else {
// Oldest packet within age limit, return.
return;
}
if (history_.empty())
return;
// After removing element from the map, update oldest_sequence_number_ to
// the element with the lowest sequence number higher than the previous
// value (there might be gaps).
it = history_.upper_bound(oldest_sequence_number_);
if (it == history_.end()) {
// No element with higher sequence number than oldest_sequence_number_
// found, check wrap around. Note that history_.upper_bound(0) will not
// find 0 even if it is there, need to explicitly check for 0.
it = history_.find(0);
if (it == history_.end())
it = history_.upper_bound(0);
}
assert(it != history_.end());
oldest_sequence_number_ = it->first;
}
}
bool SendTimeHistory::GetSendTime(uint16_t sequence_number,
int64_t* timestamp,
bool remove) {
auto it = history_.find(sequence_number);
if (it == history_.end())
return false;
*timestamp = it->second;
if (remove)
history_.erase(it);
return true;
}
} // namespace webrtc

View File

@ -0,0 +1,41 @@
/*
* Copyright (c) 2015 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_BITRATE_CONTROLLER_SEND_TIME_HISTORY_H_
#define WEBRTC_MODULES_BITRATE_CONTROLLER_SEND_TIME_HISTORY_H_
#include <map>
#include "webrtc/base/constructormagic.h"
#include "webrtc/base/basictypes.h"
namespace webrtc {
class SendTimeHistory {
public:
explicit SendTimeHistory(int64_t packet_age_limit);
virtual ~SendTimeHistory();
void AddAndRemoveOldSendTimes(uint16_t sequence_number, int64_t timestamp);
bool GetSendTime(uint16_t sequence_number, int64_t* timestamp, bool remove);
void Clear();
private:
void EraseOld(int64_t limit);
const int64_t packet_age_limit_;
uint16_t oldest_sequence_number_; // Oldest may not be lowest.
std::map<uint16_t, int64_t> history_;
DISALLOW_COPY_AND_ASSIGN(SendTimeHistory);
};
} // namespace webrtc
#endif // WEBRTC_MODULES_BITRATE_CONTROLLER_SEND_TIME_HISTORY_H_

View File

@ -0,0 +1,130 @@
/*
* Copyright (c) 2015 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 <algorithm>
#include <limits>
#include <vector>
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/modules/bitrate_controller/send_time_history.h"
#include "webrtc/system_wrappers/interface/clock.h"
namespace webrtc {
static const int kDefaultHistoryLengthMs = 1000;
class SendTimeHistoryTest : public ::testing::Test {
protected:
SendTimeHistoryTest() : history_(kDefaultHistoryLengthMs), clock_(0) {}
~SendTimeHistoryTest() {}
virtual void SetUp() {}
virtual void TearDown() {}
SendTimeHistory history_;
webrtc::SimulatedClock clock_;
};
TEST_F(SendTimeHistoryTest, AddRemoveOne) {
const uint16_t kSeqNo = 1;
const int64_t kTimestamp = 2;
history_.AddAndRemoveOldSendTimes(kSeqNo, kTimestamp);
int64_t time = 0;
EXPECT_TRUE(history_.GetSendTime(kSeqNo, &time, false));
EXPECT_EQ(kTimestamp, time);
time = 0;
EXPECT_TRUE(history_.GetSendTime(kSeqNo, &time, true));
EXPECT_EQ(kTimestamp, time);
time = 0;
EXPECT_FALSE(history_.GetSendTime(kSeqNo, &time, true));
}
TEST_F(SendTimeHistoryTest, AddThenRemoveOutOfOrder) {
struct Timestamp {
Timestamp(uint16_t sequence_number, int64_t timestamp)
: sequence_number(sequence_number), timestamp(timestamp) {}
uint16_t sequence_number;
int64_t timestamp;
};
std::vector<Timestamp> timestamps;
const size_t num_items = 100;
for (size_t i = 0; i < num_items; ++i) {
timestamps.push_back(
Timestamp(static_cast<uint16_t>(i), static_cast<int64_t>(i)));
}
std::vector<Timestamp> randomized_timestamps = timestamps;
std::random_shuffle(randomized_timestamps.begin(),
randomized_timestamps.end());
for (size_t i = 0; i < num_items; ++i) {
history_.AddAndRemoveOldSendTimes(timestamps[i].sequence_number,
timestamps[i].timestamp);
}
for (size_t i = 0; i < num_items; ++i) {
int64_t timestamp;
EXPECT_TRUE(history_.GetSendTime(randomized_timestamps[i].sequence_number,
&timestamp, false));
EXPECT_EQ(randomized_timestamps[i].timestamp, timestamp);
EXPECT_TRUE(history_.GetSendTime(randomized_timestamps[i].sequence_number,
&timestamp, true));
}
for (size_t i = 0; i < num_items; ++i) {
int64_t timestamp;
EXPECT_FALSE(
history_.GetSendTime(timestamps[i].sequence_number, &timestamp, false));
}
}
TEST_F(SendTimeHistoryTest, HistorySize) {
const int kItems = kDefaultHistoryLengthMs / 100;
for (int i = 0; i < kItems; ++i) {
history_.AddAndRemoveOldSendTimes(i, i * 100);
}
int64_t timestamp;
for (int i = 0; i < kItems; ++i) {
EXPECT_TRUE(history_.GetSendTime(i, &timestamp, false));
EXPECT_EQ(i * 100, timestamp);
}
history_.AddAndRemoveOldSendTimes(kItems, kItems * 100);
EXPECT_FALSE(history_.GetSendTime(0, &timestamp, false));
for (int i = 1; i < (kItems + 1); ++i) {
EXPECT_TRUE(history_.GetSendTime(i, &timestamp, false));
EXPECT_EQ(i * 100, timestamp);
}
}
TEST_F(SendTimeHistoryTest, HistorySizeWithWraparound) {
const int kMaxSeqNo = std::numeric_limits<uint16_t>::max();
history_.AddAndRemoveOldSendTimes(kMaxSeqNo - 2, 0);
history_.AddAndRemoveOldSendTimes(kMaxSeqNo - 1, 100);
history_.AddAndRemoveOldSendTimes(kMaxSeqNo, 200);
history_.AddAndRemoveOldSendTimes(0, 1000);
int64_t timestamp;
EXPECT_FALSE(history_.GetSendTime(kMaxSeqNo - 2, &timestamp, false));
EXPECT_TRUE(history_.GetSendTime(kMaxSeqNo - 1, &timestamp, false));
EXPECT_TRUE(history_.GetSendTime(kMaxSeqNo, &timestamp, false));
EXPECT_TRUE(history_.GetSendTime(0, &timestamp, false));
// Create a gap (kMaxSeqNo - 1) -> 0.
EXPECT_TRUE(history_.GetSendTime(kMaxSeqNo, &timestamp, true));
history_.AddAndRemoveOldSendTimes(1, 1100);
EXPECT_FALSE(history_.GetSendTime(kMaxSeqNo - 2, &timestamp, false));
EXPECT_FALSE(history_.GetSendTime(kMaxSeqNo - 1, &timestamp, false));
EXPECT_FALSE(history_.GetSendTime(kMaxSeqNo, &timestamp, false));
EXPECT_TRUE(history_.GetSendTime(0, &timestamp, false));
EXPECT_TRUE(history_.GetSendTime(1, &timestamp, false));
}
} // namespace webrtc

View File

@ -188,6 +188,7 @@
'bitrate_controller/bitrate_controller_unittest.cc', 'bitrate_controller/bitrate_controller_unittest.cc',
'bitrate_controller/remb_suppressor_unittest.cc', 'bitrate_controller/remb_suppressor_unittest.cc',
'bitrate_controller/send_side_bandwidth_estimation_unittest.cc', 'bitrate_controller/send_side_bandwidth_estimation_unittest.cc',
'bitrate_controller/send_time_history_unittest.cc',
'desktop_capture/desktop_and_cursor_composer_unittest.cc', 'desktop_capture/desktop_and_cursor_composer_unittest.cc',
'desktop_capture/desktop_region_unittest.cc', 'desktop_capture/desktop_region_unittest.cc',
'desktop_capture/differ_block_unittest.cc', 'desktop_capture/differ_block_unittest.cc',