Updating NACK RTX test

BUG=1513
R=holmer@google.com, stefan@webrtc.org

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

git-svn-id: http://webrtc.googlecode.com/svn/trunk/webrtc@4036 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/modules/rtp_rtcp/source/nack_rtx_unittest.cc b/modules/rtp_rtcp/source/nack_rtx_unittest.cc
index b1d494c..2d1306a 100644
--- a/modules/rtp_rtcp/source/nack_rtx_unittest.cc
+++ b/modules/rtp_rtcp/source/nack_rtx_unittest.cc
@@ -1,30 +1,35 @@
 /*
- *  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.
- */
+*  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 <algorithm>
-#include <vector>
+#include <iterator>
+#include <list>
+#include <set>
 
 #include "testing/gtest/include/gtest/gtest.h"
 #include "webrtc/common_types.h"
 #include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h"
 #include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h"
 
-namespace webrtc {
-const int kVideoNackListSize = 10;
+using namespace webrtc;
+
+const int kVideoNackListSize = 30;
 const int kTestId = 123;
 const uint32_t kTestSsrc = 3456;
 const uint16_t kTestSequenceNumber = 2345;
-const uint32_t kTestNumberOfPackets = 450;
-const int kTestNumberOfRtxPackets = 49;
+const uint32_t kTestNumberOfPackets = 1350;
+const int kTestNumberOfRtxPackets = 149;
+const int kNumFrames = 30;
 
-class VerifyingRtxReceiver : public RtpData {
+class VerifyingRtxReceiver : public RtpData
+{
  public:
   VerifyingRtxReceiver() {}
 
@@ -32,13 +37,12 @@
       const uint8_t* data,
       const uint16_t size,
       const webrtc::WebRtcRTPHeader* rtp_header) {
-    if (!sequence_numbers_.empty()) {
+    if (!sequence_numbers_.empty())
       EXPECT_EQ(kTestSsrc, rtp_header->header.ssrc);
-    }
     sequence_numbers_.push_back(rtp_header->header.sequenceNumber);
     return 0;
   }
-  std::vector<uint16_t > sequence_numbers_;
+  std::list<uint16_t> sequence_numbers_;
 };
 
 class RtxLoopBackTransport : public webrtc::Transport {
@@ -46,31 +50,49 @@
   explicit RtxLoopBackTransport(uint32_t rtx_ssrc)
       : count_(0),
         packet_loss_(0),
+        consecutive_drop_start_(0),
+        consecutive_drop_end_(0),
         rtx_ssrc_(rtx_ssrc),
         count_rtx_ssrc_(0),
         module_(NULL) {
   }
+
   void SetSendModule(RtpRtcp* rtpRtcpModule) {
     module_ = rtpRtcpModule;
   }
+
   void DropEveryNthPacket(int n) {
     packet_loss_ = n;
   }
+
+  void DropConsecutivePackets(int start, int total) {
+    consecutive_drop_start_ = start;
+    consecutive_drop_end_ = start + total;
+    packet_loss_ = 0;
+  }
+
   virtual int SendPacket(int channel, const void *data, int len) {
     count_++;
     const unsigned char* ptr = static_cast<const unsigned  char*>(data);
     uint32_t ssrc = (ptr[8] << 24) + (ptr[9] << 16) + (ptr[10] << 8) + ptr[11];
     if (ssrc == rtx_ssrc_) count_rtx_ssrc_++;
+    uint16_t sequence_number = (ptr[2] << 8) + ptr[3];
+    expected_sequence_numbers_.insert(expected_sequence_numbers_.end(),
+        sequence_number);
     if (packet_loss_ > 0) {
       if ((count_ % packet_loss_) == 0) {
         return len;
       }
+    } else if (count_ >= consecutive_drop_start_ &&
+        count_ < consecutive_drop_end_) {
+      return len;
     }
     if (module_->IncomingPacket((const uint8_t*)data, len) == 0) {
       return len;
     }
     return -1;
   }
+
   virtual int SendRTCPPacket(int channel, const void *data, int len) {
     if (module_->IncomingPacket((const uint8_t*)data, len) == 0) {
       return len;
@@ -79,9 +101,12 @@
   }
   int count_;
   int packet_loss_;
+  int consecutive_drop_start_;
+  int consecutive_drop_end_;
   uint32_t rtx_ssrc_;
   int count_rtx_ssrc_;
   RtpRtcp* module_;
+  std::set<uint16_t> expected_sequence_numbers_;
 };
 
 class RtpRtcpRtxNackTest : public ::testing::Test {
@@ -126,6 +151,67 @@
     }
   }
 
+  int BuildNackList(uint16_t* nack_list) {
+    receiver_.sequence_numbers_.sort();
+    std::list<uint16_t> missing_sequence_numbers;
+    std::list<uint16_t>::iterator it =
+        receiver_.sequence_numbers_.begin();
+
+    while (it != receiver_.sequence_numbers_.end()) {
+      uint16_t sequence_number_1 = *it;
+      ++it;
+      if (it != receiver_.sequence_numbers_.end()) {
+        uint16_t sequence_number_2 = *it;
+        // Add all missing sequence numbers to list
+        for (uint16_t i = sequence_number_1 + 1; i < sequence_number_2;
+            ++i) {
+          missing_sequence_numbers.push_back(i);
+        }
+      }
+    }
+    int n = 0;
+    for (it = missing_sequence_numbers.begin();
+        it != missing_sequence_numbers.end(); ++it) {
+      nack_list[n++] = (*it);
+    }
+    return n;
+  }
+
+  bool ExpectedPacketsReceived() {
+    std::list<uint16_t> received_sorted;
+    std::copy(receiver_.sequence_numbers_.begin(),
+              receiver_.sequence_numbers_.end(),
+              std::back_inserter(received_sorted));
+    received_sorted.sort();
+    return std::equal(received_sorted.begin(), received_sorted.end(),
+                      transport_.expected_sequence_numbers_.begin());
+  }
+
+  void RunRtxTest(RtxMode rtx_method, int loss) {
+    EXPECT_EQ(0, rtp_rtcp_module_->SetRTXReceiveStatus(true, kTestSsrc + 1));
+    EXPECT_EQ(0, rtp_rtcp_module_->SetRTXSendStatus(rtx_method, true,
+        kTestSsrc + 1));
+    transport_.DropEveryNthPacket(loss);
+    uint32_t timestamp = 3000;
+    uint16_t nack_list[kVideoNackListSize];
+    for (int frame = 0; frame < kNumFrames; ++frame) {
+      EXPECT_EQ(0, rtp_rtcp_module_->SendOutgoingData(webrtc::kVideoFrameDelta,
+                                                      123,
+                                                      timestamp,
+                                                      timestamp / 90,
+                                                      payload_data,
+                                                      payload_data_length));
+      int length = BuildNackList(nack_list);
+      if (length > 0)
+        rtp_rtcp_module_->SendNACK(nack_list, length);
+      fake_clock.AdvanceTimeMilliseconds(33);
+      rtp_rtcp_module_->Process();
+      // Prepare next frame.
+      timestamp += 3000;
+    }
+    receiver_.sequence_numbers_.sort();
+  }
+
   virtual void TearDown() {
     delete rtp_rtcp_module_;
   }
@@ -138,146 +224,62 @@
   SimulatedClock fake_clock;
 };
 
-TEST_F(RtpRtcpRtxNackTest, RTCP) {
+TEST_F(RtpRtcpRtxNackTest, LongNackList) {
+  const int kNumPacketsToDrop = 900;
+  const int kNumRequiredRtcp = 4;
   uint32_t timestamp = 3000;
-  uint16_t nack_list[kVideoNackListSize];
-  transport_.DropEveryNthPacket(10);
-
-  for (int frame = 0; frame < 10; ++frame) {
+  uint16_t nack_list[kNumPacketsToDrop];
+  // Disable StorePackets to be able to set a larger packet history.
+  EXPECT_EQ(0, rtp_rtcp_module_->SetStorePacketsStatus(false, 0));
+  // Enable StorePackets with a packet history of 2000 packets.
+  EXPECT_EQ(0, rtp_rtcp_module_->SetStorePacketsStatus(true, 2000));
+  // Drop 900 packets from the second one so that we get a NACK list which is
+  // big enough to require 4 RTCP packets to be fully transmitted to the sender.
+  transport_.DropConsecutivePackets(2, kNumPacketsToDrop);
+  // Send 30 frames which at the default size is roughly what we need to get
+  // enough packets.
+  for (int frame = 0; frame < kNumFrames; ++frame) {
     EXPECT_EQ(0, rtp_rtcp_module_->SendOutgoingData(webrtc::kVideoFrameDelta,
                                                     123,
                                                     timestamp,
                                                     timestamp / 90,
                                                     payload_data,
                                                     payload_data_length));
-
-    std::sort(receiver_.sequence_numbers_.begin(),
-              receiver_.sequence_numbers_.end());
-
-    std::vector<uint16_t> missing_sequence_numbers;
-    std::vector<uint16_t>::iterator it =
-        receiver_.sequence_numbers_.begin();
-
-    while (it != receiver_.sequence_numbers_.end()) {
-      uint16_t sequence_number_1 = *it;
-      ++it;
-      if (it != receiver_.sequence_numbers_.end()) {
-        uint16_t sequence_number_2 = *it;
-        // Add all missing sequence numbers to list.
-        for (uint16_t i = sequence_number_1 + 1; i < sequence_number_2;
-            ++i) {
-          missing_sequence_numbers.push_back(i);
-        }
-      }
-    }
-    int n = 0;
-    for (it = missing_sequence_numbers.begin();
-        it != missing_sequence_numbers.end(); ++it) {
-      nack_list[n++] = (*it);
-    }
-    rtp_rtcp_module_->SendNACK(nack_list, n);
-    fake_clock.AdvanceTimeMilliseconds(33);
-    rtp_rtcp_module_->Process();
-
     // Prepare next frame.
     timestamp += 3000;
+    fake_clock.AdvanceTimeMilliseconds(33);
+    rtp_rtcp_module_->Process();
   }
-  std::sort(receiver_.sequence_numbers_.begin(),
-            receiver_.sequence_numbers_.end());
-  EXPECT_EQ(kTestSequenceNumber, *(receiver_.sequence_numbers_.begin()));
-  EXPECT_EQ(kTestSequenceNumber + kTestNumberOfPackets - 1,
-            *(receiver_.sequence_numbers_.rbegin()));
-  EXPECT_EQ(kTestNumberOfPackets, receiver_.sequence_numbers_.size());
-  EXPECT_EQ(0, transport_.count_rtx_ssrc_);
+  EXPECT_FALSE(transport_.expected_sequence_numbers_.empty());
+  EXPECT_FALSE(receiver_.sequence_numbers_.empty());
+  size_t last_receive_count = receiver_.sequence_numbers_.size();
+  int length = BuildNackList(nack_list);
+  for (int i = 0; i < kNumRequiredRtcp - 1; ++i) {
+    rtp_rtcp_module_->SendNACK(nack_list, length);
+    EXPECT_GT(receiver_.sequence_numbers_.size(), last_receive_count);
+    last_receive_count = receiver_.sequence_numbers_.size();
+    EXPECT_FALSE(ExpectedPacketsReceived());
+  }
+  rtp_rtcp_module_->SendNACK(nack_list, length);
+  EXPECT_GT(receiver_.sequence_numbers_.size(), last_receive_count);
+  EXPECT_TRUE(ExpectedPacketsReceived());
 }
 
-TEST_F(RtpRtcpRtxNackTest, RTXNack) {
-  EXPECT_EQ(0, rtp_rtcp_module_->SetRTXReceiveStatus(true, kTestSsrc + 1));
-  rtp_rtcp_module_->SetRtxReceivePayloadType(119);
-  EXPECT_EQ(0, rtp_rtcp_module_->SetRTXSendStatus(kRtxRetransmitted, true,
-                                                  kTestSsrc + 1));
-  rtp_rtcp_module_->SetRtxSendPayloadType(119);
-
-  transport_.DropEveryNthPacket(10);
-
-  uint32_t timestamp = 3000;
-  uint16_t nack_list[kVideoNackListSize];
-
-  for (int frame = 0; frame < 10; ++frame) {
-    EXPECT_EQ(0, rtp_rtcp_module_->SendOutgoingData(webrtc::kVideoFrameDelta,
-                                                    123,
-                                                    timestamp,
-                                                    timestamp / 90,
-                                                    payload_data,
-                                                    payload_data_length));
-
-    std::sort(receiver_.sequence_numbers_.begin(),
-              receiver_.sequence_numbers_.end());
-
-    std::vector<uint16_t> missing_sequence_numbers;
-
-
-    std::vector<uint16_t>::iterator it =
-        receiver_.sequence_numbers_.begin();
-    while (it != receiver_.sequence_numbers_.end()) {
-      int sequence_number_1 = *it;
-      ++it;
-      if (it != receiver_.sequence_numbers_.end()) {
-        int sequence_number_2 = *it;
-        // Add all missing sequence numbers to list.
-        for (int i = sequence_number_1 + 1; i < sequence_number_2; ++i) {
-          missing_sequence_numbers.push_back(i);
-        }
-      }
-    }
-    int n = 0;
-    for (it = missing_sequence_numbers.begin();
-        it != missing_sequence_numbers.end(); ++it) {
-      nack_list[n++] = (*it);
-    }
-    rtp_rtcp_module_->SendNACK(nack_list, n);
-    fake_clock.AdvanceTimeMilliseconds(33);
-    rtp_rtcp_module_->Process();
-
-    // Prepare next frame.
-    timestamp += 3000;
-  }
-  std::sort(receiver_.sequence_numbers_.begin(),
-            receiver_.sequence_numbers_.end());
+TEST_F(RtpRtcpRtxNackTest, RtxNack) {
+  RunRtxTest(kRtxRetransmitted, 10);
   EXPECT_EQ(kTestSequenceNumber, *(receiver_.sequence_numbers_.begin()));
   EXPECT_EQ(kTestSequenceNumber + kTestNumberOfPackets - 1,
-            *(receiver_.sequence_numbers_.rbegin()));
+      *(receiver_.sequence_numbers_.rbegin()));
   EXPECT_EQ(kTestNumberOfPackets, receiver_.sequence_numbers_.size());
   EXPECT_EQ(kTestNumberOfRtxPackets, transport_.count_rtx_ssrc_);
+  EXPECT_TRUE(ExpectedPacketsReceived());
 }
 
 TEST_F(RtpRtcpRtxNackTest, RTXAllNoLoss) {
-  EXPECT_EQ(0, rtp_rtcp_module_->SetRTXReceiveStatus(true, kTestSsrc + 1));
-  EXPECT_EQ(0, rtp_rtcp_module_->SetRTXSendStatus(kRtxAll, true,
-                                                  kTestSsrc + 1));
-  transport_.DropEveryNthPacket(0);
-
-  uint32_t timestamp = 3000;
-
-  for (int frame = 0; frame < 10; ++frame) {
-    EXPECT_EQ(0, rtp_rtcp_module_->SendOutgoingData(webrtc::kVideoFrameDelta,
-                                                    123,
-                                                    timestamp,
-                                                    timestamp / 90,
-                                                    payload_data,
-                                                    payload_data_length));
-
-    fake_clock.AdvanceTimeMilliseconds(33);
-    rtp_rtcp_module_->Process();
-
-    // Prepare next frame.
-    timestamp += 3000;
-  }
-  std::sort(receiver_.sequence_numbers_.begin(),
-            receiver_.sequence_numbers_.end());
+  RunRtxTest(kRtxAll, 0);
   EXPECT_EQ(kTestSequenceNumber, *(receiver_.sequence_numbers_.begin()));
   EXPECT_EQ(kTestSequenceNumber + kTestNumberOfPackets - 1,
-            *(receiver_.sequence_numbers_.rbegin()));
+      *(receiver_.sequence_numbers_.rbegin()));
   // We have transmitted all packets twice, and loss was set to 0.
   EXPECT_EQ(kTestNumberOfPackets * 2u, receiver_.sequence_numbers_.size());
   // Half of the packets should be via RTX.
@@ -286,63 +288,13 @@
 }
 
 TEST_F(RtpRtcpRtxNackTest, RTXAllWithLoss) {
-  EXPECT_EQ(0, rtp_rtcp_module_->SetRTXReceiveStatus(true, kTestSsrc + 1));
-  EXPECT_EQ(0, rtp_rtcp_module_->SetRTXSendStatus(kRtxAll, true,
-                                                  kTestSsrc + 1));
-
   int loss = 10;
-  transport_.DropEveryNthPacket(loss);
-
-  uint32_t timestamp = 3000;
-  uint16_t nack_list[kVideoNackListSize];
-
-  for (int frame = 0; frame < 10; ++frame) {
-    EXPECT_EQ(0, rtp_rtcp_module_->SendOutgoingData(webrtc::kVideoFrameDelta,
-                                                    123,
-                                                    timestamp,
-                                                    timestamp / 90,
-                                                    payload_data,
-                                                    payload_data_length));
-    std::sort(receiver_.sequence_numbers_.begin(),
-              receiver_.sequence_numbers_.end());
-    std::vector<uint16_t> missing_sequence_numbers;
-
-    std::vector<uint16_t>::iterator it =
-        receiver_.sequence_numbers_.begin();
-    while (it != receiver_.sequence_numbers_.end()) {
-      int sequence_number_1 = *it;
-      ++it;
-      if (it != receiver_.sequence_numbers_.end()) {
-        int sequence_number_2 = *it;
-        // Add all missing sequence numbers to list.
-        for (int i = sequence_number_1 + 1; i < sequence_number_2; ++i) {
-          missing_sequence_numbers.push_back(i);
-        }
-      }
-    }
-    int n = 0;
-    for (it = missing_sequence_numbers.begin();
-        it != missing_sequence_numbers.end(); ++it) {
-      nack_list[n++] = (*it);
-    }
-    if (n > 0)
-      rtp_rtcp_module_->SendNACK(nack_list, n);
-    fake_clock.AdvanceTimeMilliseconds(33);
-    rtp_rtcp_module_->Process();
-
-    // Prepare next frame.
-    timestamp += 3000;
-  }
-  std::sort(receiver_.sequence_numbers_.begin(),
-            receiver_.sequence_numbers_.end());
+  RunRtxTest(kRtxAll, loss);
   EXPECT_EQ(kTestSequenceNumber, *(receiver_.sequence_numbers_.begin()));
   EXPECT_EQ(kTestSequenceNumber + kTestNumberOfPackets - 1,
-            *(receiver_.sequence_numbers_.rbegin()));
-  // Got everything but 10% loss.
-  EXPECT_EQ(2u * (kTestNumberOfPackets - kTestNumberOfPackets / 10),
-            receiver_.sequence_numbers_.size());
-  EXPECT_EQ(static_cast<int>(kTestNumberOfPackets),
-            transport_.count_rtx_ssrc_);
+      *(receiver_.sequence_numbers_.rbegin()));
+  // Got everything but lost packets.
+  EXPECT_EQ(2u * (kTestNumberOfPackets - kTestNumberOfPackets / loss),
+      receiver_.sequence_numbers_.size());
+  EXPECT_EQ(static_cast<int>(kTestNumberOfPackets), transport_.count_rtx_ssrc_);
 }
-
-}  // namespace webrtc