Connect LossNotificationController to RtpRtcp

* LossNotificationController is the class that decides when to issue
  LossNotification RTCP messages.
* RtpRtcp handles the technicalities of producing RTCP messages.

Bug: webrtc:10336
Change-Id: I292536257a984ca85d21d9cfa38e7ff2569cbb39
Reviewed-on: https://webrtc-review.googlesource.com/c/124123
Reviewed-by: Erik Språng <sprang@webrtc.org>
Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
Commit-Queue: Elad Alon <eladalon@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#26840}
diff --git a/video/rtp_video_stream_receiver.cc b/video/rtp_video_stream_receiver.cc
index df492ff..f40df3e 100644
--- a/video/rtp_video_stream_receiver.cc
+++ b/video/rtp_video_stream_receiver.cc
@@ -15,7 +15,6 @@
 #include <vector>
 
 #include "absl/memory/memory.h"
-
 #include "media/base/media_constants.h"
 #include "modules/pacing/packet_router.h"
 #include "modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h"
@@ -143,7 +142,11 @@
 
   process_thread_->RegisterModule(rtp_rtcp_.get(), RTC_FROM_HERE);
 
-  if (config_.rtp.nack.rtp_history_ms != 0) {
+  if (webrtc::field_trial::IsEnabled("WebRTC-RtcpLossNotification")) {
+    loss_notification_controller_ =
+        absl::make_unique<LossNotificationController>(keyframe_request_sender_,
+                                                      this);
+  } else if (config_.rtp.nack.rtp_history_ms != 0) {
     nack_module_ = absl::make_unique<NackModule>(clock_, nack_sender,
                                                  keyframe_request_sender);
     process_thread_->RegisterModule(nack_module_.get(), RTC_FROM_HERE);
@@ -234,6 +237,8 @@
       ntp_estimator_.Estimate(rtp_header->header.timestamp);
 
   VCMPacket packet(payload_data, payload_size, rtp_header_with_ntp);
+  packet.generic_descriptor = generic_descriptor;
+
   if (nack_module_) {
     const bool is_keyframe =
         rtp_header->video_header().is_first_packet_in_frame &&
@@ -247,6 +252,16 @@
   }
   packet.receive_time_ms = clock_->TimeInMilliseconds();
 
+  if (loss_notification_controller_) {
+    if (is_recovered) {
+      // TODO(bugs.webrtc.org/10336): Implement support for reordering.
+      RTC_LOG(LS_WARNING)
+          << "LossNotificationController does not support reordering.";
+    } else {
+      loss_notification_controller_->OnReceivedPacket(packet);
+    }
+  }
+
   if (packet.sizeBytes == 0) {
     NotifyReceiverOfEmptyPacket(packet.seqNum);
     return 0;
@@ -277,8 +292,6 @@
     packet.dataPtr = data;
   }
 
-  packet.generic_descriptor = generic_descriptor;
-
   packet_buffer_->InsertPacket(&packet);
   return 0;
 }
@@ -364,6 +377,14 @@
   return rtp_rtcp_->RequestKeyFrame();
 }
 
+void RtpVideoStreamReceiver::SendLossNotification(
+    uint16_t last_decoded_seq_num,
+    uint16_t last_received_seq_num,
+    bool decodability_flag) {
+  rtp_rtcp_->SendLossNotification(last_decoded_seq_num, last_received_seq_num,
+                                  decodability_flag);
+}
+
 bool RtpVideoStreamReceiver::IsUlpfecEnabled() const {
   return config_.rtp.ulpfec_payload_type != -1;
 }
@@ -385,15 +406,25 @@
 void RtpVideoStreamReceiver::OnAssembledFrame(
     std::unique_ptr<video_coding::RtpFrameObject> frame) {
   RTC_DCHECK_RUN_ON(&network_tc_);
-  // Request a key frame as soon as possible.
-  bool key_frame_requested = false;
-  if (!has_received_frame_) {
-    has_received_frame_ = true;
+  RTC_DCHECK(frame);
+
+  absl::optional<RtpGenericFrameDescriptor> descriptor =
+      frame->GetGenericFrameDescriptor();
+
+  if (loss_notification_controller_ && descriptor) {
+    loss_notification_controller_->OnAssembledFrame(
+        frame->first_seq_num(), descriptor->FrameId(),
+        descriptor->Discardable().value_or(false),
+        descriptor->FrameDependenciesDiffs());
+  } else if (!has_received_frame_) {
+    // Request a key frame as soon as possible.
     if (frame->FrameType() != kVideoFrameKey) {
-      key_frame_requested = true;
       keyframe_request_sender_->RequestKeyFrame();
     }
   }
+
+  has_received_frame_ = true;
+
   if (buffered_frame_decryptor_ == nullptr) {
     reference_finder_->ManageFrame(std::move(frame));
   } else {
@@ -607,6 +638,10 @@
     nack_module_->OnReceivedPacket(seq_num, /* is_keyframe = */ false,
                                    /* is _recovered = */ false);
   }
+  if (loss_notification_controller_) {
+    RTC_LOG(LS_WARNING)
+        << "LossNotificationController does not expect empty packets.";
+  }
 }
 
 bool RtpVideoStreamReceiver::DeliverRtcp(const uint8_t* rtcp_packet,