Fix for retransmission. Base layer packets were not retransmitted.
Issue introduced in r6669.

R=stefan@webrtc.org

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

git-svn-id: http://webrtc.googlecode.com/svn/trunk/webrtc@6816 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/modules/rtp_rtcp/source/rtp_rtcp_impl_unittest.cc b/modules/rtp_rtcp/source/rtp_rtcp_impl_unittest.cc
index 3101a1f..9486abd 100644
--- a/modules/rtp_rtcp/source/rtp_rtcp_impl_unittest.cc
+++ b/modules/rtp_rtcp/source/rtp_rtcp_impl_unittest.cc
@@ -15,6 +15,7 @@
 #include "webrtc/modules/pacing/include/mock/mock_paced_sender.h"
 #include "webrtc/modules/rtp_rtcp/interface/rtp_header_parser.h"
 #include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h"
+#include "webrtc/modules/rtp_rtcp/source/rtcp_packet.h"
 #include "webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h"
 #include "webrtc/system_wrappers/interface/scoped_vector.h"
 
@@ -29,6 +30,9 @@
 const uint32_t kReceiverSsrc = 0x23456;
 const uint32_t kSenderRtxSsrc = 0x32345;
 const uint32_t kOneWayNetworkDelayMs = 100;
+const uint8_t kBaseLayerTid = 0;
+const uint8_t kHigherLayerTid = 1;
+const uint16_t kSequenceNumber = 100;
 
 class RtcpRttStatsTestImpl : public RtcpRttStats {
  public:
@@ -47,7 +51,12 @@
 class SendTransport : public Transport,
                       public NullRtpData {
  public:
-  SendTransport() : receiver_(NULL), clock_(NULL), delay_ms_(0) {}
+  SendTransport()
+      : receiver_(NULL),
+        clock_(NULL),
+        delay_ms_(0),
+        rtp_packets_sent_(0) {
+  }
 
   void SetRtpRtcpModule(ModuleRtpRtcpImpl* receiver) {
     receiver_ = receiver;
@@ -56,8 +65,15 @@
     clock_ = clock;
     delay_ms_ = delay_ms;
   }
-  virtual int SendPacket(int /*ch*/, const void* /*data*/, int /*len*/) {
-    return -1;
+  virtual int SendPacket(int /*ch*/, const void* data, int len) {
+    RTPHeader header;
+    scoped_ptr<RtpHeaderParser> parser(RtpHeaderParser::Create());
+    EXPECT_TRUE(parser->Parse(static_cast<const uint8_t*>(data),
+                              static_cast<size_t>(len),
+                              &header));
+    ++rtp_packets_sent_;
+    last_rtp_header_ = header;
+    return len;
   }
   virtual int SendRTCPPacket(int /*ch*/, const void *data, int len) {
     if (clock_) {
@@ -71,6 +87,8 @@
   ModuleRtpRtcpImpl* receiver_;
   SimulatedClock* clock_;
   uint32_t delay_ms_;
+  int rtp_packets_sent_;
+  RTPHeader last_rtp_header_;
 };
 
 class RtpRtcpModule {
@@ -105,6 +123,12 @@
     impl_->GetRtcpPacketTypeCounters(&packets_sent_, &packets_received_);
     return packets_received_;
   }
+  int RtpSent() {
+    return transport_.rtp_packets_sent_;
+  }
+  uint16_t LastRtpSequenceNumber() {
+    return transport_.last_rtp_header_.sequenceNumber;
+  }
 };
 }  // namespace
 
@@ -116,10 +140,22 @@
         receiver_(&clock_) {
     // Send module.
     EXPECT_EQ(0, sender_.impl_->SetSendingStatus(true));
+    EXPECT_EQ(0, sender_.impl_->SetSendingMediaStatus(true));
     sender_.impl_->SetSSRC(kSenderSsrc);
     sender_.impl_->SetRemoteSSRC(kReceiverSsrc);
+    sender_.impl_->SetSequenceNumber(kSequenceNumber);
+    sender_.impl_->SetStorePacketsStatus(true, 100);
+
+    memset(&codec_, 0, sizeof(VideoCodec));
+    codec_.plType = 100;
+    strncpy(codec_.plName, "VP8", 3);
+    codec_.width = 320;
+    codec_.height = 180;
+    EXPECT_EQ(0, sender_.impl_->RegisterSendPayload(codec_));
+
     // Receive module.
     EXPECT_EQ(0, receiver_.impl_->SetSendingStatus(false));
+    EXPECT_EQ(0, receiver_.impl_->SetSendingMediaStatus(false));
     receiver_.impl_->SetSSRC(kReceiverSsrc);
     receiver_.impl_->SetRemoteSSRC(kSenderSsrc);
     // Transport settings.
@@ -129,8 +165,91 @@
   SimulatedClock clock_;
   RtpRtcpModule sender_;
   RtpRtcpModule receiver_;
+  VideoCodec codec_;
+
+  void SendFrame(const RtpRtcpModule* module, uint8_t tid) {
+    RTPVideoHeaderVP8 vp8_header = {};
+    vp8_header.temporalIdx = tid;
+    RTPVideoHeader rtp_video_header = {
+        codec_.width, codec_.height, true, 0, kRtpVideoVp8, {vp8_header}};
+
+    const uint8_t payload[100] = {0};
+    EXPECT_EQ(0, module->impl_->SendOutgoingData(kVideoFrameKey,
+                                                 codec_.plType,
+                                                 0,
+                                                 0,
+                                                 payload,
+                                                 sizeof(payload),
+                                                 NULL,
+                                                 &rtp_video_header));
+  }
+
+  void IncomingRtcpNack(const RtpRtcpModule* module, uint16_t sequence_number) {
+    rtcp::Nack nack;
+    uint16_t list[1];
+    list[0] = sequence_number;
+    const uint16_t kListLength = sizeof(list) / sizeof(list[0]);
+    nack.From(kReceiverSsrc);
+    nack.To(kSenderSsrc);
+    nack.WithList(list, kListLength);
+    rtcp::RawPacket packet = nack.Build();
+    EXPECT_EQ(0, module->impl_->IncomingRtcpPacket(packet.buffer(),
+                                                   packet.buffer_length()));
+  }
 };
 
+TEST_F(RtpRtcpImplTest, SetSelectiveRetransmissions_BaseLayer) {
+  sender_.impl_->SetSelectiveRetransmissions(kRetransmitBaseLayer);
+  EXPECT_EQ(kRetransmitBaseLayer, sender_.impl_->SelectiveRetransmissions());
+
+  // Send frames.
+  EXPECT_EQ(0, sender_.RtpSent());
+  SendFrame(&sender_, kBaseLayerTid);    // kSequenceNumber
+  SendFrame(&sender_, kHigherLayerTid);  // kSequenceNumber + 1
+  SendFrame(&sender_, kNoTemporalIdx);   // kSequenceNumber + 2
+  EXPECT_EQ(3, sender_.RtpSent());
+  EXPECT_EQ(kSequenceNumber + 2, sender_.LastRtpSequenceNumber());
+
+  // Frame with kBaseLayerTid re-sent.
+  IncomingRtcpNack(&sender_, kSequenceNumber);
+  EXPECT_EQ(4, sender_.RtpSent());
+  EXPECT_EQ(kSequenceNumber, sender_.LastRtpSequenceNumber());
+  // Frame with kHigherLayerTid not re-sent.
+  IncomingRtcpNack(&sender_, kSequenceNumber + 1);
+  EXPECT_EQ(4, sender_.RtpSent());
+  // Frame with kNoTemporalIdx re-sent.
+  IncomingRtcpNack(&sender_, kSequenceNumber + 2);
+  EXPECT_EQ(5, sender_.RtpSent());
+  EXPECT_EQ(kSequenceNumber + 2, sender_.LastRtpSequenceNumber());
+}
+
+TEST_F(RtpRtcpImplTest, SetSelectiveRetransmissions_HigherLayers) {
+  const uint8_t kSetting = kRetransmitBaseLayer + kRetransmitHigherLayers;
+  sender_.impl_->SetSelectiveRetransmissions(kSetting);
+  EXPECT_EQ(kSetting, sender_.impl_->SelectiveRetransmissions());
+
+  // Send frames.
+  EXPECT_EQ(0, sender_.RtpSent());
+  SendFrame(&sender_, kBaseLayerTid);    // kSequenceNumber
+  SendFrame(&sender_, kHigherLayerTid);  // kSequenceNumber + 1
+  SendFrame(&sender_, kNoTemporalIdx);   // kSequenceNumber + 2
+  EXPECT_EQ(3, sender_.RtpSent());
+  EXPECT_EQ(kSequenceNumber + 2, sender_.LastRtpSequenceNumber());
+
+  // Frame with kBaseLayerTid re-sent.
+  IncomingRtcpNack(&sender_, kSequenceNumber);
+  EXPECT_EQ(4, sender_.RtpSent());
+  EXPECT_EQ(kSequenceNumber, sender_.LastRtpSequenceNumber());
+  // Frame with kHigherLayerTid re-sent.
+  IncomingRtcpNack(&sender_, kSequenceNumber + 1);
+  EXPECT_EQ(5, sender_.RtpSent());
+  EXPECT_EQ(kSequenceNumber + 1, sender_.LastRtpSequenceNumber());
+  // Frame with kNoTemporalIdx re-sent.
+  IncomingRtcpNack(&sender_, kSequenceNumber + 2);
+  EXPECT_EQ(6, sender_.RtpSent());
+  EXPECT_EQ(kSequenceNumber + 2, sender_.LastRtpSequenceNumber());
+}
+
 TEST_F(RtpRtcpImplTest, Rtt) {
   RTPHeader header;
   header.timestamp = 1;
diff --git a/modules/rtp_rtcp/source/rtp_sender_video.cc b/modules/rtp_rtcp/source/rtp_sender_video.cc
index 95e8f97..da58f61 100644
--- a/modules/rtp_rtcp/source/rtp_sender_video.cc
+++ b/modules/rtp_rtcp/source/rtp_sender_video.cc
@@ -437,6 +437,7 @@
         !(_retransmissionSettings & kRetransmitBaseLayer)) {
       storage = kDontRetransmit;
     } else if (rtpTypeHdr->VP8.temporalIdx != kNoTemporalIdx &&
+        rtpTypeHdr->VP8.temporalIdx > 0 &&
         !(_retransmissionSettings & kRetransmitHigherLayers)) {
       storage = kDontRetransmit;
     }