From 2d06e366e86be59961335c150fa99abf96e2750e Mon Sep 17 00:00:00 2001 From: Alex Narest Date: Tue, 13 Feb 2018 15:55:27 +0100 Subject: [PATCH] Adds fixed PL loss mode to neteq_quality_test. It will be available in all inheriting tests. The mode allows setting start time and duration for every loss event. Bug: webrtc:8877 Change-Id: Ife36db6d431387083ac22406a0814e02117100bc Reviewed-on: https://webrtc-review.googlesource.com/51822 Commit-Queue: Alex Narest Reviewed-by: Henrik Lundin Cr-Commit-Position: refs/heads/master@{#22005} --- .../neteq/tools/neteq_quality_test.cc | 73 ++++++++++++++++--- .../neteq/tools/neteq_quality_test.h | 41 ++++++++++- 2 files changed, 98 insertions(+), 16 deletions(-) diff --git a/modules/audio_coding/neteq/tools/neteq_quality_test.cc b/modules/audio_coding/neteq/tools/neteq_quality_test.cc index af5328e76d..82fa90e602 100644 --- a/modules/audio_coding/neteq/tools/neteq_quality_test.cc +++ b/modules/audio_coding/neteq/tools/neteq_quality_test.cc @@ -62,8 +62,10 @@ DEFINE_int(runtime_ms, 10000, "Simulated runtime (milliseconds)."); DEFINE_int(packet_loss_rate, 10, "Percentile of packet loss."); -DEFINE_int(random_loss_mode, 1, - "Random loss mode: 0--no loss, 1--uniform loss, 2--Gilbert Elliot loss."); +DEFINE_int(random_loss_mode, + kUniformLoss, + "Random loss mode: 0--no loss, 1--uniform loss, 2--Gilbert Elliot " + "loss, 3--fixed loss."); DEFINE_int(burst_length, 30, "Burst length in milliseconds, only valid for Gilbert Elliot loss."); @@ -72,6 +74,12 @@ DEFINE_float(drift_factor, 0.0, "Time drift factor."); DEFINE_int(preload_packets, 0, "Preload the buffer with this many packets."); +DEFINE_string(loss_events, + "", + "List of loss events time and duration separated by comma: " + " , " + ", ..."); + // ProbTrans00Solver() is to calculate the transition probability from no-loss // state to itself in a modified Gilbert Elliot packet loss model. The result is // to achieve the target packet loss rate |loss_rate|, when a packet is not @@ -157,8 +165,9 @@ NetEqQualityTest::NetEqQualityTest(int block_duration_ms, RTC_CHECK(FLAG_packet_loss_rate >= 0 && FLAG_packet_loss_rate <= 100) << "Invalid packet loss percentile, should be between 0 and 100."; - RTC_CHECK(FLAG_random_loss_mode >= 0 && FLAG_random_loss_mode <= 2) - << "Invalid random packet loss mode, should be between 0 and 2."; + RTC_CHECK(FLAG_random_loss_mode >= 0 && FLAG_random_loss_mode < kLastLossMode) + << "Invalid random packet loss mode, should be between 0 and " + << kLastLossMode - 1 << "."; RTC_CHECK_GE(FLAG_burst_length, kPacketLossTimeUnitMs) << "Invalid burst length, should be greater than or equal to " @@ -197,7 +206,7 @@ NetEqQualityTest::~NetEqQualityTest() { log_file_.close(); } -bool NoLoss::Lost() { +bool NoLoss::Lost(int now_ms) { return false; } @@ -205,7 +214,7 @@ UniformLoss::UniformLoss(double loss_rate) : loss_rate_(loss_rate) { } -bool UniformLoss::Lost() { +bool UniformLoss::Lost(int now_ms) { int drop_this = rand(); return (drop_this < loss_rate_ * RAND_MAX); } @@ -219,20 +228,41 @@ GilbertElliotLoss::GilbertElliotLoss(double prob_trans_11, double prob_trans_01) GilbertElliotLoss::~GilbertElliotLoss() {} -bool GilbertElliotLoss::Lost() { +bool GilbertElliotLoss::Lost(int now_ms) { // Simulate bursty channel (Gilbert model). // (1st order) Markov chain model with memory of the previous/last // packet state (lost or received). if (lost_last_) { // Previous packet was not received. uniform_loss_model_->set_loss_rate(prob_trans_11_); - return lost_last_ = uniform_loss_model_->Lost(); + return lost_last_ = uniform_loss_model_->Lost(now_ms); } else { uniform_loss_model_->set_loss_rate(prob_trans_01_); - return lost_last_ = uniform_loss_model_->Lost(); + return lost_last_ = uniform_loss_model_->Lost(now_ms); } } +FixedLossModel::FixedLossModel( + std::set loss_events) + : loss_events_(loss_events) { + loss_events_it_ = loss_events_.begin(); +} + +FixedLossModel::~FixedLossModel() {} + +bool FixedLossModel::Lost(int now_ms) { + if (loss_events_it_ != loss_events_.end() && + now_ms > loss_events_it_->start_ms) { + if (now_ms <= loss_events_it_->start_ms + loss_events_it_->duration_ms) { + return true; + } else { + ++loss_events_it_; + return false; + } + } + return false; +} + void NetEqQualityTest::SetUp() { ASSERT_EQ(0, neteq_->RegisterPayloadType(decoder_type_, "noname", kPayloadType)); @@ -240,7 +270,7 @@ void NetEqQualityTest::SetUp() { int units = block_duration_ms_ / kPacketLossTimeUnitMs; switch (FLAG_random_loss_mode) { - case 1: { + case kUniformLoss: { // |unit_loss_rate| is the packet loss rate for each unit time interval // (kPacketLossTimeUnitMs). Since a packet loss event is generated if any // of |block_duration_ms_ / kPacketLossTimeUnitMs| unit time intervals of @@ -252,7 +282,7 @@ void NetEqQualityTest::SetUp() { loss_model_.reset(new UniformLoss(unit_loss_rate)); break; } - case 2: { + case kGilbertElliotLoss: { // |FLAG_burst_length| should be integer times of kPacketLossTimeUnitMs. ASSERT_EQ(0, FLAG_burst_length % kPacketLossTimeUnitMs); @@ -278,6 +308,25 @@ void NetEqQualityTest::SetUp() { 1.0f - prob_trans_00)); break; } + case kFixedLoss: { + std::istringstream loss_events_stream(FLAG_loss_events); + std::string loss_event_string; + std::set loss_events; + while (std::getline(loss_events_stream, loss_event_string, ',')) { + std::vector loss_event_params; + std::istringstream loss_event_params_stream(loss_event_string); + std::copy(std::istream_iterator(loss_event_params_stream), + std::istream_iterator(), + std::back_inserter(loss_event_params)); + RTC_CHECK_EQ(loss_event_params.size(), 2); + auto result = loss_events.insert( + FixedLossEvent(loss_event_params[0], loss_event_params[1])); + RTC_CHECK(result.second); + } + RTC_CHECK_GT(loss_events.size(), 0); + loss_model_.reset(new FixedLossModel(loss_events)); + break; + } default: { loss_model_.reset(new NoLoss); break; @@ -299,7 +348,7 @@ bool NetEqQualityTest::PacketLost() { // same packet loss profile. bool lost = false; for (int idx = 0; idx < cycles; idx ++) { - if (loss_model_->Lost()) { + if (loss_model_->Lost(decoded_time_ms_)) { // The packet will be lost if any of the drawings indicates a loss, but // the loop has to go on to make sure that codecs with different block // lengths keep the same pace. diff --git a/modules/audio_coding/neteq/tools/neteq_quality_test.h b/modules/audio_coding/neteq/tools/neteq_quality_test.h index 8532f25a0d..531a0805ab 100644 --- a/modules/audio_coding/neteq/tools/neteq_quality_test.h +++ b/modules/audio_coding/neteq/tools/neteq_quality_test.h @@ -27,21 +27,29 @@ namespace webrtc { namespace test { +enum LossModes { + kNoLoss, + kUniformLoss, + kGilbertElliotLoss, + kFixedLoss, + kLastLossMode +}; + class LossModel { public: virtual ~LossModel() {}; - virtual bool Lost() = 0; + virtual bool Lost(int now_ms) = 0; }; class NoLoss : public LossModel { public: - bool Lost() override; + bool Lost(int now_ms) override; }; class UniformLoss : public LossModel { public: UniformLoss(double loss_rate); - bool Lost() override; + bool Lost(int now_ms) override; void set_loss_rate(double loss_rate) { loss_rate_ = loss_rate; } private: @@ -52,7 +60,7 @@ class GilbertElliotLoss : public LossModel { public: GilbertElliotLoss(double prob_trans_11, double prob_trans_01); ~GilbertElliotLoss() override; - bool Lost() override; + bool Lost(int now_ms) override; private: // Prob. of losing current packet, when previous packet is lost. @@ -63,6 +71,31 @@ class GilbertElliotLoss : public LossModel { std::unique_ptr uniform_loss_model_; }; +struct FixedLossEvent { + int start_ms; + int duration_ms; + FixedLossEvent(int start_ms, int duration_ms) + : start_ms(start_ms), duration_ms(duration_ms) {} +}; + +struct FixedLossEventCmp { + bool operator()(const FixedLossEvent& l_event, + const FixedLossEvent& r_event) const { + return l_event.start_ms < r_event.start_ms; + } +}; + +class FixedLossModel : public LossModel { + public: + FixedLossModel(std::set loss_events); + ~FixedLossModel() override; + bool Lost(int now_ms) override; + + private: + std::set loss_events_; + std::set::iterator loss_events_it_; +}; + class NetEqQualityTest : public ::testing::Test { protected: NetEqQualityTest(int block_duration_ms,