Add trace-based delivery filter to BWE test framework.

R=mflodman@webrtc.org, solenberg@webrtc.org

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

git-svn-id: http://webrtc.googlecode.com/svn/trunk@5423 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
stefan@webrtc.org 2014-01-24 10:00:27 +00:00
parent c279a5d72c
commit 99a8c7e039
16 changed files with 175 additions and 35 deletions

View File

@ -0,0 +1 @@
2a4617e3497d8faa2fdccfa8964da26499eb13d6

View File

@ -0,0 +1 @@
8ea680a570df53fba206b984f38d4762481322eb

View File

@ -0,0 +1 @@
fd7ea55f4009359a78928af5c43e84b2b4101f50

View File

@ -0,0 +1 @@
46ac4f207c9437b1c4a35c3e398da65354f49742

View File

@ -0,0 +1 @@
72c5686ceebec94c9388ba9869d98caaf3a8b4a9

View File

@ -0,0 +1 @@
1998229c3ded7222faa4fcb85d1237ef54766c58

View File

@ -0,0 +1 @@
13acfb4cf4240e298d8e5f22e76125574848831e

View File

@ -0,0 +1 @@
f35cb94b893912b5312eb74c63d36b65426576e0

View File

@ -0,0 +1 @@
87d02bc510eac4b8b4a2453687c6b49f39aa481c

View File

@ -0,0 +1 @@
07716dffe2905abde0ae7bec475106e476bc9b25

View File

@ -0,0 +1 @@
2d32cd78d75549a5d0795bb9fbe35a00663f949a

View File

@ -27,6 +27,8 @@
'../../DEPS',
'../../data/audio_processing/output_data_float.pb',
'../../data/voice_engine/audio_tiny48.wav',
'../../resources/att-downlink.rx',
'../../resources/att-uplink.rx',
'../../resources/audio_coding/neteq4_network_stats.dat',
'../../resources/audio_coding/neteq4_rtcp_stats.dat',
'../../resources/audio_coding/neteq4_universal_ref.pcm',
@ -69,6 +71,15 @@
'../../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_SteadyLoss_0_TOF.bin',
'../../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_UnlimitedSpeed_0_AST.bin',
'../../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_UnlimitedSpeed_0_TOF.bin',
'../../resources/sprint-downlink.rx',
'../../resources/sprint-uplink.rx',
'../../resources/synthetic-trace.rx',
'../../resources/tmobile-downlink.rx',
'../../resources/tmobile-uplink.rx',
'../../resources/verizon3g-downlink.rx',
'../../resources/verizon3g-uplink.rx',
'../../resources/verizon4g-downlink.rx',
'../../resources/verizon4g-uplink.rx',
'../../resources/video_coding/frame-ethernet-ii.pcap',
'../../resources/video_coding/frame-loopback.pcap',
'../../resources/video_coding/pltype103.rtp',

View File

@ -10,6 +10,7 @@
#include "webrtc/modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h"
#include "webrtc/modules/remote_bitrate_estimator/test/bwe_test.h"
#include "webrtc/test/testsupport/fileutils.h"
namespace webrtc {
namespace testing {
@ -227,6 +228,18 @@ TEST_P(BweTest, Multi2) {
jitter.SetJitter(120);
RunFor(5 * 60 * 1000);
}
TEST_P(BweTest, SprintUplinkTest) {
TraceBasedDeliveryFilter filter(this);
ASSERT_TRUE(filter.Init(test::ResourcePath("sprint-uplink", "rx")));
RunFor(60 * 1000);
}
TEST_P(BweTest, Verizon4gDownlinkTest) {
TraceBasedDeliveryFilter filter(this);
ASSERT_TRUE(filter.Init(test::ResourcePath("verizon4g-downlink", "rx")));
RunFor(22 * 60 * 1000);
}
} // namespace bwe
} // namespace testing
} // namespace webrtc

View File

@ -10,6 +10,9 @@
#include "webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework.h"
#include <cstdio>
#include <sstream>
namespace webrtc {
namespace testing {
namespace bwe {
@ -280,6 +283,66 @@ void ChokeFilter::RunFor(int64_t /*time_ms*/, Packets* in_out) {
}
}
TraceBasedDeliveryFilter::TraceBasedDeliveryFilter(
PacketProcessorListener* listener)
: PacketProcessor(listener),
delivery_times_us_(),
next_delivery_it_(),
local_time_us_(-1) {}
bool TraceBasedDeliveryFilter::Init(const std::string& filename) {
FILE* trace_file = fopen(filename.c_str(), "r");
if (!trace_file) {
return false;
}
int64_t first_timestamp = -1;
while(!feof(trace_file)) {
const size_t kMaxLineLength = 100;
char line[kMaxLineLength];
if (fgets(line, kMaxLineLength, trace_file)) {
std::string line_string(line);
std::istringstream buffer(line_string);
int64_t timestamp;
buffer >> timestamp;
timestamp /= 1000; // Convert to microseconds.
if (first_timestamp == -1)
first_timestamp = timestamp;
assert(delivery_times_us_.empty() ||
timestamp - first_timestamp - delivery_times_us_.back() >= 0);
delivery_times_us_.push_back(timestamp - first_timestamp);
}
}
assert(!delivery_times_us_.empty());
next_delivery_it_ = delivery_times_us_.begin();
fclose(trace_file);
return true;
}
void TraceBasedDeliveryFilter::RunFor(int64_t time_ms, Packets* in_out) {
assert(in_out);
for (PacketsIt it = in_out->begin(); it != in_out->end(); ++it) {
do {
ProceedToNextSlot();
} while (local_time_us_ < it->send_time_us());
it->set_send_time_us(local_time_us_);
}
}
void TraceBasedDeliveryFilter::ProceedToNextSlot() {
if (*next_delivery_it_ <= local_time_us_) {
++next_delivery_it_;
if (next_delivery_it_ == delivery_times_us_.end()) {
// When the trace wraps we allow two packets to be sent back-to-back.
for (TimeList::iterator it = delivery_times_us_.begin();
it != delivery_times_us_.end(); ++it) {
*it += local_time_us_;
}
next_delivery_it_ = delivery_times_us_.begin();
}
}
local_time_us_ = *next_delivery_it_;
}
PacketSender::PacketSender(PacketProcessorListener* listener)
: PacketProcessor(listener) {
}

View File

@ -285,6 +285,28 @@ class ChokeFilter : public PacketProcessor {
DISALLOW_IMPLICIT_CONSTRUCTORS(ChokeFilter);
};
class TraceBasedDeliveryFilter : public PacketProcessor {
public:
explicit TraceBasedDeliveryFilter(PacketProcessorListener* listener);
virtual ~TraceBasedDeliveryFilter() {}
// The file should contain nanosecond timestamps corresponding to the time
// when the network can accept another packet. The timestamps should be
// separated by new lines, e.g., "100000000\n125000000\n321000000\n..."
bool Init(const std::string& filename);
virtual void RunFor(int64_t time_ms, Packets* in_out);
private:
void ProceedToNextSlot();
typedef std::vector<int64_t> TimeList;
TimeList delivery_times_us_;
TimeList::const_iterator next_delivery_it_;
int64_t local_time_us_;
DISALLOW_COPY_AND_ASSIGN(TraceBasedDeliveryFilter);
};
class PacketSender : public PacketProcessor {
public:
struct Feedback {

View File

@ -14,6 +14,7 @@
#include "gtest/gtest.h"
#include "webrtc/system_wrappers/interface/constructor_magic.h"
#include "webrtc/test/testsupport/fileutils.h"
using std::vector;
@ -567,8 +568,7 @@ TEST(BweTestFramework_ReorderFilterTest, Reorder100) {
class BweTestFramework_ChokeFilterTest : public ::testing::Test {
public:
BweTestFramework_ChokeFilterTest()
: filter_(NULL),
now_ms_(0),
: now_ms_(0),
sequence_number_(0),
output_packets_(),
send_times_us_() {
@ -576,9 +576,9 @@ class BweTestFramework_ChokeFilterTest : public ::testing::Test {
virtual ~BweTestFramework_ChokeFilterTest() {}
protected:
ChokeFilter filter_;
void TestChoke(int64_t run_for_ms, uint32_t packets_to_generate,
void TestChoke(PacketProcessor* filter,
int64_t run_for_ms,
uint32_t packets_to_generate,
uint32_t expected_kbit_transmitted) {
// Generate a bunch of packets, apply choke, verify output is ordered.
Packets packets;
@ -591,7 +591,7 @@ class BweTestFramework_ChokeFilterTest : public ::testing::Test {
send_times_us_.push_back(send_time_ms * 1000);
}
ASSERT_TRUE(IsTimeSorted(packets));
filter_.RunFor(run_for_ms, &packets);
filter->RunFor(run_for_ms, &packets);
now_ms_ += run_for_ms;
output_packets_.splice(output_packets_.end(), packets);
ASSERT_TRUE(IsTimeSorted(output_packets_));
@ -633,68 +633,88 @@ TEST_F(BweTestFramework_ChokeFilterTest, Short) {
// 100ms, 100 packets, 10 kbps choke -> 1 kbit of data should have propagated.
// That is actually just a single packet, since each packet has 1000 bits of
// payload.
filter_.SetCapacity(10);
TestChoke(100, 100, 1);
ChokeFilter filter(NULL);
filter.SetCapacity(10);
TestChoke(&filter, 100, 100, 1);
}
TEST_F(BweTestFramework_ChokeFilterTest, Medium) {
// 100ms, 10 packets, 10 kbps choke -> 1 packet through, or 1 kbit.
filter_.SetCapacity(10);
TestChoke(100, 10, 1);
ChokeFilter filter(NULL);
filter.SetCapacity(10);
TestChoke(&filter, 100, 10, 1);
// 200ms, no new packets -> another packet through.
TestChoke(100, 0, 1);
TestChoke(&filter, 100, 0, 1);
// 1000ms, no new packets -> 8 more packets.
TestChoke(800, 0, 8);
TestChoke(&filter, 800, 0, 8);
// 2000ms, no new packets -> queue is empty so no output.
TestChoke(1000, 0, 0);
TestChoke(&filter, 1000, 0, 0);
}
TEST_F(BweTestFramework_ChokeFilterTest, Long) {
// 100ms, 100 packets in queue, 10 kbps choke -> 1 packet through, or 1 kbit.
filter_.SetCapacity(10);
TestChoke(100, 100, 1);
ChokeFilter filter(NULL);
filter.SetCapacity(10);
TestChoke(&filter, 100, 100, 1);
// 200ms, no input, another packet through.
TestChoke(100, 0, 1);
TestChoke(&filter, 100, 0, 1);
// 1000ms, no input, 8 packets through.
TestChoke(800, 0, 8);
TestChoke(&filter, 800, 0, 8);
// 10000ms, no input, raise choke to 100 kbps. Remaining 90 packets in queue
// should be propagated, for a total of 90 kbps.
filter_.SetCapacity(100);
TestChoke(9000, 0, 90);
filter.SetCapacity(100);
TestChoke(&filter, 9000, 0, 90);
// 10100ms, 20 more packets -> 10 packets or 10 kbit through.
TestChoke(100, 20, 10);
TestChoke(&filter, 100, 20, 10);
// 10300ms, 10 more packets -> 20 packets out.
TestChoke(200, 10, 20);
TestChoke(&filter, 200, 10, 20);
// 11300ms, no input, queue should be empty.
filter_.SetCapacity(10);
TestChoke(1000, 0, 0);
filter.SetCapacity(10);
TestChoke(&filter, 1000, 0, 0);
}
TEST_F(BweTestFramework_ChokeFilterTest, MaxDelay) {
// 10 kbps choke, 500 ms delay cap
filter_.SetCapacity(10);
filter_.SetMaxDelay(500);
ChokeFilter filter(NULL);
filter.SetCapacity(10);
filter.SetMaxDelay(500);
// 100ms, 100 packets in queue, 10 kbps choke -> 1 packet through, or 1 kbit.
TestChoke(100, 100, 1);
TestChoke(&filter, 100, 100, 1);
CheckMaxDelay(500);
// 500ms, no input, 4 more packets through.
TestChoke(400, 0, 4);
TestChoke(&filter, 400, 0, 4);
// 10000ms, no input, remaining packets should have been dropped.
TestChoke(9500, 0, 0);
TestChoke(&filter, 9500, 0, 0);
// 100 ms delay cap
filter_.SetMaxDelay(100);
filter.SetMaxDelay(100);
// 10100ms, 50 more packets -> 2 packets or 2 kbit through.
TestChoke(100, 50, 2);
TestChoke(&filter, 100, 50, 2);
CheckMaxDelay(100);
// 20000ms, no input, remaining packets in queue should have been dropped.
TestChoke(9900, 0, 0);
TestChoke(&filter, 9900, 0, 0);
// Reset delay cap (0 is no cap) and verify no packets are dropped.
filter_.SetCapacity(10);
filter_.SetMaxDelay(0);
TestChoke(100, 100, 2);
TestChoke(9900, 0, 98);
filter.SetCapacity(10);
filter.SetMaxDelay(0);
TestChoke(&filter, 100, 100, 2);
TestChoke(&filter, 9900, 0, 98);
}
TEST_F(BweTestFramework_ChokeFilterTest, ShortTrace) {
// According to the input file 6 packets should be transmitted within
// 100 milliseconds.
TraceBasedDeliveryFilter filter(NULL);
ASSERT_TRUE(filter.Init(test::ResourcePath("synthetic-trace", "rx")));
TestChoke(&filter, 100, 100, 6);
}
TEST_F(BweTestFramework_ChokeFilterTest, ShortTraceWrap) {
// According to the input file 10 packets should be transmitted within
// 140 milliseconds (at the wrapping point two packets are sent back to back).
TraceBasedDeliveryFilter filter(NULL);
ASSERT_TRUE(filter.Init(test::ResourcePath("synthetic-trace", "rx")));
TestChoke(&filter, 140, 100, 10);
}
void TestVideoSender(VideoSender* sender, int64_t run_for_ms,