Plot bitrate allocation per layer based on RTCP XR target bitrate.

Bug: webrtc:10312
Change-Id: Ic0221e71d27d1fdc35c50a93e7e2303953c4fbf5
Reviewed-on: https://webrtc-review.googlesource.com/c/123222
Reviewed-by: Mirta Dvornicic <mirtad@webrtc.org>
Commit-Queue: Björn Terelius <terelius@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#26717}
diff --git a/rtc_tools/event_log_visualizer/analyzer.cc b/rtc_tools/event_log_visualizer/analyzer.cc
index 1b52c30..a4126bc 100644
--- a/rtc_tools/event_log_visualizer/analyzer.cc
+++ b/rtc_tools/event_log_visualizer/analyzer.cc
@@ -1115,6 +1115,46 @@
   plot->SetTitle(GetDirectionAsString(direction) + " bitrate per stream");
 }
 
+// Plot the bitrate allocation for each temporal and spatial layer.
+// Computed from RTCP XR target bitrate block, so the graph is only populated if
+// those are sent.
+void EventLogAnalyzer::CreateBitrateAllocationGraph(PacketDirection direction,
+                                                    Plot* plot) {
+  std::map<LayerDescription, TimeSeries> time_series;
+  const auto& xr_list = parsed_log_.extended_reports(direction);
+  for (const auto& rtcp : xr_list) {
+    const absl::optional<rtcp::TargetBitrate>& target_bitrate =
+        rtcp.xr.target_bitrate();
+    if (!target_bitrate.has_value())
+      continue;
+    for (const auto& bitrate_item : target_bitrate->GetTargetBitrates()) {
+      LayerDescription layer(rtcp.xr.sender_ssrc(), bitrate_item.spatial_layer,
+                             bitrate_item.temporal_layer);
+      auto time_series_it = time_series.find(layer);
+      if (time_series_it == time_series.end()) {
+        std::string layer_name = GetLayerName(layer);
+        bool inserted;
+        std::tie(time_series_it, inserted) = time_series.insert(
+            std::make_pair(layer, TimeSeries(layer_name, LineStyle::kStep)));
+        RTC_DCHECK(inserted);
+      }
+      float x = config_.GetCallTimeSec(rtcp.log_time_us());
+      float y = bitrate_item.target_bitrate_kbps;
+      time_series_it->second.points.emplace_back(x, y);
+    }
+  }
+  for (auto& layer : time_series) {
+    plot->AppendTimeSeries(std::move(layer.second));
+  }
+  plot->SetXAxis(config_.CallBeginTimeSec(), config_.CallEndTimeSec(),
+                 "Time (s)", kLeftMargin, kRightMargin);
+  plot->SetSuggestedYAxis(0, 1, "Bitrate (kbps)", kBottomMargin, kTopMargin);
+  if (direction == kIncomingPacket)
+    plot->SetTitle("Target bitrate per incoming layer");
+  else
+    plot->SetTitle("Target bitrate per outgoing layer");
+}
+
 void EventLogAnalyzer::CreateSendSideBweSimulationGraph(Plot* plot) {
   using RtpPacketType = LoggedRtpPacketOutgoing;
   using TransportFeedbackType = LoggedRtcpPacketTransportFeedback;
diff --git a/rtc_tools/event_log_visualizer/analyzer.h b/rtc_tools/event_log_visualizer/analyzer.h
index f8dd3de..e0ef0c3 100644
--- a/rtc_tools/event_log_visualizer/analyzer.h
+++ b/rtc_tools/event_log_visualizer/analyzer.h
@@ -81,6 +81,7 @@
                                        bool show_alr_state = false);
 
   void CreateStreamBitrateGraph(PacketDirection direction, Plot* plot);
+  void CreateBitrateAllocationGraph(PacketDirection direction, Plot* plot);
 
   void CreateSendSideBweSimulationGraph(Plot* plot);
   void CreateReceiveSideBweSimulationGraph(Plot* plot);
@@ -132,6 +133,25 @@
   void PrintNotifications(FILE* file);
 
  private:
+  struct LayerDescription {
+    LayerDescription(uint32_t ssrc,
+                     uint8_t spatial_layer,
+                     uint8_t temporal_layer)
+        : ssrc(ssrc),
+          spatial_layer(spatial_layer),
+          temporal_layer(temporal_layer) {}
+    bool operator<(const LayerDescription& other) const {
+      if (ssrc != other.ssrc)
+        return ssrc < other.ssrc;
+      if (spatial_layer != other.spatial_layer)
+        return spatial_layer < other.spatial_layer;
+      return temporal_layer < other.temporal_layer;
+    }
+    uint32_t ssrc;
+    uint8_t spatial_layer;
+    uint8_t temporal_layer;
+  };
+
   bool IsRtxSsrc(PacketDirection direction, uint32_t ssrc) const {
     if (direction == kIncomingPacket) {
       return parsed_log_.incoming_rtx_ssrcs().find(ssrc) !=
@@ -200,6 +220,14 @@
     return name.str();
   }
 
+  std::string GetLayerName(LayerDescription layer) const {
+    char buffer[100];
+    rtc::SimpleStringBuilder name(buffer);
+    name << "SSRC " << layer.ssrc << " sl " << layer.spatial_layer << ", tl "
+         << layer.temporal_layer;
+    return name.str();
+  }
+
   void Alert_RtpLogTimeGap(PacketDirection direction,
                            float time_seconds,
                            int64_t duration) {
diff --git a/rtc_tools/event_log_visualizer/main.cc b/rtc_tools/event_log_visualizer/main.cc
index c08b71b..11824da 100644
--- a/rtc_tools/event_log_visualizer/main.cc
+++ b/rtc_tools/event_log_visualizer/main.cc
@@ -94,6 +94,14 @@
 WEBRTC_DEFINE_bool(plot_outgoing_stream_bitrate,
                    true,
                    "Plot the bitrate used by each outgoing stream.");
+WEBRTC_DEFINE_bool(plot_incoming_layer_bitrate_allocation,
+                   false,
+                   "Plot the target bitrate for each incoming layer. Requires "
+                   "incoming RTCP XR with target bitrate to be populated.");
+WEBRTC_DEFINE_bool(plot_outgoing_layer_bitrate_allocation,
+                   false,
+                   "Plot the target bitrate for each outgoing layer. Requires "
+                   "outgoing RTCP XR with target bitrate to be populated.");
 WEBRTC_DEFINE_bool(
     plot_simulated_receiveside_bwe,
     false,
@@ -343,6 +351,14 @@
     analyzer.CreateStreamBitrateGraph(webrtc::kOutgoingPacket,
                                       collection->AppendNewPlot());
   }
+  if (FLAG_plot_incoming_layer_bitrate_allocation) {
+    analyzer.CreateBitrateAllocationGraph(webrtc::kIncomingPacket,
+                                          collection->AppendNewPlot());
+  }
+  if (FLAG_plot_outgoing_layer_bitrate_allocation) {
+    analyzer.CreateBitrateAllocationGraph(webrtc::kOutgoingPacket,
+                                          collection->AppendNewPlot());
+  }
   if (FLAG_plot_simulated_receiveside_bwe) {
     analyzer.CreateReceiveSideBweSimulationGraph(collection->AppendNewPlot());
   }
@@ -522,6 +538,8 @@
   FLAG_plot_outgoing_bitrate = setting;
   FLAG_plot_incoming_stream_bitrate = setting;
   FLAG_plot_outgoing_stream_bitrate = setting;
+  FLAG_plot_incoming_layer_bitrate_allocation = setting;
+  FLAG_plot_outgoing_layer_bitrate_allocation = setting;
   FLAG_plot_simulated_receiveside_bwe = setting;
   FLAG_plot_simulated_sendside_bwe = setting;
   FLAG_plot_network_delay_feedback = setting;