blob: b6a7123ccddfa42798ff1a68f555e4f6475464f8 [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 "webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework.h"
#include <numeric>
#include "gtest/gtest.h"
#include "webrtc/system_wrappers/interface/constructor_magic.h"
using std::vector;
namespace webrtc {
namespace testing {
namespace bwe {
TEST(BweTestFramework_RandomTest, Gaussian) {
enum {
kN = 100000,
kBuckets = 100,
kMean = 49,
kStddev = 10
};
Random random(0x12345678);
int buckets[kBuckets] = {0};
for (int i = 0; i < kN; ++i) {
int index = random.Gaussian(kMean, kStddev);
if (index >= 0 && index < kBuckets) {
buckets[index]++;
}
}
const double kPi = 3.14159265358979323846;
const double kScale = kN / (kStddev * std::sqrt(2.0 * kPi));
const double kDiv = -2.0 * kStddev * kStddev;
double self_corr = 0.0;
double bucket_corr = 0.0;
for (int n = 0; n < kBuckets; ++n) {
double normal_dist = kScale * std::exp((n - kMean) * (n - kMean) / kDiv);
self_corr += normal_dist * normal_dist;
bucket_corr += normal_dist * buckets[n];
}
printf("Correlation: %f (random sample), %f (self), %f (quotient)\n",
bucket_corr, self_corr, bucket_corr / self_corr);
EXPECT_NEAR(1.0, bucket_corr / self_corr, 0.0004);
}
static bool IsSequenceNumberSorted(const Packets& packets) {
PacketsConstIt last_it = packets.begin();
for (PacketsConstIt it = last_it; it != packets.end(); ++it) {
if (IsNewerSequenceNumber(last_it->header().sequenceNumber,
it->header().sequenceNumber)) {
return false;
}
last_it = it;
}
return true;
}
TEST(BweTestFramework_BwePacketTest, IsTimeSorted) {
Packets packets;
// Insert some packets in order...
EXPECT_TRUE(IsTimeSorted(packets));
packets.push_back(BwePacket(100, 0));
EXPECT_TRUE(IsTimeSorted(packets));
packets.push_back(BwePacket(110, 0));
EXPECT_TRUE(IsTimeSorted(packets));
// ...and one out-of-order...
packets.push_back(BwePacket(100, 0));
EXPECT_FALSE(IsTimeSorted(packets));
// ...remove the out-of-order packet, insert another in-order packet.
packets.pop_back();
packets.push_back(BwePacket(120, 0));
EXPECT_TRUE(IsTimeSorted(packets));
}
TEST(BweTestFramework_BwePacketTest, IsSequenceNumberSorted) {
Packets packets;
// Insert some packets in order...
EXPECT_TRUE(IsSequenceNumberSorted(packets));
packets.push_back(BwePacket(0, 100));
EXPECT_TRUE(IsSequenceNumberSorted(packets));
packets.push_back(BwePacket(0, 110));
EXPECT_TRUE(IsSequenceNumberSorted(packets));
// ...and one out-of-order...
packets.push_back(BwePacket(0, 100));
EXPECT_FALSE(IsSequenceNumberSorted(packets));
// ...remove the out-of-order packet, insert another in-order packet.
packets.pop_back();
packets.push_back(BwePacket(0, 120));
EXPECT_TRUE(IsSequenceNumberSorted(packets));
}
TEST(BweTestFramework_StatsTest, Mean) {
Stats<int32_t> stats;
EXPECT_EQ(0, stats.GetMean());
stats.Push(1);
stats.Push(3);
EXPECT_EQ(2, stats.GetMean());
// Integer division rounds (1+3-3)/3 to 0.
stats.Push(-3);
EXPECT_EQ(0, stats.GetMean());
}
TEST(BweTestFramework_StatsTest, Variance) {
Stats<int32_t> stats;
EXPECT_EQ(0, stats.GetVariance());
// Mean is 2 ; ((1-2)*(1-2)+(3-2)*(3-2))/2 = (1+1)/2 = 1
stats.Push(1);
stats.Push(3);
EXPECT_EQ(1, stats.GetVariance());
// Integer division rounds 26/3 to 8
// Mean is 0 ; (1*1+3*3+(-4)*(-4))/3 = (1+9+16)/3 = 8
stats.Push(-4);
EXPECT_EQ(8, stats.GetVariance());
}
TEST(BweTestFramework_StatsTest, StdDev) {
Stats<int32_t> stats;
EXPECT_EQ(0, stats.GetStdDev());
// Variance is 1 ; sqrt(1) = 1
stats.Push(1);
stats.Push(3);
EXPECT_EQ(1, stats.GetStdDev());
// Variance is 8 ; sqrt(8) = 2 with integers.
stats.Push(-4);
EXPECT_EQ(2, stats.GetStdDev());
}
TEST(BweTestFramework_StatsTest, MinMax) {
Stats<int32_t> stats;
EXPECT_EQ(0, stats.GetMin());
EXPECT_EQ(0, stats.GetMax());
stats.Push(1);
EXPECT_EQ(1, stats.GetMin());
EXPECT_EQ(1, stats.GetMax());
stats.Push(3);
EXPECT_EQ(1, stats.GetMin());
EXPECT_EQ(3, stats.GetMax());
stats.Push(-4);
EXPECT_EQ(-4, stats.GetMin());
EXPECT_EQ(3, stats.GetMax());
}
void TestVideoSender(VideoSender* sender, int64_t run_for_ms,
uint32_t expected_packets,
uint32_t expected_payload_size,
uint32_t expected_total_payload_size) {
assert(sender);
Packets packets;
sender->RunFor(run_for_ms, &packets);
ASSERT_TRUE(IsTimeSorted(packets));
ASSERT_TRUE(IsSequenceNumberSorted(packets));
EXPECT_EQ(expected_packets, packets.size());
int64_t send_time_us = -1;
uint32_t total_payload_size = 0;
uint32_t absolute_send_time = 0;
uint32_t absolute_send_time_wraps = 0;
uint32_t rtp_timestamp = 0;
uint32_t rtp_timestamp_wraps = 0;
for (PacketsIt it = packets.begin(); it != packets.end(); ++it) {
EXPECT_LE(send_time_us, it->send_time_us());
send_time_us = it->send_time_us();
if (sender->max_payload_size_bytes() != it->payload_size()) {
EXPECT_EQ(expected_payload_size, it->payload_size());
}
total_payload_size += it->payload_size();
if (absolute_send_time > it->header().extension.absoluteSendTime) {
absolute_send_time_wraps++;
}
absolute_send_time = it->header().extension.absoluteSendTime;
if (rtp_timestamp > it->header().timestamp) {
rtp_timestamp_wraps++;
}
rtp_timestamp = it->header().timestamp;
}
EXPECT_EQ(expected_total_payload_size, total_payload_size);
EXPECT_GE(1u, absolute_send_time_wraps);
EXPECT_GE(1u, rtp_timestamp_wraps);
}
TEST(BweTestFramework_VideoSenderTest, Fps1Kpbs80_1s) {
// 1 fps, 80 kbps
VideoSender sender(1.0f, 80, 0x1234, 0);
EXPECT_EQ(10000u, sender.bytes_per_second());
// We're at 1 fps, so all packets should be generated on first call, giving 10
// packets of each 1000 bytes, total 10000 bytes.
TestVideoSender(&sender, 1, 10, 1000, 10000);
// 999ms, should see no output here.
TestVideoSender(&sender, 998, 0, 0, 0);
// 1999ms, should get data for one more frame.
TestVideoSender(&sender, 1000, 10, 1000, 10000);
// 2000ms, one more frame.
TestVideoSender(&sender, 1, 10, 1000, 10000);
// 2999ms, should see nothing.
TestVideoSender(&sender, 999, 0, 0, 0);
}
TEST(BweTestFramework_VideoSenderTest, Fps1Kpbs80_1s_Offset) {
// 1 fps, 80 kbps, offset 0.5 of a frame period, ==0.5s in this case.
VideoSender sender(1.0f, 80, 0x1234, 0.5f);
EXPECT_EQ(10000u, sender.bytes_per_second());
// 499ms, no output.
TestVideoSender(&sender, 499, 0, 0, 0);
// 500ms, first frame (this is the offset we set), 10 packets of 1000 bytes.
TestVideoSender(&sender, 1, 10, 1000, 10000);
// 1499ms, nothing.
TestVideoSender(&sender, 999, 0, 0, 0);
// 1999ms, second frame.
TestVideoSender(&sender, 500, 10, 1000, 10000);
// 2499ms, nothing.
TestVideoSender(&sender, 500, 0, 0, 0);
// 2500ms, third frame.
TestVideoSender(&sender, 1, 10, 1000, 10000);
// 3499ms, nothing.
TestVideoSender(&sender, 999, 0, 0, 0);
}
TEST(BweTestFramework_VideoSenderTest, Fps50Kpbs80_11s) {
// 50 fps, 80 kbps.
VideoSender sender(50.0f, 80, 0x1234, 0);
EXPECT_EQ(10000u, sender.bytes_per_second());
// 9998ms, should see 500 frames, 200 byte payloads, total 100000 bytes.
TestVideoSender(&sender, 9998, 500, 200, 100000);
// 9999ms, nothing.
TestVideoSender(&sender, 1, 0, 0, 0);
// 10000ms, 501st frame as a single packet.
TestVideoSender(&sender, 1, 1, 200, 200);
// 10998ms, 49 more frames.
TestVideoSender(&sender, 998, 49, 200, 9800);
// 10999ms, nothing.
TestVideoSender(&sender, 1, 0, 0, 0);
}
TEST(BweTestFramework_VideoSenderTest, Fps10Kpbs120_1s) {
// 20 fps, 120 kbps.
VideoSender sender(20.0f, 120, 0x1234, 0);
EXPECT_EQ(15000u, sender.bytes_per_second());
// 498ms, 10 frames with 750 byte payloads, total 7500 bytes.
TestVideoSender(&sender, 498, 10, 750, 7500);
// 499ms, nothing.
TestVideoSender(&sender, 1, 0, 0, 0);
// 500ms, one more frame.
TestVideoSender(&sender, 1, 1, 750, 750);
// 998ms, 9 more frames.
TestVideoSender(&sender, 498, 9, 750, 6750);
// 999ms, nothing.
TestVideoSender(&sender, 1, 0, 0, 0);
}
TEST(BweTestFramework_VideoSenderTest, Fps30Kpbs800_20s) {
// 20 fps, 820 kbps.
VideoSender sender(25.0f, 820, 0x1234, 0);
EXPECT_EQ(102500u, sender.bytes_per_second());
// 9998ms, 250 frames. 820 kbps = 102500 bytes/s, so total should be 1025000.
// Each frame is 102500/25=4100 bytes, or 5 packets (4 @1000 bytes, 1 @100),
// so packet count should be 5*250=1250 and last packet of each frame has
// 100 bytes of payload.
TestVideoSender(&sender, 9998, 1250, 100, 1025000);
// 9999ms, nothing.
TestVideoSender(&sender, 1, 0, 0, 0);
// 19998ms, 250 more frames.
TestVideoSender(&sender, 9999, 1250, 100, 1025000);
// 19999ms, nothing.
TestVideoSender(&sender, 1, 0, 0, 0);
// 20038ms, one more frame, as described above (25fps == 40ms/frame).
TestVideoSender(&sender, 39, 5, 100, 4100);
// 20039ms, nothing.
TestVideoSender(&sender, 1, 0, 0, 0);
}
TEST(BweTestFramework_VideoSenderTest, TestAppendInOrder) {
// 1 fps, 80 kbps, 250ms offset.
VideoSender sender1(1.0f, 80, 0x1234, 0.25f);
EXPECT_EQ(10000u, sender1.bytes_per_second());
Packets packets;
// Generate some packets, verify they are sorted.
sender1.RunFor(999, &packets);
ASSERT_TRUE(IsTimeSorted(packets));
ASSERT_TRUE(IsSequenceNumberSorted(packets));
EXPECT_EQ(10u, packets.size());
// Generate some more packets and verify they are appended to end of list.
sender1.RunFor(1000, &packets);
ASSERT_TRUE(IsTimeSorted(packets));
ASSERT_TRUE(IsSequenceNumberSorted(packets));
EXPECT_EQ(20u, packets.size());
// Another sender, 2 fps, 160 kpbs, 150ms offset
VideoSender sender2(2.0f, 160, 0x2234, 0.30f);
EXPECT_EQ(20000u, sender2.bytes_per_second());
// Generate some packets, verify that they are merged with the packets already
// on the list.
sender2.RunFor(999, &packets);
ASSERT_TRUE(IsTimeSorted(packets));
EXPECT_EQ(40u, packets.size());
// Generate some more.
sender2.RunFor(1000, &packets);
ASSERT_TRUE(IsTimeSorted(packets));
EXPECT_EQ(60u, packets.size());
}
class BweTestFramework_RateCounterFilterTest : public ::testing::Test {
public:
BweTestFramework_RateCounterFilterTest()
: filter_(),
now_ms_(0) {
}
virtual ~BweTestFramework_RateCounterFilterTest() {}
protected:
void TestRateCounter(int64_t run_for_ms, uint32_t payload_bits,
uint32_t expected_pps, uint32_t expected_bps) {
Packets packets;
RTPHeader header = {0};
// "Send" a packet every 10 ms.
for (int64_t i = 0; i < run_for_ms; i += 10, now_ms_ += 10) {
packets.push_back(BwePacket(now_ms_ * 1000, payload_bits / 8, header));
}
filter_.RunFor(run_for_ms, &packets);
ASSERT_TRUE(IsTimeSorted(packets));
EXPECT_EQ(expected_pps, filter_.packets_per_second());
EXPECT_EQ(expected_bps, filter_.bits_per_second());
}
private:
RateCounterFilter filter_;
int64_t now_ms_;
DISALLOW_COPY_AND_ASSIGN(BweTestFramework_RateCounterFilterTest);
};
TEST_F(BweTestFramework_RateCounterFilterTest, Short) {
// 100ms, 100 bytes per packet, should result in 10 pps and 8 kbps. We're
// generating one packet every 10 ms ; 10 * 800 = 8k
TestRateCounter(100, 800, 10, 8000);
}
TEST_F(BweTestFramework_RateCounterFilterTest, Medium) {
// 100ms, like above.
TestRateCounter(100, 800, 10, 8000);
// 1000ms, 100 bpp, should result in 100 pps and 80 kbps. We're still
// generating packets every 10 ms.
TestRateCounter(900, 800, 100, 80000);
}
TEST_F(BweTestFramework_RateCounterFilterTest, Long) {
// 100ms, 1000ms, like above.
TestRateCounter(100, 800, 10, 8000);
TestRateCounter(900, 800, 100, 80000);
// 2000ms, should only see rate of last second, so 100 pps, and 40 kbps now.
TestRateCounter(1000, 400, 100, 40000);
// 2500ms, half a second with zero payload size. We should get same pps as
// before, but kbps should drop to half of previous rate.
TestRateCounter(500, 0, 100, 20000);
// Another half second with zero payload size. Now the kbps rate should drop
// to zero.
TestRateCounter(500, 0, 100, 0);
// Increate payload size again. 200 * 100 * 0.5 = 10 kbps.
TestRateCounter(500, 200, 100, 10000);
}
static void TestLossFilter(float loss_percent, bool zero_tolerance) {
LossFilter filter;
filter.SetLoss(loss_percent);
Packets::size_type sent_packets = 0;
Packets::size_type remaining_packets = 0;
// No input should yield no output
{
Packets packets;
sent_packets += packets.size();
filter.RunFor(0, &packets);
ASSERT_TRUE(IsTimeSorted(packets));
ASSERT_TRUE(IsSequenceNumberSorted(packets));
remaining_packets += packets.size();
EXPECT_EQ(0u, sent_packets);
EXPECT_EQ(0u, remaining_packets);
}
// Generate and process 10000 packets in different batch sizes (some empty)
for (int i = 0; i < 2225; ++i) {
Packets packets;
packets.insert(packets.end(), i % 10, BwePacket());
sent_packets += packets.size();
filter.RunFor(0, &packets);
ASSERT_TRUE(IsTimeSorted(packets));
ASSERT_TRUE(IsSequenceNumberSorted(packets));
remaining_packets += packets.size();
}
float loss_fraction = 0.01f * (100.0f - loss_percent);
Packets::size_type expected_packets = loss_fraction * sent_packets;
if (zero_tolerance) {
EXPECT_EQ(expected_packets, remaining_packets);
} else {
// Require within 1% of expected
EXPECT_NEAR(expected_packets, remaining_packets, 100);
}
}
TEST(BweTestFramework_LossFilterTest, Loss0) {
// With 0% loss, the result should be exact (no loss).
TestLossFilter(0.0f, true);
}
TEST(BweTestFramework_LossFilterTest, Loss10) {
TestLossFilter(10.0f, false);
}
TEST(BweTestFramework_LossFilterTest, Loss50) {
TestLossFilter(50.0f, false);
}
TEST(BweTestFramework_LossFilterTest, Loss100) {
// With 100% loss, the result should be exact (no packets out).
TestLossFilter(100.0f, true);
}
class BweTestFramework_DelayFilterTest : public ::testing::Test {
public:
BweTestFramework_DelayFilterTest()
: filter_(),
now_ms_(0),
sequence_number_(0) {
}
virtual ~BweTestFramework_DelayFilterTest() {}
protected:
void TestDelayFilter(int64_t run_for_ms, uint32_t in_packets,
uint32_t out_packets) {
Packets packets;
for (uint32_t i = 0; i < in_packets; ++i) {
packets.push_back(BwePacket(now_ms_ * 1000 + (sequence_number_ >> 4),
sequence_number_));
sequence_number_++;
}
filter_.RunFor(run_for_ms, &packets);
ASSERT_TRUE(IsTimeSorted(packets));
ASSERT_TRUE(IsSequenceNumberSorted(packets));
for (PacketsConstIt it = packets.begin(); it != packets.end(); ++it) {
EXPECT_LE(now_ms_ * 1000, it->send_time_us());
}
EXPECT_EQ(out_packets, packets.size());
accumulated_packets_.splice(accumulated_packets_.end(), packets);
now_ms_ += run_for_ms;
}
void TestDelayFilter(int64_t delay_ms) {
filter_.SetDelay(delay_ms);
TestDelayFilter(1, 0, 0); // No input should yield no output
// Single packet
TestDelayFilter(0, 1, 1);
TestDelayFilter(delay_ms, 0, 0);
for (int i = 0; i < delay_ms; ++i) {
filter_.SetDelay(i);
TestDelayFilter(1, 10, 10);
}
TestDelayFilter(0, 0, 0);
TestDelayFilter(delay_ms, 0, 0);
// Wait a little longer - should still see no output
TestDelayFilter(delay_ms, 0, 0);
for (int i = 1; i < delay_ms + 1; ++i) {
filter_.SetDelay(i);
TestDelayFilter(1, 5, 5);
}
TestDelayFilter(0, 0, 0);
filter_.SetDelay(2 * delay_ms);
TestDelayFilter(1, 0, 0);
TestDelayFilter(delay_ms, 13, 13);
TestDelayFilter(delay_ms, 0, 0);
// Wait a little longer - should still see no output
TestDelayFilter(delay_ms, 0, 0);
for (int i = 0; i < 2 * delay_ms; ++i) {
filter_.SetDelay(2 * delay_ms - i - 1);
TestDelayFilter(1, 5, 5);
}
TestDelayFilter(0, 0, 0);
filter_.SetDelay(0);
TestDelayFilter(0, 7, 7);
ASSERT_TRUE(IsTimeSorted(accumulated_packets_));
ASSERT_TRUE(IsSequenceNumberSorted(accumulated_packets_));
}
DelayFilter filter_;
Packets accumulated_packets_;
private:
int64_t now_ms_;
uint32_t sequence_number_;
DISALLOW_COPY_AND_ASSIGN(BweTestFramework_DelayFilterTest);
};
TEST_F(BweTestFramework_DelayFilterTest, Delay0) {
TestDelayFilter(1, 0, 0); // No input should yield no output
TestDelayFilter(1, 10, 10); // Expect no delay (delay time is zero)
TestDelayFilter(1, 0, 0); // Check no packets are still in buffer
filter_.SetDelay(0);
TestDelayFilter(1, 5, 5); // Expect no delay (delay time is zero)
TestDelayFilter(1, 0, 0); // Check no packets are still in buffer
}
TEST_F(BweTestFramework_DelayFilterTest, Delay1) {
TestDelayFilter(1);
}
TEST_F(BweTestFramework_DelayFilterTest, Delay2) {
TestDelayFilter(2);
}
TEST_F(BweTestFramework_DelayFilterTest, Delay20) {
TestDelayFilter(20);
}
TEST_F(BweTestFramework_DelayFilterTest, Delay100) {
TestDelayFilter(100);
}
TEST_F(BweTestFramework_DelayFilterTest, JumpToZeroDelay) {
DelayFilter delay;
Packets acc;
Packets packets;
// Delay a bunch of packets, accumulate them to the 'acc' list.
delay.SetDelay(100.0f);
for (uint32_t i = 0; i < 10; ++i) {
packets.push_back(BwePacket(i * 100, i));
}
delay.RunFor(1000, &packets);
acc.splice(acc.end(), packets);
ASSERT_TRUE(IsTimeSorted(acc));
ASSERT_TRUE(IsSequenceNumberSorted(acc));
// Drop delay to zero, send a few more packets through the delay, append them
// to the 'acc' list and verify that it is all sorted.
delay.SetDelay(0.0f);
for (uint32_t i = 10; i < 50; ++i) {
packets.push_back(BwePacket(i * 100, i));
}
delay.RunFor(1000, &packets);
acc.splice(acc.end(), packets);
ASSERT_TRUE(IsTimeSorted(acc));
ASSERT_TRUE(IsSequenceNumberSorted(acc));
}
TEST_F(BweTestFramework_DelayFilterTest, IncreasingDelay) {
// Gradually increase delay.
for (int i = 1; i < 50; i += 4) {
TestDelayFilter(i);
}
// Reach a steady state.
filter_.SetDelay(100);
TestDelayFilter(1, 20, 20);
TestDelayFilter(2, 0, 0);
TestDelayFilter(99, 20, 20);
// Drop delay back down to zero.
filter_.SetDelay(0);
TestDelayFilter(1, 100, 100);
TestDelayFilter(23010, 0, 0);
ASSERT_TRUE(IsTimeSorted(accumulated_packets_));
ASSERT_TRUE(IsSequenceNumberSorted(accumulated_packets_));
}
static void TestJitterFilter(int64_t stddev_jitter_ms) {
JitterFilter filter;
filter.SetJitter(stddev_jitter_ms);
int64_t now_ms = 0;
uint32_t sequence_number = 0;
// Generate packets, add jitter to them, accumulate the altered packets.
Packets original;
Packets jittered;
for (uint32_t i = 0; i < 1000; ++i) {
Packets packets;
for (uint32_t j = 0; j < i % 100; ++j) {
packets.push_back(BwePacket(now_ms * 1000, sequence_number++));
now_ms += 5 * stddev_jitter_ms;
}
original.insert(original.end(), packets.begin(), packets.end());
filter.RunFor(stddev_jitter_ms, &packets);
jittered.splice(jittered.end(), packets);
}
// Jittered packets should still be in order.
ASSERT_TRUE(IsTimeSorted(original));
ASSERT_TRUE(IsTimeSorted(jittered));
ASSERT_TRUE(IsSequenceNumberSorted(original));
ASSERT_TRUE(IsSequenceNumberSorted(jittered));
EXPECT_EQ(original.size(), jittered.size());
// Make sure jittered and original packets are in same order. Collect time
// difference (jitter) in stats, then check that mean jitter is close to zero
// and standard deviation of jitter is what we set it to.
Stats<double> jitter_us;
for (PacketsIt it1 = original.begin(), it2 = jittered.begin();
it1 != original.end() && it2 != jittered.end(); ++it1, ++it2) {
EXPECT_EQ(it1->header().sequenceNumber, it2->header().sequenceNumber);
jitter_us.Push(it2->send_time_us() - it1->send_time_us());
}
EXPECT_NEAR(0.0, jitter_us.GetMean(), stddev_jitter_ms * 1000.0 * 0.008);
EXPECT_NEAR(stddev_jitter_ms * 1000.0, jitter_us.GetStdDev(),
stddev_jitter_ms * 1000.0 * 0.02);
}
TEST(BweTestFramework_JitterFilterTest, Jitter0) {
TestJitterFilter(0);
}
TEST(BweTestFramework_JitterFilterTest, Jitter1) {
TestJitterFilter(1);
}
TEST(BweTestFramework_JitterFilterTest, Jitter5) {
TestJitterFilter(5);
}
TEST(BweTestFramework_JitterFilterTest, Jitter10) {
TestJitterFilter(10);
}
TEST(BweTestFramework_JitterFilterTest, Jitter1031) {
TestJitterFilter(1031);
}
static void TestReorderFilter(uint32_t reorder_percent, uint32_t near) {
const uint32_t kPacketCount = 10000;
// Generate packets with 10 ms interval.
Packets packets;
int64_t now_ms = 0;
uint32_t sequence_number = 1;
for (uint32_t i = 0; i < kPacketCount; ++i, now_ms += 10) {
packets.push_back(BwePacket(now_ms * 1000, sequence_number++));
}
ASSERT_TRUE(IsTimeSorted(packets));
ASSERT_TRUE(IsSequenceNumberSorted(packets));
// Reorder packets, verify that send times are still in order.
ReorderFilter filter;
filter.SetReorder(reorder_percent);
filter.RunFor(now_ms, &packets);
ASSERT_TRUE(IsTimeSorted(packets));
// We measure the amount of reordering by summing the distance by which out-
// of-order packets have been moved in the stream.
uint32_t distance = 0;
uint32_t last_sequence_number = 0;
for (PacketsIt it = packets.begin(); it != packets.end(); ++it) {
uint32_t sequence_number = it->header().sequenceNumber;
if (sequence_number < last_sequence_number) {
distance += last_sequence_number - sequence_number;
}
last_sequence_number = sequence_number;
}
// Because reordering is random, we allow a threshold when comparing. The
// maximum distance a packet can be moved is PacketCount - 1.
EXPECT_NEAR(((kPacketCount - 1) * reorder_percent) / 100, distance, near);
}
TEST(BweTestFramework_ReorderFilterTest, Reorder0) {
// For 0% reordering, no packets should have been moved, so result is exact.
TestReorderFilter(0, 0);
}
TEST(BweTestFramework_ReorderFilterTest, Reorder10) {
TestReorderFilter(10, 30);
}
TEST(BweTestFramework_ReorderFilterTest, Reorder20) {
TestReorderFilter(20, 20);
}
TEST(BweTestFramework_ReorderFilterTest, Reorder50) {
TestReorderFilter(50, 20);
}
TEST(BweTestFramework_ReorderFilterTest, Reorder70) {
TestReorderFilter(70, 20);
}
TEST(BweTestFramework_ReorderFilterTest, Reorder100) {
// Note that because the implementation works by optionally swapping two
// adjacent packets, when the likelihood of a swap is 1.0, a swap will always
// occur, so the stream will be in order except for the first packet, which
// has been moved to the end. Therefore we expect the result to be exact here.
TestReorderFilter(100.0, 0);
}
class BweTestFramework_ChokeFilterTest : public ::testing::Test {
public:
BweTestFramework_ChokeFilterTest()
: filter_(),
now_ms_(0),
sequence_number_(0),
output_packets_(),
send_times_us_() {
}
virtual ~BweTestFramework_ChokeFilterTest() {}
protected:
ChokeFilter filter_;
void TestChoke(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;
RTPHeader header = {0};
for (uint32_t i = 0; i < packets_to_generate; ++i) {
int64_t send_time_ms = now_ms_ + (i * run_for_ms) / packets_to_generate;
header.sequenceNumber = sequence_number_++;
// Payload is 1000 bits.
packets.push_back(BwePacket(send_time_ms * 1000, 125, header));
send_times_us_.push_back(send_time_ms * 1000);
}
ASSERT_TRUE(IsTimeSorted(packets));
filter_.RunFor(run_for_ms, &packets);
now_ms_ += run_for_ms;
output_packets_.splice(output_packets_.end(), packets);
ASSERT_TRUE(IsTimeSorted(output_packets_));
ASSERT_TRUE(IsSequenceNumberSorted(output_packets_));
// Sum up the transmitted bytes up until the current time.
uint32_t bytes_transmitted = 0;
while (!output_packets_.empty()) {
const BwePacket& packet = output_packets_.front();
if (packet.send_time_us() > now_ms_ * 1000) {
break;
}
bytes_transmitted += packet.payload_size();
output_packets_.pop_front();
}
EXPECT_EQ(expected_kbit_transmitted, (bytes_transmitted * 8) / 1000);
}
void CheckMaxDelay(int64_t max_delay_ms) {
for (PacketsIt it = output_packets_.begin(); it != output_packets_.end();
++it) {
const BwePacket& packet = *it;
int64_t delay_us = packet.send_time_us() -
send_times_us_[packet.header().sequenceNumber];
EXPECT_GE(max_delay_ms * 1000, delay_us);
}
}
private:
int64_t now_ms_;
uint32_t sequence_number_;
Packets output_packets_;
std::vector<int64_t> send_times_us_;
DISALLOW_COPY_AND_ASSIGN(BweTestFramework_ChokeFilterTest);
};
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);
}
TEST_F(BweTestFramework_ChokeFilterTest, Medium) {
// 100ms, 10 packets, 10 kbps choke -> 1 packet through, or 1 kbit.
filter_.SetCapacity(10);
TestChoke(100, 10, 1);
// 200ms, no new packets -> another packet through.
TestChoke(100, 0, 1);
// 1000ms, no new packets -> 8 more packets.
TestChoke(800, 0, 8);
// 2000ms, no new packets -> queue is empty so no output.
TestChoke(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);
// 200ms, no input, another packet through.
TestChoke(100, 0, 1);
// 1000ms, no input, 8 packets through.
TestChoke(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);
// 10100ms, 20 more packets -> 10 packets or 10 kbit through.
TestChoke(100, 20, 10);
// 10300ms, 10 more packets -> 20 packets out.
TestChoke(200, 10, 20);
// 11300ms, no input, queue should be empty.
filter_.SetCapacity(10);
TestChoke(1000, 0, 0);
}
TEST_F(BweTestFramework_ChokeFilterTest, MaxDelay) {
// 10 kbps choke, 500 ms delay cap
filter_.SetCapacity(10);
filter_.SetMaxDelay(500);
// 100ms, 100 packets in queue, 10 kbps choke -> 1 packet through, or 1 kbit.
TestChoke(100, 100, 1);
CheckMaxDelay(500);
// 500ms, no input, 4 more packets through.
TestChoke(400, 0, 4);
// 10000ms, no input, remaining packets should have been dropped.
TestChoke(9500, 0, 0);
// 100 ms delay cap
filter_.SetMaxDelay(100);
// 10100ms, 50 more packets -> 2 packets or 2 kbit through.
TestChoke(100, 50, 2);
CheckMaxDelay(100);
// 20000ms, no input, remaining packets in queue should have been dropped.
TestChoke(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);
}
} // namespace bwe
} // namespace testing
} // namespace webrtc