Add simulation of robust throughput estimator to the event log analyzer

Bug: webrtc:11566
Change-Id: I873d1c1bd6682a973b3a130289390e09ef47cc37
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/177017
Commit-Queue: Björn Terelius <terelius@webrtc.org>
Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
Reviewed-by: Sebastian Jansson <srte@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#31538}
diff --git a/rtc_tools/BUILD.gn b/rtc_tools/BUILD.gn
index b8158f6..f33d96e 100644
--- a/rtc_tools/BUILD.gn
+++ b/rtc_tools/BUILD.gn
@@ -370,6 +370,7 @@
         "../rtc_base:rtc_base_approved",
         "../rtc_base:rtc_numerics",
         "../rtc_base:stringutils",
+        "../test:explicit_key_value_config",
       ]
       absl_deps = [
         "//third_party/abseil-cpp/absl/algorithm:container",
diff --git a/rtc_tools/rtc_event_log_visualizer/analyzer.cc b/rtc_tools/rtc_event_log_visualizer/analyzer.cc
index 8ca108e..6d84b1b 100644
--- a/rtc_tools/rtc_event_log_visualizer/analyzer.cc
+++ b/rtc_tools/rtc_event_log_visualizer/analyzer.cc
@@ -56,10 +56,7 @@
 #include "rtc_base/rate_statistics.h"
 #include "rtc_base/strings/string_builder.h"
 #include "rtc_tools/rtc_event_log_visualizer/log_simulation.h"
-
-#ifndef BWE_TEST_LOGGING_COMPILE_TIME_ENABLE
-#define BWE_TEST_LOGGING_COMPILE_TIME_ENABLE 0
-#endif  // BWE_TEST_LOGGING_COMPILE_TIME_ENABLE
+#include "test/explicit_key_value_config.h"
 
 namespace webrtc {
 
@@ -1212,10 +1209,13 @@
 
   TimeSeries time_series("Delay-based estimate", LineStyle::kStep,
                          PointStyle::kHighlight);
-  TimeSeries acked_time_series("Acked bitrate", LineStyle::kLine,
+  TimeSeries acked_time_series("Raw acked bitrate", LineStyle::kLine,
                                PointStyle::kHighlight);
-  TimeSeries acked_estimate_time_series(
-      "Acked bitrate estimate", LineStyle::kLine, PointStyle::kHighlight);
+  TimeSeries robust_time_series("Robust throughput estimate", LineStyle::kLine,
+                                PointStyle::kHighlight);
+  TimeSeries acked_estimate_time_series("Ackednowledged bitrate estimate",
+                                        LineStyle::kLine,
+                                        PointStyle::kHighlight);
 
   auto rtp_iterator = outgoing_rtp.begin();
   auto rtcp_iterator = incoming_rtcp.begin();
@@ -1241,20 +1241,18 @@
     return std::numeric_limits<int64_t>::max();
   };
 
-  RateStatistics acked_bitrate(250, 8000);
-#if !(BWE_TEST_LOGGING_COMPILE_TIME_ENABLE)
-  FieldTrialBasedConfig field_trial_config_;
-  // The event_log_visualizer should normally not be compiled with
-  // BWE_TEST_LOGGING_COMPILE_TIME_ENABLE since the normal plots won't work.
-  // However, compiling with BWE_TEST_LOGGING, running with --plot=sendside_bwe
-  // and piping the output to plot_dynamics.py can be used as a hack to get the
-  // internal state of various BWE components. In this case, it is important
-  // we don't instantiate the AcknowledgedBitrateEstimator both here and in
-  // GoogCcNetworkController since that would lead to duplicate outputs.
+  RateStatistics acked_bitrate(750, 8000);
+  test::ExplicitKeyValueConfig throughput_config(
+      "WebRTC-Bwe-RobustThroughputEstimatorSettings/"
+      "enabled:true,reduce_bias:true,assume_shared_link:false,initial_packets:"
+      "10,min_packets:25,window_duration:750ms,unacked_weight:0.5/");
+  std::unique_ptr<AcknowledgedBitrateEstimatorInterface>
+      robust_throughput_estimator(
+          AcknowledgedBitrateEstimatorInterface::Create(&throughput_config));
+  FieldTrialBasedConfig field_trial_config;
   std::unique_ptr<AcknowledgedBitrateEstimatorInterface>
       acknowledged_bitrate_estimator(
-          AcknowledgedBitrateEstimatorInterface::Create(&field_trial_config_));
-#endif  // !(BWE_TEST_LOGGING_COMPILE_TIME_ENABLE)
+          AcknowledgedBitrateEstimatorInterface::Create(&field_trial_config));
   int64_t time_us =
       std::min({NextRtpTime(), NextRtcpTime(), NextProcessTime()});
   int64_t last_update_us = 0;
@@ -1264,24 +1262,40 @@
       RTC_DCHECK_EQ(clock.TimeInMicroseconds(), NextRtpTime());
       const RtpPacketType& rtp_packet = *rtp_iterator->second;
       if (rtp_packet.rtp.header.extension.hasTransportSequenceNumber) {
-        RTC_DCHECK(rtp_packet.rtp.header.extension.hasTransportSequenceNumber);
         RtpPacketSendInfo packet_info;
         packet_info.ssrc = rtp_packet.rtp.header.ssrc;
         packet_info.transport_sequence_number =
             rtp_packet.rtp.header.extension.transportSequenceNumber;
         packet_info.rtp_sequence_number = rtp_packet.rtp.header.sequenceNumber;
         packet_info.length = rtp_packet.rtp.total_length;
+        if (IsRtxSsrc(parsed_log_, PacketDirection::kOutgoingPacket,
+                      rtp_packet.rtp.header.ssrc)) {
+          // Don't set the optional media type as we don't know if it is
+          // a retransmission, FEC or padding.
+        } else if (IsVideoSsrc(parsed_log_, PacketDirection::kOutgoingPacket,
+                               rtp_packet.rtp.header.ssrc)) {
+          packet_info.packet_type = RtpPacketMediaType::kVideo;
+        } else if (IsAudioSsrc(parsed_log_, PacketDirection::kOutgoingPacket,
+                               rtp_packet.rtp.header.ssrc)) {
+          packet_info.packet_type = RtpPacketMediaType::kAudio;
+        }
         transport_feedback.AddPacket(
             packet_info,
             0u,  // Per packet overhead bytes.
             Timestamp::Micros(rtp_packet.rtp.log_time_us()));
-        rtc::SentPacket sent_packet(
-            rtp_packet.rtp.header.extension.transportSequenceNumber,
-            rtp_packet.rtp.log_time_us() / 1000);
-        auto sent_msg = transport_feedback.ProcessSentPacket(sent_packet);
-        if (sent_msg)
-          observer.Update(goog_cc->OnSentPacket(*sent_msg));
       }
+      rtc::SentPacket sent_packet;
+      sent_packet.send_time_ms = rtp_packet.rtp.log_time_ms();
+      sent_packet.info.included_in_allocation = true;
+      sent_packet.info.packet_size_bytes = rtp_packet.rtp.total_length;
+      if (rtp_packet.rtp.header.extension.hasTransportSequenceNumber) {
+        sent_packet.packet_id =
+            rtp_packet.rtp.header.extension.transportSequenceNumber;
+        sent_packet.info.included_in_feedback = true;
+      }
+      auto sent_msg = transport_feedback.ProcessSentPacket(sent_packet);
+      if (sent_msg)
+        observer.Update(goog_cc->OnSentPacket(*sent_msg));
       ++rtp_iterator;
     }
     if (clock.TimeInMicroseconds() >= NextRtcpTime()) {
@@ -1296,13 +1310,13 @@
         std::vector<PacketResult> feedback =
             feedback_msg->SortedByReceiveTime();
         if (!feedback.empty()) {
-#if !(BWE_TEST_LOGGING_COMPILE_TIME_ENABLE)
           acknowledged_bitrate_estimator->IncomingPacketFeedbackVector(
               feedback);
-#endif  // !(BWE_TEST_LOGGING_COMPILE_TIME_ENABLE)
-          for (const PacketResult& packet : feedback)
+          robust_throughput_estimator->IncomingPacketFeedbackVector(feedback);
+          for (const PacketResult& packet : feedback) {
             acked_bitrate.Update(packet.sent_packet.size.bytes(),
                                  packet.receive_time.ms());
+          }
           bitrate_bps = acked_bitrate.Rate(feedback.back().receive_time.ms());
         }
       }
@@ -1310,12 +1324,14 @@
       float x = config_.GetCallTimeSec(clock.TimeInMicroseconds());
       float y = bitrate_bps.value_or(0) / 1000;
       acked_time_series.points.emplace_back(x, y);
-#if !(BWE_TEST_LOGGING_COMPILE_TIME_ENABLE)
+      y = robust_throughput_estimator->bitrate()
+              .value_or(DataRate::Zero())
+              .kbps();
+      robust_time_series.points.emplace_back(x, y);
       y = acknowledged_bitrate_estimator->bitrate()
               .value_or(DataRate::Zero())
               .kbps();
       acked_estimate_time_series.points.emplace_back(x, y);
-#endif  // !(BWE_TEST_LOGGING_COMPILE_TIME_ENABLE)
       ++rtcp_iterator;
     }
     if (clock.TimeInMicroseconds() >= NextProcessTime()) {
@@ -1336,6 +1352,7 @@
   }
   // Add the data set to the plot.
   plot->AppendTimeSeries(std::move(time_series));
+  plot->AppendTimeSeries(std::move(robust_time_series));
   plot->AppendTimeSeries(std::move(acked_time_series));
   plot->AppendTimeSeriesIfNotEmpty(std::move(acked_estimate_time_series));
 
diff --git a/test/BUILD.gn b/test/BUILD.gn
index 974848b..9215b67 100644
--- a/test/BUILD.gn
+++ b/test/BUILD.gn
@@ -216,6 +216,20 @@
   deps = [ "../system_wrappers:field_trial" ]
 }
 
+rtc_library("explicit_key_value_config") {
+  sources = [
+    "explicit_key_value_config.cc",
+    "explicit_key_value_config.h",
+  ]
+
+  deps = [
+    "../api/transport:webrtc_key_value_config",
+    "../rtc_base:checks",
+    "../system_wrappers:field_trial",
+  ]
+  absl_deps = [ "//third_party/abseil-cpp/absl/strings:strings" ]
+}
+
 rtc_library("perf_test") {
   visibility = [ "*" ]
   testonly = true
diff --git a/test/explicit_key_value_config.cc b/test/explicit_key_value_config.cc
new file mode 100644
index 0000000..69f725a
--- /dev/null
+++ b/test/explicit_key_value_config.cc
@@ -0,0 +1,57 @@
+/*
+ *  Copyright (c) 2020 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "test/explicit_key_value_config.h"
+
+#include "api/transport/webrtc_key_value_config.h"
+#include "rtc_base/checks.h"
+#include "system_wrappers/include/field_trial.h"
+
+namespace webrtc {
+namespace test {
+
+ExplicitKeyValueConfig::ExplicitKeyValueConfig(const std::string& s) {
+  std::string::size_type field_start = 0;
+  while (field_start < s.size()) {
+    std::string::size_type separator_pos = s.find('/', field_start);
+    RTC_CHECK_NE(separator_pos, std::string::npos)
+        << "Missing separator '/' after field trial key.";
+    RTC_CHECK_GT(separator_pos, field_start)
+        << "Field trial key cannot be empty.";
+    std::string key = s.substr(field_start, separator_pos - field_start);
+    field_start = separator_pos + 1;
+
+    RTC_CHECK_LT(field_start, s.size())
+        << "Missing value after field trial key. String ended.";
+    separator_pos = s.find('/', field_start);
+    RTC_CHECK_NE(separator_pos, std::string::npos)
+        << "Missing terminating '/' in field trial string.";
+    RTC_CHECK_GT(separator_pos, field_start)
+        << "Field trial value cannot be empty.";
+    std::string value = s.substr(field_start, separator_pos - field_start);
+    field_start = separator_pos + 1;
+
+    key_value_map_[key] = value;
+  }
+  // This check is technically redundant due to earlier checks.
+  // We nevertheless keep the check to make it clear that the entire
+  // string has been processed, and without indexing past the end.
+  RTC_CHECK_EQ(field_start, s.size());
+}
+
+std::string ExplicitKeyValueConfig::Lookup(absl::string_view key) const {
+  auto it = key_value_map_.find(std::string(key));
+  if (it != key_value_map_.end())
+    return it->second;
+  return "";
+}
+
+}  // namespace test
+}  // namespace webrtc
diff --git a/test/explicit_key_value_config.h b/test/explicit_key_value_config.h
new file mode 100644
index 0000000..9a3bc84
--- /dev/null
+++ b/test/explicit_key_value_config.h
@@ -0,0 +1,35 @@
+/*
+ *  Copyright (c) 2020 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef TEST_EXPLICIT_KEY_VALUE_CONFIG_H_
+#define TEST_EXPLICIT_KEY_VALUE_CONFIG_H_
+
+#include <map>
+#include <string>
+
+#include "absl/strings/string_view.h"
+#include "api/transport/webrtc_key_value_config.h"
+
+namespace webrtc {
+namespace test {
+
+class ExplicitKeyValueConfig : public WebRtcKeyValueConfig {
+ public:
+  explicit ExplicitKeyValueConfig(const std::string& s);
+  std::string Lookup(absl::string_view key) const override;
+
+ private:
+  std::map<std::string, std::string> key_value_map_;
+};
+
+}  // namespace test
+}  // namespace webrtc
+
+#endif  // TEST_EXPLICIT_KEY_VALUE_CONFIG_H_