Add sending Nack to RtcpTransceiver

Bug: webrtc:8239
Change-Id: Idf27bb05958d9eceaf601078019f05444232581f
Reviewed-on: https://webrtc-review.googlesource.com/26260
Reviewed-by: Niels Moller <nisse@webrtc.org>
Commit-Queue: Danil Chapovalov <danilchap@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#20907}
diff --git a/modules/rtp_rtcp/source/rtcp_packet/nack.cc b/modules/rtp_rtcp/source/rtcp_packet/nack.cc
index c196e29..ba5a12b 100644
--- a/modules/rtp_rtcp/source/rtcp_packet/nack.cc
+++ b/modules/rtp_rtcp/source/rtcp_packet/nack.cc
@@ -11,6 +11,7 @@
 #include "modules/rtp_rtcp/source/rtcp_packet/nack.h"
 
 #include <algorithm>
+#include <utility>
 
 #include "modules/rtp_rtcp/source/byte_io.h"
 #include "modules/rtp_rtcp/source/rtcp_packet/common_header.h"
@@ -123,9 +124,13 @@
 
 void Nack::SetPacketIds(const uint16_t* nack_list, size_t length) {
   RTC_DCHECK(nack_list);
+  SetPacketIds(std::vector<uint16_t>(nack_list, nack_list + length));
+}
+
+void Nack::SetPacketIds(std::vector<uint16_t> nack_list) {
   RTC_DCHECK(packet_ids_.empty());
   RTC_DCHECK(packed_.empty());
-  packet_ids_.assign(nack_list, nack_list + length);
+  packet_ids_ = std::move(nack_list);
   Pack();
 }
 
diff --git a/modules/rtp_rtcp/source/rtcp_packet/nack.h b/modules/rtp_rtcp/source/rtcp_packet/nack.h
index 3f6330d..13a590f 100644
--- a/modules/rtp_rtcp/source/rtcp_packet/nack.h
+++ b/modules/rtp_rtcp/source/rtcp_packet/nack.h
@@ -30,6 +30,7 @@
   bool Parse(const CommonHeader& packet);
 
   void SetPacketIds(const uint16_t* nack_list, size_t length);
+  void SetPacketIds(std::vector<uint16_t> nack_list);
   const std::vector<uint16_t>& packet_ids() const { return packet_ids_; }
 
   size_t BlockLength() const override;
diff --git a/modules/rtp_rtcp/source/rtcp_transceiver.cc b/modules/rtp_rtcp/source/rtcp_transceiver.cc
index 7feca3f..c0b829c 100644
--- a/modules/rtp_rtcp/source/rtcp_transceiver.cc
+++ b/modules/rtp_rtcp/source/rtcp_transceiver.cc
@@ -90,6 +90,22 @@
   });
 }
 
+void RtcpTransceiver::SendNack(uint32_t ssrc,
+                               std::vector<uint16_t> sequence_numbers) {
+  // TODO(danilchap): Replace with lambda with move capture when available.
+  struct Closure {
+    void operator()() {
+      if (ptr)
+        ptr->SendNack(ssrc, std::move(sequence_numbers));
+    }
+
+    rtc::WeakPtr<RtcpTransceiverImpl> ptr;
+    uint32_t ssrc;
+    std::vector<uint16_t> sequence_numbers;
+  };
+  task_queue_->PostTask(Closure{ptr_, ssrc, std::move(sequence_numbers)});
+}
+
 void RtcpTransceiver::SendPictureLossIndication(std::vector<uint32_t> ssrcs) {
   // TODO(danilchap): Replace with lambda with move capture when available.
   struct Closure {
diff --git a/modules/rtp_rtcp/source/rtcp_transceiver.h b/modules/rtp_rtcp/source/rtcp_transceiver.h
index 9d69545..417943a 100644
--- a/modules/rtp_rtcp/source/rtcp_transceiver.h
+++ b/modules/rtp_rtcp/source/rtcp_transceiver.h
@@ -44,7 +44,10 @@
   // Stops sending REMB in following compound packets.
   void UnsetRemb();
 
-  // Request new key frame.
+  // Reports missing packets, https://tools.ietf.org/html/rfc4585#section-6.2.1
+  void SendNack(uint32_t ssrc, std::vector<uint16_t> sequence_numbers);
+
+  // Requests new key frame.
   // using PLI, https://tools.ietf.org/html/rfc4585#section-6.3.1.1
   void SendPictureLossIndication(std::vector<uint32_t> ssrcs);
   // using FIR, https://tools.ietf.org/html/rfc5104#section-4.3.1.2
diff --git a/modules/rtp_rtcp/source/rtcp_transceiver_impl.cc b/modules/rtp_rtcp/source/rtcp_transceiver_impl.cc
index b870dd1..fbe1717 100644
--- a/modules/rtp_rtcp/source/rtcp_transceiver_impl.cc
+++ b/modules/rtp_rtcp/source/rtcp_transceiver_impl.cc
@@ -18,6 +18,7 @@
 #include "modules/rtp_rtcp/source/rtcp_packet.h"
 #include "modules/rtp_rtcp/source/rtcp_packet/common_header.h"
 #include "modules/rtp_rtcp/source/rtcp_packet/fir.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/nack.h"
 #include "modules/rtp_rtcp/source/rtcp_packet/pli.h"
 #include "modules/rtp_rtcp/source/rtcp_packet/receiver_report.h"
 #include "modules/rtp_rtcp/source/rtcp_packet/report_block.h"
@@ -130,6 +131,18 @@
   remb_.reset();
 }
 
+void RtcpTransceiverImpl::SendNack(uint32_t ssrc,
+                                   std::vector<uint16_t> sequence_numbers) {
+  RTC_DCHECK(!sequence_numbers.empty());
+  SendImmediateFeedback([&](PacketSender* sender) {
+    rtcp::Nack nack;
+    nack.SetSenderSsrc(config_.feedback_ssrc);
+    nack.SetMediaSsrc(ssrc);
+    nack.SetPacketIds(std::move(sequence_numbers));
+    sender->AppendPacket(nack);
+  });
+}
+
 void RtcpTransceiverImpl::SendPictureLossIndication(
     rtc::ArrayView<const uint32_t> ssrcs) {
   RTC_DCHECK(!ssrcs.empty());
diff --git a/modules/rtp_rtcp/source/rtcp_transceiver_impl.h b/modules/rtp_rtcp/source/rtcp_transceiver_impl.h
index a89f3e1..8cde921 100644
--- a/modules/rtp_rtcp/source/rtcp_transceiver_impl.h
+++ b/modules/rtp_rtcp/source/rtcp_transceiver_impl.h
@@ -44,6 +44,8 @@
   void SetRemb(int bitrate_bps, std::vector<uint32_t> ssrcs);
   void UnsetRemb();
 
+  void SendNack(uint32_t ssrc, std::vector<uint16_t> sequence_numbers);
+
   void SendPictureLossIndication(rtc::ArrayView<const uint32_t> ssrcs);
   void SendFullIntraRequest(rtc::ArrayView<const uint32_t> ssrcs);
 
diff --git a/modules/rtp_rtcp/source/rtcp_transceiver_impl_unittest.cc b/modules/rtp_rtcp/source/rtcp_transceiver_impl_unittest.cc
index c7f7482..2d291b2 100644
--- a/modules/rtp_rtcp/source/rtcp_transceiver_impl_unittest.cc
+++ b/modules/rtp_rtcp/source/rtcp_transceiver_impl_unittest.cc
@@ -447,6 +447,28 @@
   EXPECT_EQ(CompactNtpRttToMs(report_blocks[1].delay_since_last_sr()), 100);
 }
 
+TEST(RtcpTransceiverImplTest, SendsNack) {
+  const uint32_t kSenderSsrc = 1234;
+  const uint32_t kRemoteSsrc = 4321;
+  std::vector<uint16_t> kMissingSequenceNumbers = {34, 37, 38};
+  MockTransport outgoing_transport;
+  RtcpTransceiverConfig config;
+  config.feedback_ssrc = kSenderSsrc;
+  config.schedule_periodic_compound_packets = false;
+  config.outgoing_transport = &outgoing_transport;
+  RtcpTransceiverImpl rtcp_transceiver(config);
+  RtcpPacketParser rtcp_parser;
+  EXPECT_CALL(outgoing_transport, SendRtcp(_, _))
+      .WillOnce(Invoke(&rtcp_parser, &RtcpPacketParser::Parse));
+
+  rtcp_transceiver.SendNack(kRemoteSsrc, kMissingSequenceNumbers);
+
+  EXPECT_EQ(rtcp_parser.nack()->num_packets(), 1);
+  EXPECT_EQ(rtcp_parser.nack()->sender_ssrc(), kSenderSsrc);
+  EXPECT_EQ(rtcp_parser.nack()->media_ssrc(), kRemoteSsrc);
+  EXPECT_EQ(rtcp_parser.nack()->packet_ids(), kMissingSequenceNumbers);
+}
+
 TEST(RtcpTransceiverImplTest, RequestKeyFrameWithPictureLossIndication) {
   const uint32_t kSenderSsrc = 1234;
   const uint32_t kRemoteSsrcs[] = {4321, 5321};