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:
parent
59ae5ff310
commit
f35e4bc694
@ -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) {
|
||||||
|
@ -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, ],
|
||||||
|
83
webrtc/modules/bitrate_controller/send_time_history.cc
Normal file
83
webrtc/modules/bitrate_controller/send_time_history.cc
Normal 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
|
41
webrtc/modules/bitrate_controller/send_time_history.h
Normal file
41
webrtc/modules/bitrate_controller/send_time_history.h
Normal 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_
|
130
webrtc/modules/bitrate_controller/send_time_history_unittest.cc
Normal file
130
webrtc/modules/bitrate_controller/send_time_history_unittest.cc
Normal 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,
|
||||||
|
×tamp, false));
|
||||||
|
EXPECT_EQ(randomized_timestamps[i].timestamp, timestamp);
|
||||||
|
EXPECT_TRUE(history_.GetSendTime(randomized_timestamps[i].sequence_number,
|
||||||
|
×tamp, true));
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < num_items; ++i) {
|
||||||
|
int64_t timestamp;
|
||||||
|
EXPECT_FALSE(
|
||||||
|
history_.GetSendTime(timestamps[i].sequence_number, ×tamp, 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, ×tamp, false));
|
||||||
|
EXPECT_EQ(i * 100, timestamp);
|
||||||
|
}
|
||||||
|
history_.AddAndRemoveOldSendTimes(kItems, kItems * 100);
|
||||||
|
EXPECT_FALSE(history_.GetSendTime(0, ×tamp, false));
|
||||||
|
for (int i = 1; i < (kItems + 1); ++i) {
|
||||||
|
EXPECT_TRUE(history_.GetSendTime(i, ×tamp, 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, ×tamp, false));
|
||||||
|
EXPECT_TRUE(history_.GetSendTime(kMaxSeqNo - 1, ×tamp, false));
|
||||||
|
EXPECT_TRUE(history_.GetSendTime(kMaxSeqNo, ×tamp, false));
|
||||||
|
EXPECT_TRUE(history_.GetSendTime(0, ×tamp, false));
|
||||||
|
|
||||||
|
// Create a gap (kMaxSeqNo - 1) -> 0.
|
||||||
|
EXPECT_TRUE(history_.GetSendTime(kMaxSeqNo, ×tamp, true));
|
||||||
|
|
||||||
|
history_.AddAndRemoveOldSendTimes(1, 1100);
|
||||||
|
|
||||||
|
EXPECT_FALSE(history_.GetSendTime(kMaxSeqNo - 2, ×tamp, false));
|
||||||
|
EXPECT_FALSE(history_.GetSendTime(kMaxSeqNo - 1, ×tamp, false));
|
||||||
|
EXPECT_FALSE(history_.GetSendTime(kMaxSeqNo, ×tamp, false));
|
||||||
|
EXPECT_TRUE(history_.GetSendTime(0, ×tamp, false));
|
||||||
|
EXPECT_TRUE(history_.GetSendTime(1, ×tamp, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace webrtc
|
@ -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',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user