From bf40b42af585128a5b22299bdfaff706659774bd Mon Sep 17 00:00:00 2001 From: Cesar Magalhaes Date: Wed, 15 Jul 2015 19:47:10 +0200 Subject: [PATCH] Modified Simulation Framework Jitter Model. Using a right-sided (absolute value), truncated gaussian distribution originally with zero mean. Currently truncated at x = 3 * std_dev. Added expected value computation. Modified jitter unittests accordingly. BUG=webrtc:4848 R=stefan@webrtc.org Review URL: https://codereview.webrtc.org/1237303002 . Cr-Commit-Position: refs/heads/master@{#9587} --- .../remote_bitrate_estimators_test.cc | 10 ++-- .../test/bwe_test_framework.cc | 58 +++++++++++++++---- .../test/bwe_test_framework.h | 5 +- .../test/bwe_test_framework_unittest.cc | 23 +++++--- .../remote_bitrate_estimator/test/packet.h | 1 + 5 files changed, 71 insertions(+), 26 deletions(-) diff --git a/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimators_test.cc b/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimators_test.cc index 5c147d683b..044e43424b 100644 --- a/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimators_test.cc +++ b/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimators_test.cc @@ -124,7 +124,7 @@ TEST_P(DefaultBweTest, SteadyJitter) { JitterFilter jitter(&uplink_, 0); RateCounterFilter counter(&uplink_, 0, ""); PacketReceiver receiver(&uplink_, 0, GetParam(), false, false); - jitter.SetJitter(20); + jitter.SetMaxJitter(20); RunFor(2 * 60 * 1000); } @@ -134,7 +134,7 @@ TEST_P(DefaultBweTest, IncreasingJitter1) { JitterFilter jitter(&uplink_, 0); PacketReceiver receiver(&uplink_, 0, GetParam(), false, false); for (int i = 0; i < 2 * 60 * 2; ++i) { - jitter.SetJitter(i); + jitter.SetMaxJitter(i); RunFor(10 * 1000); } RunFor(10 * 60 * 1000); @@ -147,10 +147,10 @@ TEST_P(DefaultBweTest, IncreasingJitter2) { PacketReceiver receiver(&uplink_, 0, GetParam(), false, false); RunFor(30 * 1000); for (int i = 1; i < 51; ++i) { - jitter.SetJitter(10.0f * i); + jitter.SetMaxJitter(10.0f * i); RunFor(10 * 1000); } - jitter.SetJitter(0.0f); + jitter.SetMaxJitter(0.0f); RunFor(10 * 60 * 1000); } @@ -232,7 +232,7 @@ TEST_P(DefaultBweTest, Multi2) { RateCounterFilter counter(&uplink_, 0, ""); PacketReceiver receiver(&uplink_, 0, GetParam(), false, false); choke.set_capacity_kbps(2000); - jitter.SetJitter(120); + jitter.SetMaxJitter(120); RunFor(5 * 60 * 1000); } diff --git a/webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework.cc b/webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework.cc index 2d256d49fc..90e4094cb3 100644 --- a/webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework.cc +++ b/webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework.cc @@ -389,7 +389,8 @@ JitterFilter::JitterFilter(PacketProcessorListener* listener, int flow_id) : PacketProcessor(listener, flow_id, kRegular), random_(0x89674523), stddev_jitter_us_(0), - last_send_time_us_(0) { + last_send_time_us_(0), + reordering_(false) { } JitterFilter::JitterFilter(PacketProcessorListener* listener, @@ -397,27 +398,62 @@ JitterFilter::JitterFilter(PacketProcessorListener* listener, : PacketProcessor(listener, flow_ids, kRegular), random_(0x89674523), stddev_jitter_us_(0), - last_send_time_us_(0) { + last_send_time_us_(0), + reordering_(false) { } -void JitterFilter::SetJitter(int64_t stddev_jitter_ms) { +const int kN = 3; // Truncated N sigma gaussian. + +void JitterFilter::SetMaxJitter(int64_t max_jitter_ms) { BWE_TEST_LOGGING_ENABLE(false); - BWE_TEST_LOGGING_LOG1("Jitter", "%d ms", - static_cast(stddev_jitter_ms)); - assert(stddev_jitter_ms >= 0); - stddev_jitter_us_ = stddev_jitter_ms * 1000; + BWE_TEST_LOGGING_LOG1("Max Jitter", "%d ms", static_cast(max_jitter_ms)); + assert(max_jitter_ms >= 0); + // Truncated gaussian, Max jitter = kN*sigma. + stddev_jitter_us_ = (max_jitter_ms * 1000 + kN / 2) / kN; +} + +namespace { +inline int64_t TruncatedNSigmaGaussian(Random* const random, + int64_t mean, + int64_t std_dev) { + int64_t gaussian_random = random->Gaussian(mean, std_dev); + return std::max(std::min(gaussian_random, kN * std_dev), -kN * std_dev); +} } void JitterFilter::RunFor(int64_t /*time_ms*/, Packets* in_out) { assert(in_out); for (Packet* packet : *in_out) { - int64_t new_send_time_us = packet->send_time_us(); - new_send_time_us += random_.Gaussian(0, stddev_jitter_us_); - last_send_time_us_ = std::max(last_send_time_us_, new_send_time_us); - packet->set_send_time_us(last_send_time_us_); + int64_t jitter_us = + std::abs(TruncatedNSigmaGaussian(&random_, 0, stddev_jitter_us_)); + int64_t new_send_time_us = packet->send_time_us() + jitter_us; + + if (!reordering_) { + new_send_time_us = std::max(last_send_time_us_, new_send_time_us); + } + + // Receiver timestamp cannot be lower than sender timestamp. + assert(new_send_time_us >= packet->sender_timestamp_us()); + + packet->set_send_time_us(new_send_time_us); + last_send_time_us_ = new_send_time_us; } } +// Computes the expected value for a right sided (abs) truncated gaussian. +// Does not take into account possible reoerdering updates. +int64_t JitterFilter::MeanUs() { + const double kPi = 3.1415926535897932; + double max_jitter_us = static_cast(kN * stddev_jitter_us_); + double right_sided_mean_us = + static_cast(stddev_jitter_us_) / sqrt(kPi / 2.0); + double truncated_mean_us = + right_sided_mean_us * + (1.0 - exp(-pow(static_cast(kN), 2.0) / 2.0)) + + max_jitter_us * erfc(static_cast(kN)); + return static_cast(truncated_mean_us + 0.5); +} + ReorderFilter::ReorderFilter(PacketProcessorListener* listener, int flow_id) : PacketProcessor(listener, flow_id, kRegular), random_(0x27452389), diff --git a/webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework.h b/webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework.h index b742f7ffd1..d62e6d0e24 100644 --- a/webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework.h +++ b/webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework.h @@ -314,13 +314,16 @@ class JitterFilter : public PacketProcessor { JitterFilter(PacketProcessorListener* listener, const FlowIds& flow_ids); virtual ~JitterFilter() {} - void SetJitter(int64_t stddev_jitter_ms); + void SetMaxJitter(int64_t stddev_jitter_ms); virtual void RunFor(int64_t time_ms, Packets* in_out); + void set_reorderdering(bool reordering) { reordering_ = reordering; } + int64_t MeanUs(); private: Random random_; int64_t stddev_jitter_us_; int64_t last_send_time_us_; + bool reordering_; // False by default. DISALLOW_IMPLICIT_CONSTRUCTORS(JitterFilter); }; diff --git a/webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework_unittest.cc b/webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework_unittest.cc index 875c8f798f..e46e170447 100644 --- a/webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework_unittest.cc +++ b/webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework_unittest.cc @@ -457,12 +457,12 @@ TEST_F(BweTestFramework_DelayFilterTest, IncreasingDelay) { ASSERT_TRUE(IsSequenceNumberSorted(accumulated_packets_)); } -static void TestJitterFilter(int64_t stddev_jitter_ms) { +static void TestJitterFilter(int64_t max_jitter_ms) { JitterFilter filter(NULL, 0); - filter.SetJitter(stddev_jitter_ms); + filter.SetMaxJitter(max_jitter_ms); int64_t now_ms = 0; - uint32_t sequence_number = 0; + uint16_t sequence_number = 0; // Generate packets, add jitter to them, accumulate the altered packets. Packets original; @@ -473,9 +473,9 @@ static void TestJitterFilter(int64_t stddev_jitter_ms) { packets.push_back(new MediaPacket(now_ms * 1000, sequence_number)); original.push_back(new MediaPacket(now_ms * 1000, sequence_number)); ++sequence_number; - now_ms += 5 * stddev_jitter_ms; + now_ms += 5 * max_jitter_ms; } - filter.RunFor(stddev_jitter_ms, &packets); + filter.RunFor(max_jitter_ms, &packets); jittered.splice(jittered.end(), packets); } @@ -490,17 +490,22 @@ static void TestJitterFilter(int64_t stddev_jitter_ms) { // 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 jitter_us; + int64_t max_jitter_obtained_us = 0; for (PacketsIt it1 = original.begin(), it2 = jittered.begin(); it1 != original.end() && it2 != jittered.end(); ++it1, ++it2) { const MediaPacket* packet1 = static_cast(*it1); const MediaPacket* packet2 = static_cast(*it2); EXPECT_EQ(packet1->header().sequenceNumber, packet2->header().sequenceNumber); - jitter_us.Push(packet1->send_time_us() - packet2->send_time_us()); + max_jitter_obtained_us = + std::max(max_jitter_obtained_us, + packet2->send_time_us() - packet1->send_time_us()); + jitter_us.Push(packet2->send_time_us() - packet1->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); + EXPECT_NEAR(filter.MeanUs(), jitter_us.GetMean(), + max_jitter_ms * 1000.0 * 0.01); + EXPECT_NEAR(max_jitter_ms * 1000.0, max_jitter_obtained_us, + max_jitter_ms * 1000.0 * 0.01); for (auto* packet : original) delete packet; for (auto* packet : jittered) diff --git a/webrtc/modules/remote_bitrate_estimator/test/packet.h b/webrtc/modules/remote_bitrate_estimator/test/packet.h index e565e9f5db..4edad8fdae 100644 --- a/webrtc/modules/remote_bitrate_estimator/test/packet.h +++ b/webrtc/modules/remote_bitrate_estimator/test/packet.h @@ -36,6 +36,7 @@ class Packet { virtual int flow_id() const { return flow_id_; } virtual void set_send_time_us(int64_t send_time_us); virtual int64_t send_time_us() const { return send_time_us_; } + virtual int64_t sender_timestamp_us() const { return sender_timestamp_us_; } virtual size_t payload_size() const { return payload_size_; } virtual Packet::Type GetPacketType() const = 0; virtual void set_sender_timestamp_us(int64_t sender_timestamp_us) {