blob: deeeb9013b65d5ae91760bf291744041faa07ed2 [file] [log] [blame]
/*
* 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 "gtest/gtest.h"
#include "webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework.h"
#include "webrtc/modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h"
#include "webrtc/system_wrappers/interface/clock.h"
#include "webrtc/system_wrappers/interface/constructor_magic.h"
#include "webrtc/system_wrappers/interface/scoped_ptr.h"
#define ENABLE_1_SENDER 1
#define ENABLE_3_SENDERS 1
#define ENABLE_10_SENDERS 1
#define ENABLE_BASIC_TESTS 1
#define ENABLE_LOSS_TESTS 0
#define ENABLE_DELAY_TESTS 0
#define ENABLE_JITTER_TESTS 0
#define ENABLE_REORDER_TESTS 0
#define ENABLE_CHOKE_TESTS 0
#define ENABLE_MULTI_TESTS 0
#define ENABLE_TOF_ESTIMATOR 1
#define ENABLE_AST_ESTIMATOR 1
using std::vector;
namespace webrtc {
namespace testing {
namespace bwe {
const int64_t kSimulationIntervalMs = 1000;
namespace stl_helpers {
template<typename T> void DeleteElements(T* container) {
if (!container) return;
for (typename T::iterator it = container->begin(); it != container->end();
++it) {
delete *it;
}
container->clear();
}
} // namespace stl_helpers
class TestedEstimator : public RemoteBitrateObserver {
public:
TestedEstimator(const std::string& debug_name,
const RemoteBitrateEstimatorFactory& factory)
: debug_name_(debug_name),
clock_(0),
stats_(),
relative_estimator_stats_(),
latest_estimate_kbps_(-1.0),
estimator_(factory.Create(this, &clock_)),
relative_estimator_(NULL) {
assert(estimator_.get());
// Default RTT in RemoteRateControl is 200 ms ; 50 ms is more realistic.
estimator_->OnRttUpdate(50);
}
void SetRelativeEstimator(TestedEstimator* relative_estimator) {
relative_estimator_ = relative_estimator;
}
void EatPacket(const BwePacket& packet) {
BWE_TEST_LOGGING_CONTEXT(debug_name_);
latest_estimate_kbps_ = -1.0;
// We're treating the send time (from previous filter) as the arrival
// time once packet reaches the estimator.
int64_t packet_time_ms = (packet.send_time_us() + 500) / 1000;
BWE_TEST_LOGGING_TIME(packet_time_ms);
int64_t step_ms = estimator_->TimeUntilNextProcess();
while ((clock_.TimeInMilliseconds() + step_ms) < packet_time_ms) {
clock_.AdvanceTimeMilliseconds(step_ms);
estimator_->Process();
step_ms = estimator_->TimeUntilNextProcess();
}
estimator_->IncomingPacket(packet_time_ms, packet.payload_size(),
packet.header());
clock_.AdvanceTimeMilliseconds(packet_time_ms -
clock_.TimeInMilliseconds());
ASSERT_TRUE(packet_time_ms == clock_.TimeInMilliseconds());
}
void CheckEstimate() {
BWE_TEST_LOGGING_CONTEXT(debug_name_);
double estimated_kbps = 0.0;
if (LatestEstimate(&estimated_kbps)) {
stats_.Push(estimated_kbps);
BWE_TEST_LOGGING_PLOT("Estimate", clock_.TimeInMilliseconds(),
estimated_kbps / 100);
double relative_estimate_kbps = 0.0;
if (relative_estimator_ &&
relative_estimator_->LatestEstimate(&relative_estimate_kbps)) {
relative_estimator_stats_.Push(estimated_kbps - relative_estimate_kbps);
}
}
}
void LogStats() {
BWE_TEST_LOGGING_CONTEXT(debug_name_);
BWE_TEST_LOGGING_CONTEXT("Mean");
stats_.Log("kbps");
if (relative_estimator_) {
BWE_TEST_LOGGING_CONTEXT("Diff");
relative_estimator_stats_.Log("kbps");
}
}
virtual void OnReceiveBitrateChanged(const vector<unsigned int>& ssrcs,
unsigned int bitrate) {
}
private:
bool LatestEstimate(double* estimate_kbps) {
if (latest_estimate_kbps_ < 0.0) {
vector<unsigned int> ssrcs;
unsigned int bps = 0;
if (!estimator_->LatestEstimate(&ssrcs, &bps)) {
return false;
}
latest_estimate_kbps_ = bps / 1000.0;
}
*estimate_kbps = latest_estimate_kbps_;
return true;
}
std::string debug_name_;
bool log_estimates_;
SimulatedClock clock_;
Stats<double> stats_;
Stats<double> relative_estimator_stats_;
double latest_estimate_kbps_;
scoped_ptr<RemoteBitrateEstimator> estimator_;
TestedEstimator* relative_estimator_;
DISALLOW_IMPLICIT_CONSTRUCTORS(TestedEstimator);
};
class RemoteBitrateEstimatorsTest : public ::testing::Test {
public:
RemoteBitrateEstimatorsTest()
: run_time_ms_(0),
estimators_(),
previous_packets_(),
processors_(),
video_senders_() {
}
virtual ~RemoteBitrateEstimatorsTest() {
stl_helpers::DeleteElements(&estimators_);
stl_helpers::DeleteElements(&video_senders_);
}
virtual void SetUp() {
#if ENABLE_TOF_ESTIMATOR
estimators_.push_back(new TestedEstimator("TOF",
RemoteBitrateEstimatorFactory()));
#endif
#if ENABLE_AST_ESTIMATOR
estimators_.push_back(new TestedEstimator("AST",
AbsoluteSendTimeRemoteBitrateEstimatorFactory()));
#endif
// Set all estimators as relative to the first one.
for (uint32_t i = 1; i < estimators_.size(); ++i) {
estimators_[i]->SetRelativeEstimator(estimators_[0]);
}
}
protected:
void RunFor(int64_t time_ms) {
for (run_time_ms_ += time_ms; run_time_ms_ >= kSimulationIntervalMs;
run_time_ms_ -= kSimulationIntervalMs) {
Packets packets;
for (vector<PacketProcessorInterface*>::const_iterator it =
processors_.begin(); it != processors_.end(); ++it) {
(*it)->RunFor(kSimulationIntervalMs, &packets);
}
// Verify packets are in order between batches.
if (!packets.empty() && !previous_packets_.empty()) {
packets.splice(packets.begin(), previous_packets_,
--previous_packets_.end());
ASSERT_TRUE(IsTimeSorted(packets));
packets.erase(packets.begin());
} else {
ASSERT_TRUE(IsTimeSorted(packets));
}
for (PacketsConstIt pit = packets.begin(); pit != packets.end(); ++pit) {
for (vector<TestedEstimator*>::iterator eit = estimators_.begin();
eit != estimators_.end(); ++eit) {
(*eit)->EatPacket(*pit);
}
}
previous_packets_.swap(packets);
for (vector<TestedEstimator*>::iterator eit = estimators_.begin();
eit != estimators_.end(); ++eit) {
(*eit)->CheckEstimate();
}
}
}
void AddVideoSenders(uint32_t count) {
struct { float fps; uint32_t kbps; uint32_t ssrc; float frame_offset; }
configs[] = {
{ 30.00f, 150, 0x1234, 0.13f },
{ 15.00f, 500, 0x2345, 0.16f },
{ 30.00f, 1200, 0x3456, 0.26f },
{ 7.49f, 150, 0x4567, 0.05f },
{ 7.50f, 150, 0x5678, 0.15f },
{ 7.51f, 150, 0x6789, 0.25f },
{ 15.02f, 150, 0x7890, 0.27f },
{ 15.03f, 150, 0x8901, 0.38f },
{ 30.02f, 150, 0x9012, 0.39f },
{ 30.03f, 150, 0x0123, 0.52f }
};
assert(count <= sizeof(configs) / sizeof(configs[0]));
uint32_t total_capacity = 0;
for (uint32_t i = 0; i < count; ++i) {
video_senders_.push_back(new VideoSender(configs[i].fps, configs[i].kbps,
configs[i].ssrc, configs[i].frame_offset));
processors_.push_back(video_senders_.back());
total_capacity += configs[i].kbps;
}
BWE_TEST_LOGGING_LOG1("RequiredLinkCapacity", "%d kbps", total_capacity)
}
void LogStats() {
for (vector<TestedEstimator*>::iterator eit = estimators_.begin();
eit != estimators_.end(); ++eit) {
(*eit)->LogStats();
}
}
void UnlimitedSpeedTest() {
RunFor(10 * 60 * 1000);
}
void SteadyLossTest() {
LossFilter loss;
processors_.push_back(&loss);
loss.SetLoss(20.0);
RunFor(10 * 60 * 1000);
}
void IncreasingLoss1Test() {
LossFilter loss;
processors_.push_back(&loss);
for (int i = 0; i < 76; ++i) {
loss.SetLoss(i);
RunFor(5000);
}
}
void SteadyDelayTest() {
DelayFilter delay;
processors_.push_back(&delay);
delay.SetDelay(1000);
RunFor(10 * 60 * 1000);
}
void IncreasingDelay1Test() {
DelayFilter delay;
processors_.push_back(&delay);
RunFor(10 * 60 * 1000);
for (int i = 0; i < 30 * 2; ++i) {
delay.SetDelay(i);
RunFor(10 * 1000);
}
RunFor(10 * 60 * 1000);
}
void IncreasingDelay2Test() {
DelayFilter delay;
RateCounterFilter counter;
processors_.push_back(&delay);
processors_.push_back(&counter);
RunFor(1 * 60 * 1000);
for (int i = 1; i < 51; ++i) {
delay.SetDelay(10.0f * i);
RunFor(10 * 1000);
}
delay.SetDelay(0.0f);
RunFor(10 * 60 * 1000);
}
void JumpyDelay1Test() {
DelayFilter delay;
processors_.push_back(&delay);
RunFor(10 * 60 * 1000);
for (int i = 1; i < 200; ++i) {
delay.SetDelay((10 * i) % 500);
RunFor(1000);
delay.SetDelay(1.0f);
RunFor(1000);
}
delay.SetDelay(0.0f);
RunFor(10 * 60 * 1000);
}
void SteadyJitterTest() {
JitterFilter jitter;
RateCounterFilter counter;
processors_.push_back(&jitter);
processors_.push_back(&counter);
jitter.SetJitter(20);
RunFor(2 * 60 * 1000);
}
void IncreasingJitter1Test() {
JitterFilter jitter;
processors_.push_back(&jitter);
for (int i = 0; i < 2 * 60 * 2; ++i) {
jitter.SetJitter(i);
RunFor(10 * 1000);
}
RunFor(10 * 60 * 1000);
}
void IncreasingJitter2Test() {
JitterFilter jitter;
processors_.push_back(&jitter);
RunFor(30 * 1000);
for (int i = 1; i < 51; ++i) {
jitter.SetJitter(10.0f * i);
RunFor(10 * 1000);
}
jitter.SetJitter(0.0f);
RunFor(10 * 60 * 1000);
}
void SteadyReorderTest() {
ReorderFilter reorder;
processors_.push_back(&reorder);
reorder.SetReorder(20.0);
RunFor(10 * 60 * 1000);
}
void IncreasingReorder1Test() {
ReorderFilter reorder;
processors_.push_back(&reorder);
for (int i = 0; i < 76; ++i) {
reorder.SetReorder(i);
RunFor(5000);
}
}
void SteadyChokeTest() {
ChokeFilter choke;
processors_.push_back(&choke);
choke.SetCapacity(140);
RunFor(10 * 60 * 1000);
}
void IncreasingChoke1Test() {
ChokeFilter choke;
processors_.push_back(&choke);
for (int i = 1200; i >= 100; i -= 100) {
choke.SetCapacity(i);
RunFor(5000);
}
}
void IncreasingChoke2Test() {
ChokeFilter choke;
processors_.push_back(&choke);
RunFor(60 * 1000);
for (int i = 1200; i >= 100; i -= 20) {
choke.SetCapacity(i);
RunFor(1000);
}
}
void Multi1Test() {
DelayFilter delay;
ChokeFilter choke;
RateCounterFilter counter;
processors_.push_back(&delay);
processors_.push_back(&choke);
processors_.push_back(&counter);
choke.SetCapacity(1000);
RunFor(1 * 60 * 1000);
for (int i = 1; i < 51; ++i) {
delay.SetDelay(100.0f * i);
RunFor(10 * 1000);
}
delay.SetDelay(0.0f);
RunFor(5 * 60 * 1000);
}
void Multi2Test() {
ChokeFilter choke;
JitterFilter jitter;
RateCounterFilter counter;
processors_.push_back(&choke);
processors_.push_back(&jitter);
processors_.push_back(&counter);
choke.SetCapacity(2000);
jitter.SetJitter(120);
RunFor(5 * 60 * 1000);
}
private:
int64_t run_time_ms_;
vector<TestedEstimator*> estimators_;
Packets previous_packets_;
vector<PacketProcessorInterface*> processors_;
vector<VideoSender*> video_senders_;
DISALLOW_COPY_AND_ASSIGN(RemoteBitrateEstimatorsTest);
};
#define SINGLE_TEST(enabled, test_name, video_senders, log)\
TEST_F(RemoteBitrateEstimatorsTest, test_name##_##video_senders##Sender) {\
BWE_TEST_LOGGING_ENABLE(log);\
if (enabled) {\
BWE_TEST_LOGGING_CONTEXT(#test_name);\
AddVideoSenders(video_senders);\
test_name##Test();\
LogStats();\
}\
}
#define MULTI_TEST(enabled, test_name, log)\
SINGLE_TEST((enabled) && ENABLE_1_SENDER, test_name, 1, log)\
SINGLE_TEST((enabled) && ENABLE_3_SENDERS, test_name, 3, log)\
SINGLE_TEST((enabled) && ENABLE_10_SENDERS, test_name, 10, log)
MULTI_TEST(ENABLE_BASIC_TESTS, UnlimitedSpeed, true)
MULTI_TEST(ENABLE_LOSS_TESTS, SteadyLoss, true)
MULTI_TEST(ENABLE_LOSS_TESTS, IncreasingLoss1, true)
MULTI_TEST(ENABLE_DELAY_TESTS, SteadyDelay, true)
MULTI_TEST(ENABLE_DELAY_TESTS, IncreasingDelay1, true)
MULTI_TEST(ENABLE_DELAY_TESTS, IncreasingDelay2, true)
MULTI_TEST(ENABLE_DELAY_TESTS, JumpyDelay1, true)
MULTI_TEST(ENABLE_JITTER_TESTS, SteadyJitter, true)
MULTI_TEST(ENABLE_JITTER_TESTS, IncreasingJitter1, true)
MULTI_TEST(ENABLE_JITTER_TESTS, IncreasingJitter2, true)
MULTI_TEST(ENABLE_REORDER_TESTS, SteadyReorder, true)
MULTI_TEST(ENABLE_REORDER_TESTS, IncreasingReorder1, true)
MULTI_TEST(ENABLE_CHOKE_TESTS, SteadyChoke, true)
MULTI_TEST(ENABLE_CHOKE_TESTS, IncreasingChoke1, true)
MULTI_TEST(ENABLE_CHOKE_TESTS, IncreasingChoke2, true)
MULTI_TEST(ENABLE_MULTI_TESTS, Multi1, true)
MULTI_TEST(ENABLE_MULTI_TESTS, Multi2, true)
} // namespace bwe
} // namespace testing
} // namespace webrtc