Allow passing an event log as string to NetEqSimulator.

Previously only reading from the filesystem was supported, this CL
allows parsing an event log from a string.

Bug: webrtc:10337
Change-Id: Iadde3319eb8fb4175625f510201fac9c01c80ed9
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/127296
Commit-Queue: Ivo Creusen <ivoc@webrtc.org>
Reviewed-by: Minyue Li <minyue@webrtc.org>
Reviewed-by: Karl Wiberg <kwiberg@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#27202}
diff --git a/api/BUILD.gn b/api/BUILD.gn
index 5d02637..c1a7275 100644
--- a/api/BUILD.gn
+++ b/api/BUILD.gn
@@ -421,6 +421,7 @@
         "../rtc_base:checks",
         "../rtc_base:rtc_base_approved",
         "//third_party/abseil-cpp/absl/memory",
+        "//third_party/abseil-cpp/absl/strings",
       ]
     }
   }
diff --git a/api/test/neteq_simulator_factory.cc b/api/test/neteq_simulator_factory.cc
index 6580d1d..64e9c5b 100644
--- a/api/test/neteq_simulator_factory.cc
+++ b/api/test/neteq_simulator_factory.cc
@@ -50,7 +50,30 @@
   config.replacement_audio_file = FLAG_replacement_audio_file;
   config.max_nr_packets_in_buffer = FLAG_max_nr_packets_in_buffer;
   config.output_audio_filename = output_audio_filename;
-  return factory_->InitializeTest(argv[1], config);
+  return factory_->InitializeTestFromFile(argv[1], config);
+}
+
+std::unique_ptr<NetEqSimulator> NetEqSimulatorFactory::CreateSimulatorFromFile(
+    absl::string_view event_log_filename,
+    absl::string_view replacement_audio_filename,
+    Config simulation_config) {
+  NetEqTestFactory::Config config;
+  config.replacement_audio_file = std::string(replacement_audio_filename);
+  config.max_nr_packets_in_buffer = simulation_config.max_nr_packets_in_buffer;
+  return factory_->InitializeTestFromFile(std::string(event_log_filename),
+                                          config);
+}
+
+std::unique_ptr<NetEqSimulator>
+NetEqSimulatorFactory::CreateSimulatorFromString(
+    absl::string_view event_log_file_contents,
+    absl::string_view replacement_audio_filename,
+    Config simulation_config) {
+  NetEqTestFactory::Config config;
+  config.replacement_audio_file = std::string(replacement_audio_filename);
+  config.max_nr_packets_in_buffer = simulation_config.max_nr_packets_in_buffer;
+  return factory_->InitializeTestFromString(
+      std::string(event_log_file_contents), config);
 }
 
 }  // namespace test
diff --git a/api/test/neteq_simulator_factory.h b/api/test/neteq_simulator_factory.h
index e37ff55..245162f 100644
--- a/api/test/neteq_simulator_factory.h
+++ b/api/test/neteq_simulator_factory.h
@@ -12,7 +12,9 @@
 #define API_TEST_NETEQ_SIMULATOR_FACTORY_H_
 
 #include <memory>
+#include <string>
 
+#include "absl/strings/string_view.h"
 #include "api/test/neteq_simulator.h"
 
 namespace webrtc {
@@ -24,8 +26,20 @@
  public:
   NetEqSimulatorFactory();
   ~NetEqSimulatorFactory();
+  struct Config {
+    int max_nr_packets_in_buffer = 0;
+  };
   // This function takes the same arguments as the neteq_rtpplay utility.
   std::unique_ptr<NetEqSimulator> CreateSimulator(int argc, char* argv[]);
+  std::unique_ptr<NetEqSimulator> CreateSimulatorFromFile(
+      absl::string_view event_log_filename,
+      absl::string_view replacement_audio_filename,
+      Config simulation_config);
+  // The same as above, but pass the file contents as a string.
+  std::unique_ptr<NetEqSimulator> CreateSimulatorFromString(
+      absl::string_view event_log_file_contents,
+      absl::string_view replacement_audio_file,
+      Config simulation_config);
 
  private:
   std::unique_ptr<NetEqTestFactory> factory_;
diff --git a/modules/audio_coding/neteq/tools/neteq_event_log_input.cc b/modules/audio_coding/neteq/tools/neteq_event_log_input.cc
index 9107e5e..60fd897 100644
--- a/modules/audio_coding/neteq/tools/neteq_event_log_input.cc
+++ b/modules/audio_coding/neteq/tools/neteq_event_log_input.cc
@@ -11,6 +11,7 @@
 #include "modules/audio_coding/neteq/tools/neteq_event_log_input.h"
 
 #include <limits>
+#include <memory>
 
 #include "modules/audio_coding/neteq/tools/rtc_event_log_source.h"
 #include "rtc_base/checks.h"
@@ -18,11 +19,18 @@
 namespace webrtc {
 namespace test {
 
-NetEqEventLogInput::NetEqEventLogInput(const std::string& file_name,
-                                       absl::optional<uint32_t> ssrc_filter)
-    : source_(RtcEventLogSource::Create(file_name, ssrc_filter)) {
-  LoadNextPacket();
-  AdvanceOutputEvent();
+NetEqEventLogInput* NetEqEventLogInput::CreateFromFile(
+    const std::string& file_name,
+    absl::optional<uint32_t> ssrc_filter) {
+  return new NetEqEventLogInput(
+      RtcEventLogSource::CreateFromFile(file_name, ssrc_filter));
+}
+
+NetEqEventLogInput* NetEqEventLogInput::CreateFromString(
+    const std::string& file_contents,
+    absl::optional<uint32_t> ssrc_filter) {
+  return new NetEqEventLogInput(
+      RtcEventLogSource::CreateFromString(file_contents, ssrc_filter));
 }
 
 absl::optional<int64_t> NetEqEventLogInput::NextOutputEventTime() const {
@@ -40,5 +48,12 @@
   return source_.get();
 }
 
+NetEqEventLogInput::NetEqEventLogInput(
+    std::unique_ptr<RtcEventLogSource> source)
+    : source_(std::move(source)) {
+  LoadNextPacket();
+  AdvanceOutputEvent();
+}
+
 }  // namespace test
 }  // namespace webrtc
diff --git a/modules/audio_coding/neteq/tools/neteq_event_log_input.h b/modules/audio_coding/neteq/tools/neteq_event_log_input.h
index e04df16..238946a 100644
--- a/modules/audio_coding/neteq/tools/neteq_event_log_input.h
+++ b/modules/audio_coding/neteq/tools/neteq_event_log_input.h
@@ -27,8 +27,12 @@
 // RtcEventLogSource.
 class NetEqEventLogInput final : public NetEqPacketSourceInput {
  public:
-  NetEqEventLogInput(const std::string& file_name,
-                     absl::optional<uint32_t> ssrc_filter);
+  static NetEqEventLogInput* CreateFromFile(
+      const std::string& file_name,
+      absl::optional<uint32_t> ssrc_filter);
+  static NetEqEventLogInput* CreateFromString(
+      const std::string& file_contents,
+      absl::optional<uint32_t> ssrc_filter);
 
   absl::optional<int64_t> NextOutputEventTime() const override;
   void AdvanceOutputEvent() override;
@@ -37,6 +41,7 @@
   PacketSource* source() override;
 
  private:
+  NetEqEventLogInput(std::unique_ptr<RtcEventLogSource> source);
   std::unique_ptr<RtcEventLogSource> source_;
 };
 
diff --git a/modules/audio_coding/neteq/tools/neteq_rtpplay.cc b/modules/audio_coding/neteq/tools/neteq_rtpplay.cc
index 7ebc326..1d313f5 100644
--- a/modules/audio_coding/neteq/tools/neteq_rtpplay.cc
+++ b/modules/audio_coding/neteq/tools/neteq_rtpplay.cc
@@ -377,8 +377,8 @@
     config.ssrc_filter = absl::make_optional(ssrc);
   }
 
-  std::unique_ptr<webrtc::test::NetEqTest> test = factory.InitializeTest(
-      /*input_filename=*/argv[1], config);
+  std::unique_ptr<webrtc::test::NetEqTest> test =
+      factory.InitializeTestFromFile(/*input_filename=*/argv[1], config);
   test->Run();
   return 0;
 }
diff --git a/modules/audio_coding/neteq/tools/neteq_test_factory.cc b/modules/audio_coding/neteq/tools/neteq_test_factory.cc
index f352e3a..832d678 100644
--- a/modules/audio_coding/neteq/tools/neteq_test_factory.cc
+++ b/modules/audio_coding/neteq/tools/neteq_test_factory.cc
@@ -108,8 +108,17 @@
 NetEqTestFactory::Config::Config(const Config& other) = default;
 NetEqTestFactory::Config::~Config() = default;
 
-std::unique_ptr<NetEqTest> NetEqTestFactory::InitializeTest(
-    std::string input_file_name,
+std::unique_ptr<NetEqTest> NetEqTestFactory::InitializeTestFromString(
+    const std::string& input_string,
+    const Config& config) {
+  std::unique_ptr<NetEqInput> input(
+      NetEqEventLogInput::CreateFromString(input_string, config.ssrc_filter));
+  RTC_CHECK(input) << "Cannot parse input string";
+  return InitializeTest(std::move(input), config);
+}
+
+std::unique_ptr<NetEqTest> NetEqTestFactory::InitializeTestFromFile(
+    const std::string& input_file_name,
     const Config& config) {
   // Gather RTP header extensions in a map.
   NetEqPacketSourceInput::RtpHeaderExtensionMap rtp_ext_map = {
@@ -125,12 +134,19 @@
     input.reset(new NetEqRtpDumpInput(input_file_name, rtp_ext_map,
                                       config.ssrc_filter));
   } else {
-    input.reset(new NetEqEventLogInput(input_file_name, config.ssrc_filter));
+    input.reset(NetEqEventLogInput::CreateFromFile(input_file_name,
+                                                   config.ssrc_filter));
   }
 
   std::cout << "Input file: " << input_file_name << std::endl;
   RTC_CHECK(input) << "Cannot open input file";
-  RTC_CHECK(!input->ended()) << "Input file is empty";
+  return InitializeTest(std::move(input), config);
+}
+
+std::unique_ptr<NetEqTest> NetEqTestFactory::InitializeTest(
+    std::unique_ptr<NetEqInput> input,
+    const Config& config) {
+  RTC_CHECK(!input->ended()) << "Input is empty";
 
   // Check the sample rate.
   absl::optional<int> sample_rate_hz;
diff --git a/modules/audio_coding/neteq/tools/neteq_test_factory.h b/modules/audio_coding/neteq/tools/neteq_test_factory.h
index 4da5d55..34b7c77 100644
--- a/modules/audio_coding/neteq/tools/neteq_test_factory.h
+++ b/modules/audio_coding/neteq/tools/neteq_test_factory.h
@@ -133,10 +133,16 @@
     absl::optional<std::string> output_audio_filename;
   };
 
-  std::unique_ptr<NetEqTest> InitializeTest(std::string input_filename,
-                                            const Config& config);
+  std::unique_ptr<NetEqTest> InitializeTestFromFile(
+      const std::string& input_filename,
+      const Config& config);
+  std::unique_ptr<NetEqTest> InitializeTestFromString(
+      const std::string& input_string,
+      const Config& config);
 
  private:
+  std::unique_ptr<NetEqTest> InitializeTest(std::unique_ptr<NetEqInput> input,
+                                            const Config& config);
   std::unique_ptr<SsrcSwitchDetector> ssrc_switch_detector_;
   std::unique_ptr<NetEqStatsPlotter> stats_plotter_;
 };
diff --git a/modules/audio_coding/neteq/tools/rtc_event_log_source.cc b/modules/audio_coding/neteq/tools/rtc_event_log_source.cc
index 591e2b9..fa9f2d9 100644
--- a/modules/audio_coding/neteq/tools/rtc_event_log_source.cc
+++ b/modules/audio_coding/neteq/tools/rtc_event_log_source.cc
@@ -36,11 +36,23 @@
 }
 }  // namespace
 
-RtcEventLogSource* RtcEventLogSource::Create(
+std::unique_ptr<RtcEventLogSource> RtcEventLogSource::CreateFromFile(
     const std::string& file_name,
     absl::optional<uint32_t> ssrc_filter) {
-  RtcEventLogSource* source = new RtcEventLogSource();
-  RTC_CHECK(source->OpenFile(file_name, ssrc_filter));
+  auto source = std::unique_ptr<RtcEventLogSource>(new RtcEventLogSource());
+  ParsedRtcEventLog parsed_log;
+  RTC_CHECK(parsed_log.ParseFile(file_name));
+  RTC_CHECK(source->Initialize(parsed_log, ssrc_filter));
+  return source;
+}
+
+std::unique_ptr<RtcEventLogSource> RtcEventLogSource::CreateFromString(
+    const std::string& file_contents,
+    absl::optional<uint32_t> ssrc_filter) {
+  auto source = std::unique_ptr<RtcEventLogSource>(new RtcEventLogSource());
+  ParsedRtcEventLog parsed_log;
+  RTC_CHECK(parsed_log.ParseString(file_contents));
+  RTC_CHECK(source->Initialize(parsed_log, ssrc_filter));
   return source;
 }
 
@@ -64,12 +76,8 @@
 
 RtcEventLogSource::RtcEventLogSource() : PacketSource() {}
 
-bool RtcEventLogSource::OpenFile(const std::string& file_name,
-                                 absl::optional<uint32_t> ssrc_filter) {
-  ParsedRtcEventLog parsed_log;
-  if (!parsed_log.ParseFile(file_name))
-    return false;
-
+bool RtcEventLogSource::Initialize(const ParsedRtcEventLog& parsed_log,
+                                   absl::optional<uint32_t> ssrc_filter) {
   const auto first_log_end_time_us =
       parsed_log.stop_log_events().empty()
           ? std::numeric_limits<int64_t>::max()
diff --git a/modules/audio_coding/neteq/tools/rtc_event_log_source.h b/modules/audio_coding/neteq/tools/rtc_event_log_source.h
index 5238efb..3c91f73 100644
--- a/modules/audio_coding/neteq/tools/rtc_event_log_source.h
+++ b/modules/audio_coding/neteq/tools/rtc_event_log_source.h
@@ -33,8 +33,13 @@
  public:
   // Creates an RtcEventLogSource reading from |file_name|. If the file cannot
   // be opened, or has the wrong format, NULL will be returned.
-  static RtcEventLogSource* Create(const std::string& file_name,
-                                   absl::optional<uint32_t> ssrc_filter);
+  static std::unique_ptr<RtcEventLogSource> CreateFromFile(
+      const std::string& file_name,
+      absl::optional<uint32_t> ssrc_filter);
+  // Same as above, but uses a string with the file contents.
+  static std::unique_ptr<RtcEventLogSource> CreateFromString(
+      const std::string& file_contents,
+      absl::optional<uint32_t> ssrc_filter);
 
   virtual ~RtcEventLogSource();
 
@@ -48,8 +53,8 @@
  private:
   RtcEventLogSource();
 
-  bool OpenFile(const std::string& file_name,
-                absl::optional<uint32_t> ssrc_filter);
+  bool Initialize(const ParsedRtcEventLog& parsed_log,
+                  absl::optional<uint32_t> ssrc_filter);
 
   std::vector<std::unique_ptr<Packet>> rtp_packets_;
   size_t rtp_packet_index_ = 0;