Plot RTCP SR and RR contents in event_log_visualizer.

Plot the contents of all report blocks in all sender and receiver reports.
This includes fraction lost, cumulative number of lost packets, extended
highest sequence number and time since last received SR.

Bug: None
Change-Id: Ifbded689a666da140c468e11c33b6c6f99a3041e
Reviewed-on: https://webrtc-review.googlesource.com/90247
Reviewed-by: Alex Narest <alexnarest@webrtc.org>
Commit-Queue: Björn Terelius <terelius@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#24083}
diff --git a/rtc_tools/event_log_visualizer/analyzer.cc b/rtc_tools/event_log_visualizer/analyzer.cc
index 7555845..4ddd68c 100644
--- a/rtc_tools/event_log_visualizer/analyzer.cc
+++ b/rtc_tools/event_log_visualizer/analyzer.cc
@@ -1458,6 +1458,61 @@
   plot->SetTitle(GetDirectionAsString(direction) + " timestamps");
 }
 
+void EventLogAnalyzer::CreateSenderAndReceiverReportPlot(
+    PacketDirection direction,
+    rtc::FunctionView<float(const rtcp::ReportBlock&)> fy,
+    std::string title,
+    std::string yaxis_label,
+    Plot* plot) {
+  std::map<uint32_t, TimeSeries> sr_reports_by_ssrc;
+  const auto& sender_reports = parsed_log_.sender_reports(direction);
+  for (const auto& rtcp : sender_reports) {
+    float x = ToCallTimeSec(rtcp.log_time_us());
+    uint32_t ssrc = rtcp.sr.sender_ssrc();
+    for (const auto& block : rtcp.sr.report_blocks()) {
+      float y = fy(block);
+      auto sr_report_it = sr_reports_by_ssrc.find(ssrc);
+      bool inserted;
+      if (sr_report_it == sr_reports_by_ssrc.end()) {
+        std::tie(sr_report_it, inserted) = sr_reports_by_ssrc.emplace(
+            ssrc, TimeSeries(GetStreamName(direction, ssrc) + " Sender Reports",
+                             LineStyle::kLine, PointStyle::kHighlight));
+      }
+      sr_report_it->second.points.emplace_back(x, y);
+    }
+  }
+  for (auto& kv : sr_reports_by_ssrc) {
+    plot->AppendTimeSeries(std::move(kv.second));
+  }
+
+  std::map<uint32_t, TimeSeries> rr_reports_by_ssrc;
+  const auto& receiver_reports = parsed_log_.receiver_reports(direction);
+  for (const auto& rtcp : receiver_reports) {
+    float x = ToCallTimeSec(rtcp.log_time_us());
+    uint32_t ssrc = rtcp.rr.sender_ssrc();
+    for (const auto& block : rtcp.rr.report_blocks()) {
+      float y = fy(block);
+      auto rr_report_it = rr_reports_by_ssrc.find(ssrc);
+      bool inserted;
+      if (rr_report_it == rr_reports_by_ssrc.end()) {
+        std::tie(rr_report_it, inserted) = rr_reports_by_ssrc.emplace(
+            ssrc,
+            TimeSeries(GetStreamName(direction, ssrc) + " Receiver Reports",
+                       LineStyle::kLine, PointStyle::kHighlight));
+      }
+      rr_report_it->second.points.emplace_back(x, y);
+    }
+  }
+  for (auto& kv : rr_reports_by_ssrc) {
+    plot->AppendTimeSeries(std::move(kv.second));
+  }
+
+  plot->SetXAxis(ToCallTimeSec(begin_time_), call_duration_s_, "Time (s)",
+                 kLeftMargin, kRightMargin);
+  plot->SetSuggestedYAxis(0, 1, yaxis_label, kBottomMargin, kTopMargin);
+  plot->SetTitle(title);
+}
+
 void EventLogAnalyzer::CreateAudioEncoderTargetBitrateGraph(Plot* plot) {
   TimeSeries time_series("Audio encoder target bitrate", LineStyle::kLine,
                          PointStyle::kHighlight);
diff --git a/rtc_tools/event_log_visualizer/analyzer.h b/rtc_tools/event_log_visualizer/analyzer.h
index 22101b6..4b8c27c 100644
--- a/rtc_tools/event_log_visualizer/analyzer.h
+++ b/rtc_tools/event_log_visualizer/analyzer.h
@@ -64,6 +64,12 @@
   void CreatePacerDelayGraph(Plot* plot);
 
   void CreateTimestampGraph(PacketDirection direction, Plot* plot);
+  void CreateSenderAndReceiverReportPlot(
+      PacketDirection direction,
+      rtc::FunctionView<float(const rtcp::ReportBlock&)> fy,
+      std::string title,
+      std::string yaxis_label,
+      Plot* plot);
 
   void CreateAudioEncoderTargetBitrateGraph(Plot* plot);
   void CreateAudioEncoderFrameLengthGraph(Plot* plot);
diff --git a/rtc_tools/event_log_visualizer/main.cc b/rtc_tools/event_log_visualizer/main.cc
index b1fc0d2..fb497db 100644
--- a/rtc_tools/event_log_visualizer/main.cc
+++ b/rtc_tools/event_log_visualizer/main.cc
@@ -97,6 +97,12 @@
 DEFINE_bool(plot_timestamps,
             false,
             "Plot the rtp timestamps of all rtp and rtcp packets over time.");
+DEFINE_bool(plot_rtcp_details,
+            false,
+            "Plot the contents of all report blocks in all sender and receiver "
+            "reports. This includes fraction lost, cumulative number of lost "
+            "packets, extended highest sequence number and time since last "
+            "received SR.");
 DEFINE_bool(plot_audio_encoder_bitrate_bps,
             false,
             "Plot the audio encoder target bitrate.");
@@ -305,6 +311,59 @@
     analyzer.CreateTimestampGraph(webrtc::kOutgoingPacket,
                                   collection->AppendNewPlot());
   }
+  if (FLAG_plot_rtcp_details) {
+    auto GetFractionLost = [](const webrtc::rtcp::ReportBlock& block) -> float {
+      return static_cast<double>(block.fraction_lost()) / 256 * 100;
+    };
+    analyzer.CreateSenderAndReceiverReportPlot(
+        webrtc::kIncomingPacket, GetFractionLost,
+        "Fraction lost (incoming RTCP)", "Loss rate (percent)",
+        collection->AppendNewPlot());
+    analyzer.CreateSenderAndReceiverReportPlot(
+        webrtc::kOutgoingPacket, GetFractionLost,
+        "Fraction lost (outgoing RTCP)", "Loss rate (percent)",
+        collection->AppendNewPlot());
+
+    auto GetCumulativeLost =
+        [](const webrtc::rtcp::ReportBlock& block) -> float {
+      return block.cumulative_lost_signed();
+    };
+    analyzer.CreateSenderAndReceiverReportPlot(
+        webrtc::kIncomingPacket, GetCumulativeLost,
+        "Cumulative lost packets (incoming RTCP)", "Packets",
+        collection->AppendNewPlot());
+    analyzer.CreateSenderAndReceiverReportPlot(
+        webrtc::kOutgoingPacket, GetCumulativeLost,
+        "Cumulative lost packets (outgoing RTCP)", "Packets",
+        collection->AppendNewPlot());
+
+    auto GetHighestSeqNumber =
+        [](const webrtc::rtcp::ReportBlock& block) -> float {
+      return block.extended_high_seq_num();
+    };
+    analyzer.CreateSenderAndReceiverReportPlot(
+        webrtc::kIncomingPacket, GetHighestSeqNumber,
+        "Highest sequence number (incoming RTCP)", "Seqence number",
+        collection->AppendNewPlot());
+    analyzer.CreateSenderAndReceiverReportPlot(
+        webrtc::kOutgoingPacket, GetHighestSeqNumber,
+        "Highest sequence number (outgoing RTCP)", "Seqence number",
+        collection->AppendNewPlot());
+
+    auto DelaySinceLastSr =
+        [](const webrtc::rtcp::ReportBlock& block) -> float {
+      return static_cast<double>(block.delay_since_last_sr()) / 65536;
+    };
+    analyzer.CreateSenderAndReceiverReportPlot(
+        webrtc::kIncomingPacket, DelaySinceLastSr,
+        "Delay since last received sender report (incoming RTCP)", "Time (s)",
+        collection->AppendNewPlot());
+    analyzer.CreateSenderAndReceiverReportPlot(
+        webrtc::kOutgoingPacket, DelaySinceLastSr,
+        "Delay since last received sender report (outgoing RTCP)", "Time (s)",
+        collection->AppendNewPlot());
+  }
+
   if (FLAG_plot_pacer_delay) {
     analyzer.CreatePacerDelayGraph(collection->AppendNewPlot());
   }
@@ -410,6 +469,7 @@
   FLAG_plot_network_delay_feedback = setting;
   FLAG_plot_fraction_loss_feedback = setting;
   FLAG_plot_timestamps = setting;
+  FLAG_plot_rtcp_details = setting;
   FLAG_plot_audio_encoder_bitrate_bps = setting;
   FLAG_plot_audio_encoder_frame_length_ms = setting;
   FLAG_plot_audio_encoder_packet_loss = setting;