Add parser and unittests for new RTC event log format.


Bug: webrtc:8111
Change-Id: I78db0765449a07fb94caef6b1452024105d7a69b
Reviewed-on: https://webrtc-review.googlesource.com/c/106709
Commit-Queue: Björn Terelius <terelius@webrtc.org>
Reviewed-by: Elad Alon <eladalon@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#25390}
diff --git a/logging/rtc_event_log/encoder/rtc_event_log_encoder_unittest.cc b/logging/rtc_event_log/encoder/rtc_event_log_encoder_unittest.cc
index 4c36684..726161e 100644
--- a/logging/rtc_event_log/encoder/rtc_event_log_encoder_unittest.cc
+++ b/logging/rtc_event_log/encoder/rtc_event_log_encoder_unittest.cc
@@ -11,9 +11,11 @@
 #include <deque>
 #include <limits>
 #include <string>
+#include <tuple>
 
 #include "absl/memory/memory.h"
 #include "logging/rtc_event_log/encoder/rtc_event_log_encoder_legacy.h"
+#include "logging/rtc_event_log/encoder/rtc_event_log_encoder_new_format.h"
 #include "logging/rtc_event_log/events/rtc_event_alr_state.h"
 #include "logging/rtc_event_log/events/rtc_event_audio_network_adaptation.h"
 #include "logging/rtc_event_log/events/rtc_event_audio_playout.h"
@@ -40,14 +42,16 @@
 
 namespace webrtc {
 
-
-class RtcEventLogEncoderTest : public testing::TestWithParam<int> {
+class RtcEventLogEncoderTest
+    : public testing::TestWithParam<std::tuple<int, bool>> {
  protected:
   RtcEventLogEncoderTest()
-      : encoder_(new RtcEventLogEncoderLegacy),
-        seed_(GetParam()),
-        prng_(seed_),
-        gen_(seed_ * 880001UL) {}
+      : seed_(std::get<0>(GetParam())), prng_(seed_), gen_(seed_ * 880001UL) {
+    if (std::get<1>(GetParam()))
+      encoder_ = absl::make_unique<RtcEventLogEncoderNewFormat>();
+    else
+      encoder_ = absl::make_unique<RtcEventLogEncoderLegacy>();
+  }
   ~RtcEventLogEncoderTest() override = default;
 
   // ANA events have some optional fields, so we want to make sure that we get
@@ -85,16 +89,14 @@
   auto original_runtime_config = *runtime_config;
   auto event = absl::make_unique<RtcEventAudioNetworkAdaptation>(
       std::move(runtime_config));
-  const int64_t timestamp_us = event->timestamp_us_;
-  history_.push_back(std::move(event));
+  history_.push_back(event->Copy());
 
   std::string encoded = encoder_->EncodeBatch(history_.begin(), history_.end());
   ASSERT_TRUE(parsed_log_.ParseString(encoded));
   const auto& ana_configs = parsed_log_.audio_network_adaptation_events();
-  ASSERT_EQ(ana_configs.size(), 1u);
 
-  EXPECT_EQ(ana_configs[0].timestamp_us, timestamp_us);
-  EXPECT_EQ(ana_configs[0].config, original_runtime_config);
+  ASSERT_EQ(ana_configs.size(), 1u);
+  test::VerifyLoggedAudioNetworkAdaptationEvent(*event, ana_configs[0]);
 }
 
 TEST_P(RtcEventLogEncoderTest, RtcEventAudioNetworkAdaptationBitrate) {
@@ -184,6 +186,7 @@
   ASSERT_EQ(playout_events.size(), 1u);
   const auto playout_stream = playout_events.find(ssrc);
   ASSERT_TRUE(playout_stream != playout_events.end());
+
   ASSERT_EQ(playout_stream->second.size(), 1u);
   LoggedAudioPlayoutEvent playout_event = playout_stream->second[0];
   test::VerifyLoggedAudioPlayoutEvent(*event, playout_event);
@@ -242,7 +245,6 @@
   const auto& bwe_loss_updates = parsed_log_.bwe_loss_updates();
 
   ASSERT_EQ(bwe_loss_updates.size(), 1u);
-
   test::VerifyLoggedBweLossBasedUpdate(*event, bwe_loss_updates[0]);
 }
 
@@ -281,7 +283,7 @@
   const auto& start_log_events = parsed_log_.start_log_events();
 
   ASSERT_EQ(start_log_events.size(), 1u);
-  EXPECT_EQ(start_log_events[0].timestamp_us, timestamp_us);
+  test::VerifyLoggedStartEvent(timestamp_us, start_log_events[0]);
 }
 
 TEST_P(RtcEventLogEncoderTest, RtcEventLoggingStopped) {
@@ -291,7 +293,7 @@
   const auto& stop_log_events = parsed_log_.stop_log_events();
 
   ASSERT_EQ(stop_log_events.size(), 1u);
-  EXPECT_EQ(stop_log_events[0].timestamp_us, timestamp_us);
+  test::VerifyLoggedStopEvent(timestamp_us, stop_log_events[0]);
 }
 
 TEST_P(RtcEventLogEncoderTest, RtcEventProbeClusterCreated) {
@@ -435,6 +437,7 @@
 
 INSTANTIATE_TEST_CASE_P(RandomSeeds,
                         RtcEventLogEncoderTest,
-                        ::testing::Values(1, 2, 3, 4, 5));
+                        ::testing::Combine(::testing::Values(1, 2, 3, 4, 5),
+                                           ::testing::Bool()));
 
 }  // namespace webrtc
diff --git a/logging/rtc_event_log/rtc_event_log_parser_new.cc b/logging/rtc_event_log/rtc_event_log_parser_new.cc
index 64d2e13..d352817 100644
--- a/logging/rtc_event_log/rtc_event_log_parser_new.cc
+++ b/logging/rtc_event_log/rtc_event_log_parser_new.cc
@@ -28,6 +28,7 @@
 #include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor.h"
 #include "modules/congestion_controller/rtp/transport_feedback_adapter.h"
 #include "modules/remote_bitrate_estimator/include/bwe_defines.h"
+#include "modules/rtp_rtcp/include/rtp_cvo.h"
 #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
 #include "modules/rtp_rtcp/source/byte_io.h"
 #include "modules/rtp_rtcp/source/rtp_header_extensions.h"
@@ -39,6 +40,7 @@
 namespace webrtc {
 
 namespace {
+// Conversion functions for legacy wire format.
 RtcpMode GetRuntimeRtcpMode(rtclog::VideoReceiveConfig::RtcpMode rtcp_mode) {
   switch (rtcp_mode) {
     case rtclog::VideoReceiveConfig::RTCP_COMPOUND:
@@ -212,6 +214,175 @@
   return IceCandidatePairEventType::kCheckSent;
 }
 
+// Conversion functions for version 2 of the wire format.
+BandwidthUsage GetRuntimeDetectorState(
+    rtclog2::DelayBasedBweUpdates::DetectorState detector_state) {
+  switch (detector_state) {
+    case rtclog2::DelayBasedBweUpdates::BWE_NORMAL:
+      return BandwidthUsage::kBwNormal;
+    case rtclog2::DelayBasedBweUpdates::BWE_UNDERUSING:
+      return BandwidthUsage::kBwUnderusing;
+    case rtclog2::DelayBasedBweUpdates::BWE_OVERUSING:
+      return BandwidthUsage::kBwOverusing;
+    case rtclog2::DelayBasedBweUpdates::BWE_UNKNOWN_STATE:
+      break;
+  }
+  RTC_NOTREACHED();
+  return BandwidthUsage::kBwNormal;
+}
+
+ProbeFailureReason GetRuntimeProbeFailureReason(
+    rtclog2::BweProbeResultFailure::FailureReason failure) {
+  switch (failure) {
+    case rtclog2::BweProbeResultFailure::INVALID_SEND_RECEIVE_INTERVAL:
+      return ProbeFailureReason::kInvalidSendReceiveInterval;
+    case rtclog2::BweProbeResultFailure::INVALID_SEND_RECEIVE_RATIO:
+      return ProbeFailureReason::kInvalidSendReceiveRatio;
+    case rtclog2::BweProbeResultFailure::TIMEOUT:
+      return ProbeFailureReason::kTimeout;
+    case rtclog2::BweProbeResultFailure::UNKNOWN:
+      break;
+  }
+  RTC_NOTREACHED();
+  return ProbeFailureReason::kTimeout;
+}
+
+IceCandidatePairConfigType GetRuntimeIceCandidatePairConfigType(
+    rtclog2::IceCandidatePairConfig::IceCandidatePairConfigType type) {
+  switch (type) {
+    case rtclog2::IceCandidatePairConfig::ADDED:
+      return IceCandidatePairConfigType::kAdded;
+    case rtclog2::IceCandidatePairConfig::UPDATED:
+      return IceCandidatePairConfigType::kUpdated;
+    case rtclog2::IceCandidatePairConfig::DESTROYED:
+      return IceCandidatePairConfigType::kDestroyed;
+    case rtclog2::IceCandidatePairConfig::SELECTED:
+      return IceCandidatePairConfigType::kSelected;
+    case rtclog2::IceCandidatePairConfig::UNKNOWN_CONFIG_TYPE:
+      break;
+  }
+  RTC_NOTREACHED();
+  return IceCandidatePairConfigType::kAdded;
+}
+
+IceCandidateType GetRuntimeIceCandidateType(
+    rtclog2::IceCandidatePairConfig::IceCandidateType type) {
+  switch (type) {
+    case rtclog2::IceCandidatePairConfig::LOCAL:
+      return IceCandidateType::kLocal;
+    case rtclog2::IceCandidatePairConfig::STUN:
+      return IceCandidateType::kStun;
+    case rtclog2::IceCandidatePairConfig::PRFLX:
+      return IceCandidateType::kPrflx;
+    case rtclog2::IceCandidatePairConfig::RELAY:
+      return IceCandidateType::kRelay;
+    case rtclog2::IceCandidatePairConfig::UNKNOWN_CANDIDATE_TYPE:
+      return IceCandidateType::kUnknown;
+  }
+  RTC_NOTREACHED();
+  return IceCandidateType::kUnknown;
+}
+
+IceCandidatePairProtocol GetRuntimeIceCandidatePairProtocol(
+    rtclog2::IceCandidatePairConfig::Protocol protocol) {
+  switch (protocol) {
+    case rtclog2::IceCandidatePairConfig::UDP:
+      return IceCandidatePairProtocol::kUdp;
+    case rtclog2::IceCandidatePairConfig::TCP:
+      return IceCandidatePairProtocol::kTcp;
+    case rtclog2::IceCandidatePairConfig::SSLTCP:
+      return IceCandidatePairProtocol::kSsltcp;
+    case rtclog2::IceCandidatePairConfig::TLS:
+      return IceCandidatePairProtocol::kTls;
+    case rtclog2::IceCandidatePairConfig::UNKNOWN_PROTOCOL:
+      return IceCandidatePairProtocol::kUnknown;
+  }
+  RTC_NOTREACHED();
+  return IceCandidatePairProtocol::kUnknown;
+}
+
+IceCandidatePairAddressFamily GetRuntimeIceCandidatePairAddressFamily(
+    rtclog2::IceCandidatePairConfig::AddressFamily address_family) {
+  switch (address_family) {
+    case rtclog2::IceCandidatePairConfig::IPV4:
+      return IceCandidatePairAddressFamily::kIpv4;
+    case rtclog2::IceCandidatePairConfig::IPV6:
+      return IceCandidatePairAddressFamily::kIpv6;
+    case rtclog2::IceCandidatePairConfig::UNKNOWN_ADDRESS_FAMILY:
+      return IceCandidatePairAddressFamily::kUnknown;
+  }
+  RTC_NOTREACHED();
+  return IceCandidatePairAddressFamily::kUnknown;
+}
+
+IceCandidateNetworkType GetRuntimeIceCandidateNetworkType(
+    rtclog2::IceCandidatePairConfig::NetworkType network_type) {
+  switch (network_type) {
+    case rtclog2::IceCandidatePairConfig::ETHERNET:
+      return IceCandidateNetworkType::kEthernet;
+    case rtclog2::IceCandidatePairConfig::LOOPBACK:
+      return IceCandidateNetworkType::kLoopback;
+    case rtclog2::IceCandidatePairConfig::WIFI:
+      return IceCandidateNetworkType::kWifi;
+    case rtclog2::IceCandidatePairConfig::VPN:
+      return IceCandidateNetworkType::kVpn;
+    case rtclog2::IceCandidatePairConfig::CELLULAR:
+      return IceCandidateNetworkType::kCellular;
+    case rtclog2::IceCandidatePairConfig::UNKNOWN_NETWORK_TYPE:
+      return IceCandidateNetworkType::kUnknown;
+  }
+  RTC_NOTREACHED();
+  return IceCandidateNetworkType::kUnknown;
+}
+
+IceCandidatePairEventType GetRuntimeIceCandidatePairEventType(
+    rtclog2::IceCandidatePairEvent::IceCandidatePairEventType type) {
+  switch (type) {
+    case rtclog2::IceCandidatePairEvent::CHECK_SENT:
+      return IceCandidatePairEventType::kCheckSent;
+    case rtclog2::IceCandidatePairEvent::CHECK_RECEIVED:
+      return IceCandidatePairEventType::kCheckReceived;
+    case rtclog2::IceCandidatePairEvent::CHECK_RESPONSE_SENT:
+      return IceCandidatePairEventType::kCheckResponseSent;
+    case rtclog2::IceCandidatePairEvent::CHECK_RESPONSE_RECEIVED:
+      return IceCandidatePairEventType::kCheckResponseReceived;
+    case rtclog2::IceCandidatePairEvent::UNKNOWN_CHECK_TYPE:
+      break;
+  }
+  RTC_NOTREACHED();
+  return IceCandidatePairEventType::kCheckSent;
+}
+
+std::vector<RtpExtension> GetRuntimeRtpHeaderExtensionConfig(
+    const rtclog2::RtpHeaderExtensionConfig& proto_header_extensions) {
+  std::vector<RtpExtension> rtp_extensions;
+  if (proto_header_extensions.has_transmission_time_offset_id()) {
+    rtp_extensions.emplace_back(
+        RtpExtension::kTimestampOffsetUri,
+        proto_header_extensions.transmission_time_offset_id());
+  }
+  if (proto_header_extensions.has_absolute_send_time_id()) {
+    rtp_extensions.emplace_back(
+        RtpExtension::kAbsSendTimeUri,
+        proto_header_extensions.absolute_send_time_id());
+  }
+  if (proto_header_extensions.has_transport_sequence_number_id()) {
+    rtp_extensions.emplace_back(
+        RtpExtension::kTransportSequenceNumberUri,
+        proto_header_extensions.transport_sequence_number_id());
+  }
+  if (proto_header_extensions.has_audio_level_id()) {
+    rtp_extensions.emplace_back(RtpExtension::kAudioLevelUri,
+                                proto_header_extensions.audio_level_id());
+  }
+  if (proto_header_extensions.has_video_rotation_id()) {
+    rtp_extensions.emplace_back(RtpExtension::kVideoRotationUri,
+                                proto_header_extensions.video_rotation_id());
+  }
+  return rtp_extensions;
+}
+// End of conversion functions.
+
 // Reads a VarInt from |stream| and returns it. Also writes the read bytes to
 // |buffer| starting |bytes_written| bytes into the buffer. |bytes_written| is
 // incremented for each written byte.
@@ -277,9 +448,15 @@
                                    const uint8_t* packet,
                                    size_t total_length)
     : timestamp_us(timestamp_us), raw_data(packet, packet + total_length) {}
+LoggedRtcpPacket::LoggedRtcpPacket(uint64_t timestamp_us,
+                                   const std::string& packet)
+    : timestamp_us(timestamp_us), raw_data(packet.size()) {
+  memcpy(raw_data.data(), packet.data(), packet.size());
+}
 LoggedRtcpPacket::LoggedRtcpPacket(const LoggedRtcpPacket& rhs) = default;
 LoggedRtcpPacket::~LoggedRtcpPacket() = default;
 
+LoggedVideoSendConfig::LoggedVideoSendConfig() = default;
 LoggedVideoSendConfig::LoggedVideoSendConfig(
     int64_t timestamp_us,
     const std::vector<rtclog::StreamConfig>& configs)
@@ -478,9 +655,8 @@
 
 bool ParsedRtcEventLogNew::ParseStreamInternal(
     std::istream& stream) {  // no-presubmit-check TODO(webrtc:8982)
-  const size_t kMaxEventSize = (1u << 16) - 1;
-  const size_t kMaxVarintSize = 10;
-  std::vector<char> buffer(kMaxEventSize + 2 * kMaxVarintSize);
+  constexpr uint64_t kMaxEventSize = 10000000;  // Sanity check.
+  std::vector<char> buffer(0xFFFF);
 
   RTC_DCHECK(stream.good());
 
@@ -491,10 +667,12 @@
       break;
     }
 
-    // Read the next message tag. The tag number is defined as
-    // (fieldnumber << 3) | wire_type. In our case, the field number is
-    // supposed to be 1 and the wire type for a length-delimited field is 2.
-    const uint64_t kExpectedV1Tag = (1 << 3) | 2;
+    // Read the next message tag. Protobuf defines the message tag as
+    // (field_number << 3) | wire_type. In the legacy encoding, the field number
+    // is supposed to be 1 and the wire type for a length-delimited field is 2.
+    // In the new encoding we still expect the wire type to be 2, but the field
+    // number will be greater than 1.
+    constexpr uint64_t kExpectedV1Tag = (1 << 3) | 2;
     size_t bytes_written = 0;
     absl::optional<uint64_t> tag =
         ParseVarInt(stream, buffer.data(), &bytes_written);
@@ -502,9 +680,13 @@
       RTC_LOG(LS_WARNING)
           << "Missing field tag from beginning of protobuf event.";
       return false;
-    } else if (*tag != kExpectedV1Tag) {
-      RTC_LOG(LS_WARNING)
-          << "Unexpected field tag at beginning of protobuf event.";
+    }
+    constexpr uint64_t kWireTypeMask = 0x07;
+    const uint64_t wire_type = *tag & kWireTypeMask;
+    if (wire_type != 2) {
+      RTC_LOG(LS_WARNING) << "Expected field tag with wire type 2 (length "
+                             "delimited message). Found wire type "
+                          << wire_type;
       return false;
     }
 
@@ -520,6 +702,8 @@
     }
 
     // Read the next protobuf event to a temporary char buffer.
+    if (buffer.size() < bytes_written + *message_length)
+      buffer.resize(bytes_written + *message_length);
     stream.read(buffer.data() + bytes_written, *message_length);
     if (stream.gcount() != static_cast<int>(*message_length)) {
       RTC_LOG(LS_WARNING) << "Failed to read protobuf message from file.";
@@ -527,21 +711,32 @@
     }
     size_t buffer_size = bytes_written + *message_length;
 
-    // Parse the protobuf event from the buffer.
-    rtclog::EventStream event_stream;
-    if (!event_stream.ParseFromArray(buffer.data(), buffer_size)) {
-      RTC_LOG(LS_WARNING) << "Failed to parse protobuf message.";
-      return false;
-    }
+    if (*tag == kExpectedV1Tag) {
+      // Parse the protobuf event from the buffer.
+      rtclog::EventStream event_stream;
+      if (!event_stream.ParseFromArray(buffer.data(), buffer_size)) {
+        RTC_LOG(LS_WARNING)
+            << "Failed to parse legacy-format protobuf message.";
+        return false;
+      }
 
-    RTC_CHECK_EQ(event_stream.stream_size(), 1);
-    StoreParsedEvent(event_stream.stream(0));
-    events_.push_back(event_stream.stream(0));
+      RTC_CHECK_EQ(event_stream.stream_size(), 1);
+      StoreParsedLegacyEvent(event_stream.stream(0));
+      events_.push_back(event_stream.stream(0));
+    } else {
+      // Parse the protobuf event from the buffer.
+      rtclog2::EventStream event_stream;
+      if (!event_stream.ParseFromArray(buffer.data(), buffer_size)) {
+        RTC_LOG(LS_WARNING) << "Failed to parse new-format protobuf message.";
+        return false;
+      }
+      StoreParsedNewFormatEvent(event_stream);
+    }
   }
   return true;
 }
 
-void ParsedRtcEventLogNew::StoreParsedEvent(const rtclog::Event& event) {
+void ParsedRtcEventLogNew::StoreParsedLegacyEvent(const rtclog::Event& event) {
   if (event.type() != rtclog::Event::VIDEO_RECEIVER_CONFIG_EVENT &&
       event.type() != rtclog::Event::VIDEO_SENDER_CONFIG_EVENT &&
       event.type() != rtclog::Event::AUDIO_RECEIVER_CONFIG_EVENT &&
@@ -1480,4 +1675,539 @@
   return rtp_rtcp_matched;
 }
 
+// Helper functions for new format starts here
+void ParsedRtcEventLogNew::StoreParsedNewFormatEvent(
+    const rtclog2::EventStream& stream) {
+  RTC_DCHECK_EQ(stream.stream_size(), 0);
+
+  RTC_DCHECK_LE(stream.incoming_rtp_packets_size(), 1);
+  if (stream.incoming_rtp_packets_size() == 1) {
+    StoreIncomingRtpPackets(stream.incoming_rtp_packets(0));
+  }
+
+  RTC_DCHECK_LE(stream.outgoing_rtp_packets_size(), 1);
+  if (stream.outgoing_rtp_packets_size() == 1) {
+    StoreOutgoingRtpPacket(stream.outgoing_rtp_packets(0));
+  }
+
+  RTC_DCHECK_LE(stream.incoming_rtcp_packets_size(), 1);
+  if (stream.incoming_rtcp_packets_size() == 1) {
+    StoreIncomingRtcpPackets(stream.incoming_rtcp_packets(0));
+  }
+
+  RTC_DCHECK_LE(stream.outgoing_rtcp_packets_size(), 1);
+  if (stream.outgoing_rtcp_packets_size() == 1) {
+    StoreOutgoingRtcpPackets(stream.outgoing_rtcp_packets(0));
+  }
+
+  RTC_DCHECK_LE(stream.audio_playout_events_size(), 1);
+  if (stream.audio_playout_events_size() == 1) {
+    StoreAudioPlayoutEvent(stream.audio_playout_events(0));
+  }
+
+  RTC_DCHECK_LE(stream.begin_log_events_size(), 1);
+  if (stream.begin_log_events_size() == 1) {
+    StoreStartEvent(stream.begin_log_events(0));
+  }
+
+  RTC_DCHECK_LE(stream.end_log_events_size(), 1);
+  if (stream.end_log_events_size() == 1) {
+    StoreStopEvent(stream.end_log_events(0));
+  }
+
+  RTC_DCHECK_LE(stream.loss_based_bwe_updates_size(), 1);
+  if (stream.loss_based_bwe_updates_size() == 1) {
+    StoreBweLossBasedUpdate(stream.loss_based_bwe_updates(0));
+  }
+
+  RTC_DCHECK_LE(stream.delay_based_bwe_updates_size(), 1);
+  if (stream.delay_based_bwe_updates_size() == 1) {
+    StoreBweDelayBasedUpdate(stream.delay_based_bwe_updates(0));
+  }
+
+  RTC_DCHECK_LE(stream.audio_network_adaptations_size(), 1);
+  if (stream.audio_network_adaptations_size() == 1) {
+    StoreAudioNetworkAdaptationEvent(stream.audio_network_adaptations(0));
+  }
+
+  RTC_DCHECK_LE(stream.probe_clusters_size(), 1);
+  if (stream.probe_clusters_size() == 1) {
+    StoreBweProbeClusterCreated(stream.probe_clusters(0));
+  }
+
+  RTC_DCHECK_LE(stream.probe_success_size(), 1);
+  if (stream.probe_success_size() == 1) {
+    StoreBweProbeSuccessEvent(stream.probe_success(0));
+  }
+
+  RTC_DCHECK_LE(stream.probe_failure_size(), 1);
+  if (stream.probe_failure_size() == 1) {
+    StoreBweProbeFailureEvent(stream.probe_failure(0));
+  }
+
+  RTC_DCHECK_LE(stream.alr_states_size(), 1);
+  if (stream.alr_states_size() == 1) {
+    StoreAlrStateEvent(stream.alr_states(0));
+  }
+
+  RTC_DCHECK_LE(stream.ice_candidate_configs_size(), 1);
+  if (stream.ice_candidate_configs_size() == 1) {
+    StoreIceCandidatePairConfig(stream.ice_candidate_configs(0));
+  }
+
+  RTC_DCHECK_LE(stream.ice_candidate_events_size(), 1);
+  if (stream.ice_candidate_events_size() == 1) {
+    StoreIceCandidateEvent(stream.ice_candidate_events(0));
+  }
+
+  RTC_DCHECK_LE(stream.audio_recv_stream_configs_size(), 1);
+  if (stream.audio_recv_stream_configs_size() == 1) {
+    StoreAudioRecvConfig(stream.audio_recv_stream_configs(0));
+  }
+
+  RTC_DCHECK_LE(stream.audio_send_stream_configs_size(), 1);
+  if (stream.audio_send_stream_configs_size() == 1) {
+    StoreAudioSendConfig(stream.audio_send_stream_configs(0));
+  }
+
+  RTC_DCHECK_LE(stream.video_recv_stream_configs_size(), 1);
+  if (stream.video_recv_stream_configs_size() == 1) {
+    StoreVideoRecvConfig(stream.video_recv_stream_configs(0));
+  }
+
+  RTC_DCHECK_LE(stream.video_send_stream_configs_size(), 1);
+  if (stream.video_send_stream_configs_size() == 1) {
+    StoreVideoSendConfig(stream.video_send_stream_configs(0));
+  }
+}
+
+void ParsedRtcEventLogNew::StoreAlrStateEvent(const rtclog2::AlrState& proto) {
+  RTC_CHECK(proto.has_timestamp_ms());
+  RTC_CHECK(proto.has_in_alr());
+  LoggedAlrStateEvent alr_event;
+  alr_event.timestamp_us = proto.timestamp_ms() * 1000;
+  alr_event.in_alr = proto.in_alr();
+
+  alr_state_events_.push_back(alr_event);
+  // TODO(terelius): Should we delta encode this event type?
+}
+
+void ParsedRtcEventLogNew::StoreAudioPlayoutEvent(
+    const rtclog2::AudioPlayoutEvents& proto) {
+  RTC_CHECK(proto.has_timestamp_ms());
+  RTC_CHECK(proto.has_local_ssrc());
+  LoggedAudioPlayoutEvent audio_playout_event;
+  audio_playout_event.timestamp_us = proto.timestamp_ms() * 1000;
+  audio_playout_event.ssrc = proto.local_ssrc();
+
+  audio_playout_events_[audio_playout_event.ssrc].push_back(
+      audio_playout_event);
+  // TODO(terelius): Parse deltas.
+}
+
+void ParsedRtcEventLogNew::StoreIncomingRtpPackets(
+    const rtclog2::IncomingRtpPackets& proto) {
+  RTC_CHECK(proto.has_timestamp_ms());
+  int64_t timestamp_ms = proto.timestamp_ms();
+
+  RTC_CHECK(proto.has_header_size());
+  size_t header_length = proto.header_size();
+
+  RTC_CHECK(proto.has_padding_size());
+  size_t padding_length = proto.padding_size();
+
+  RTC_CHECK(proto.has_payload_size());
+  size_t total_length = proto.payload_size() + header_length + padding_length;
+
+  RTPHeader header;
+  RTC_CHECK(proto.has_marker());
+  header.markerBit = proto.marker();
+  RTC_CHECK(proto.has_payload_type());
+  header.payloadType = proto.payload_type();
+  RTC_CHECK(proto.has_sequence_number());
+  header.sequenceNumber = proto.sequence_number();
+  RTC_CHECK(proto.has_rtp_timestamp());
+  header.timestamp = proto.rtp_timestamp();
+  RTC_CHECK(proto.has_ssrc());
+  header.ssrc = proto.ssrc();
+
+  header.numCSRCs = 0;  // TODO(terelius): Implement CSRC.
+  header.paddingLength = padding_length;
+  header.headerLength = header_length;
+  // TODO(terelius): Should we implement payload_type_frequency?
+
+  if (proto.has_transmission_time_offset()) {
+    header.extension.hasTransmissionTimeOffset = true;
+    header.extension.transmissionTimeOffset = proto.transmission_time_offset();
+  }
+  if (proto.has_absolute_send_time()) {
+    header.extension.hasAbsoluteSendTime = true;
+    header.extension.absoluteSendTime = proto.absolute_send_time();
+  }
+  if (proto.has_transport_sequence_number()) {
+    header.extension.hasTransportSequenceNumber = true;
+    header.extension.transportSequenceNumber =
+        proto.transport_sequence_number();
+  }
+  if (proto.has_audio_level()) {
+    header.extension.hasAudioLevel = true;
+    header.extension.voiceActivity = (proto.audio_level() >> 7) != 0;
+    header.extension.audioLevel = proto.audio_level() & 0x7Fu;
+  }
+  if (proto.has_video_rotation()) {
+    header.extension.hasVideoRotation = true;
+    header.extension.videoRotation =
+        ConvertCVOByteToVideoRotation(proto.video_rotation());
+  }
+
+  incoming_rtp_packets_map_[header.ssrc].push_back(LoggedRtpPacketIncoming(
+      timestamp_ms * 1000, header, header_length, total_length));
+  // TODO(terelius): Parse deltas.
+}
+
+void ParsedRtcEventLogNew::StoreOutgoingRtpPacket(
+    const rtclog2::OutgoingRtpPackets& proto) {
+  RTC_CHECK(proto.has_timestamp_ms());
+  int64_t timestamp_ms = proto.timestamp_ms();
+
+  RTC_CHECK(proto.has_header_size());
+  size_t header_length = proto.header_size();
+
+  RTC_CHECK(proto.has_padding_size());
+  size_t padding_length = proto.padding_size();
+
+  RTC_CHECK(proto.has_payload_size());
+  size_t total_length = proto.payload_size() + header_length + padding_length;
+
+  RTPHeader header;
+  RTC_CHECK(proto.has_marker());
+  header.markerBit = proto.marker();
+  RTC_CHECK(proto.has_payload_type());
+  header.payloadType = proto.payload_type();
+  RTC_CHECK(proto.has_sequence_number());
+  header.sequenceNumber = proto.sequence_number();
+  RTC_CHECK(proto.has_rtp_timestamp());
+  header.timestamp = proto.rtp_timestamp();
+  RTC_CHECK(proto.has_ssrc());
+  header.ssrc = proto.ssrc();
+
+  header.numCSRCs = 0;  // TODO(terelius): Implement CSRC.
+  header.paddingLength = padding_length;
+  header.headerLength = header_length;
+  // TODO(terelius): Should we implement payload_type_frequency?
+
+  if (proto.has_transmission_time_offset()) {
+    header.extension.hasTransmissionTimeOffset = true;
+    header.extension.transmissionTimeOffset = proto.transmission_time_offset();
+  }
+  if (proto.has_absolute_send_time()) {
+    header.extension.hasAbsoluteSendTime = true;
+    header.extension.absoluteSendTime = proto.absolute_send_time();
+  }
+  if (proto.has_transport_sequence_number()) {
+    header.extension.hasTransportSequenceNumber = true;
+    header.extension.transportSequenceNumber =
+        proto.transport_sequence_number();
+  }
+  if (proto.has_audio_level()) {
+    header.extension.hasAudioLevel = true;
+    header.extension.voiceActivity = (proto.audio_level() >> 7) != 0;
+    header.extension.audioLevel = proto.audio_level() & 0x7Fu;
+  }
+  if (proto.has_video_rotation()) {
+    header.extension.hasVideoRotation = true;
+    header.extension.videoRotation =
+        ConvertCVOByteToVideoRotation(proto.video_rotation());
+  }
+
+  outgoing_rtp_packets_map_[header.ssrc].push_back(LoggedRtpPacketOutgoing(
+      timestamp_ms * 1000, header, header_length, total_length));
+  // TODO(terelius): Parse deltas.
+}
+
+void ParsedRtcEventLogNew::StoreIncomingRtcpPackets(
+    const rtclog2::IncomingRtcpPackets& proto) {
+  RTC_CHECK(proto.has_timestamp_ms());
+  int64_t timestamp_ms = proto.timestamp_ms();
+
+  RTC_CHECK(proto.has_raw_packet());
+  incoming_rtcp_packets_.push_back(
+      LoggedRtcpPacketIncoming(timestamp_ms * 1000, proto.raw_packet()));
+
+  // TODO(terelius): Parse deltas.
+}
+
+void ParsedRtcEventLogNew::StoreOutgoingRtcpPackets(
+    const rtclog2::OutgoingRtcpPackets& proto) {
+  RTC_CHECK(proto.has_timestamp_ms());
+  int64_t timestamp_ms = proto.timestamp_ms();
+
+  RTC_CHECK(proto.has_raw_packet());
+  outgoing_rtcp_packets_.push_back(
+      LoggedRtcpPacketOutgoing(timestamp_ms * 1000, proto.raw_packet()));
+
+  // TODO(terelius): Parse deltas.
+}
+
+void ParsedRtcEventLogNew::StoreStartEvent(
+    const rtclog2::BeginLogEvent& proto) {
+  RTC_CHECK(proto.has_timestamp_ms());
+  LoggedStartEvent start_event(proto.timestamp_ms() * 1000);
+
+  start_log_events_.push_back(start_event);
+}
+
+void ParsedRtcEventLogNew::StoreStopEvent(const rtclog2::EndLogEvent& proto) {
+  RTC_CHECK(proto.has_timestamp_ms());
+  LoggedStopEvent stop_event(proto.timestamp_ms() * 1000);
+
+  stop_log_events_.push_back(stop_event);
+}
+
+void ParsedRtcEventLogNew::StoreBweLossBasedUpdate(
+    const rtclog2::LossBasedBweUpdates& proto) {
+  RTC_CHECK(proto.has_timestamp_ms());
+  RTC_CHECK(proto.has_bitrate_bps());
+  RTC_CHECK(proto.has_fraction_loss());
+  RTC_CHECK(proto.has_total_packets());
+
+  LoggedBweLossBasedUpdate loss_update;
+  loss_update.timestamp_us = proto.timestamp_ms() * 1000;
+  loss_update.bitrate_bps = proto.bitrate_bps();
+  loss_update.fraction_lost = proto.fraction_loss();
+  loss_update.expected_packets = proto.total_packets();
+
+  bwe_loss_updates_.push_back(loss_update);
+
+  // TODO(terelius): Parse deltas.
+}
+
+void ParsedRtcEventLogNew::StoreBweDelayBasedUpdate(
+    const rtclog2::DelayBasedBweUpdates& proto) {
+  RTC_CHECK(proto.has_timestamp_ms());
+  RTC_CHECK(proto.has_bitrate_bps());
+  RTC_CHECK(proto.has_detector_state());
+
+  LoggedBweDelayBasedUpdate delay_update;
+  delay_update.timestamp_us = proto.timestamp_ms() * 1000;
+  delay_update.bitrate_bps = proto.bitrate_bps();
+  delay_update.detector_state = GetRuntimeDetectorState(proto.detector_state());
+
+  bwe_delay_updates_.push_back(delay_update);
+
+  // TODO(terelius): Parse deltas.
+}
+
+void ParsedRtcEventLogNew::StoreBweProbeClusterCreated(
+    const rtclog2::BweProbeCluster& proto) {
+  LoggedBweProbeClusterCreatedEvent probe_cluster;
+  RTC_CHECK(proto.has_timestamp_ms());
+  probe_cluster.timestamp_us = proto.timestamp_ms() * 1000;
+  RTC_CHECK(proto.has_id());
+  probe_cluster.id = proto.id();
+  RTC_CHECK(proto.has_bitrate_bps());
+  probe_cluster.bitrate_bps = proto.bitrate_bps();
+  RTC_CHECK(proto.has_min_packets());
+  probe_cluster.min_packets = proto.min_packets();
+  RTC_CHECK(proto.has_min_bytes());
+  probe_cluster.min_bytes = proto.min_bytes();
+
+  bwe_probe_cluster_created_events_.push_back(probe_cluster);
+
+  // TODO(terelius): Should we delta encode this event type?
+}
+
+void ParsedRtcEventLogNew::StoreBweProbeSuccessEvent(
+    const rtclog2::BweProbeResultSuccess& proto) {
+  LoggedBweProbeSuccessEvent probe_result;
+  RTC_CHECK(proto.has_timestamp_ms());
+  probe_result.timestamp_us = proto.timestamp_ms() * 1000;
+  RTC_CHECK(proto.has_id());
+  probe_result.id = proto.id();
+  RTC_CHECK(proto.has_bitrate_bps());
+  probe_result.bitrate_bps = proto.bitrate_bps();
+
+  bwe_probe_success_events_.push_back(probe_result);
+
+  // TODO(terelius): Should we delta encode this event type?
+}
+
+void ParsedRtcEventLogNew::StoreBweProbeFailureEvent(
+    const rtclog2::BweProbeResultFailure& proto) {
+  LoggedBweProbeFailureEvent probe_result;
+  RTC_CHECK(proto.has_timestamp_ms());
+  probe_result.timestamp_us = proto.timestamp_ms() * 1000;
+  RTC_CHECK(proto.has_id());
+  probe_result.id = proto.id();
+  RTC_CHECK(proto.has_failure());
+  probe_result.failure_reason = GetRuntimeProbeFailureReason(proto.failure());
+
+  bwe_probe_failure_events_.push_back(probe_result);
+
+  // TODO(terelius): Should we delta encode this event type?
+}
+
+void ParsedRtcEventLogNew::StoreAudioNetworkAdaptationEvent(
+    const rtclog2::AudioNetworkAdaptations& proto) {
+  LoggedAudioNetworkAdaptationEvent ana_event;
+  RTC_CHECK(proto.has_timestamp_ms());
+  ana_event.timestamp_us = proto.timestamp_ms() * 1000;
+
+  if (proto.has_bitrate_bps()) {
+    ana_event.config.bitrate_bps = proto.bitrate_bps();
+  }
+  if (proto.has_frame_length_ms()) {
+    ana_event.config.frame_length_ms = proto.frame_length_ms();
+  }
+  if (proto.has_uplink_packet_loss_fraction()) {
+    ana_event.config.uplink_packet_loss_fraction =
+        proto.uplink_packet_loss_fraction();
+  }
+  if (proto.has_enable_fec()) {
+    ana_event.config.enable_fec = proto.enable_fec();
+  }
+  if (proto.has_enable_dtx()) {
+    ana_event.config.enable_dtx = proto.enable_dtx();
+  }
+  if (proto.has_num_channels()) {
+    ana_event.config.num_channels = proto.num_channels();
+  }
+
+  audio_network_adaptation_events_.push_back(ana_event);
+
+  // TODO(terelius): Parse deltas.
+}
+
+void ParsedRtcEventLogNew::StoreIceCandidatePairConfig(
+    const rtclog2::IceCandidatePairConfig& proto) {
+  LoggedIceCandidatePairConfig ice_config;
+  RTC_CHECK(proto.has_timestamp_ms());
+  ice_config.timestamp_us = proto.timestamp_ms() * 1000;
+
+  RTC_CHECK(proto.has_config_type());
+  ice_config.type = GetRuntimeIceCandidatePairConfigType(proto.config_type());
+  RTC_CHECK(proto.has_candidate_pair_id());
+  ice_config.candidate_pair_id = proto.candidate_pair_id();
+  RTC_CHECK(proto.has_local_candidate_type());
+  ice_config.local_candidate_type =
+      GetRuntimeIceCandidateType(proto.local_candidate_type());
+  RTC_CHECK(proto.has_local_relay_protocol());
+  ice_config.local_relay_protocol =
+      GetRuntimeIceCandidatePairProtocol(proto.local_relay_protocol());
+  RTC_CHECK(proto.has_local_network_type());
+  ice_config.local_network_type =
+      GetRuntimeIceCandidateNetworkType(proto.local_network_type());
+  RTC_CHECK(proto.has_local_address_family());
+  ice_config.local_address_family =
+      GetRuntimeIceCandidatePairAddressFamily(proto.local_address_family());
+  RTC_CHECK(proto.has_remote_candidate_type());
+  ice_config.remote_candidate_type =
+      GetRuntimeIceCandidateType(proto.remote_candidate_type());
+  RTC_CHECK(proto.has_remote_address_family());
+  ice_config.remote_address_family =
+      GetRuntimeIceCandidatePairAddressFamily(proto.remote_address_family());
+  RTC_CHECK(proto.has_candidate_pair_protocol());
+  ice_config.candidate_pair_protocol =
+      GetRuntimeIceCandidatePairProtocol(proto.candidate_pair_protocol());
+
+  ice_candidate_pair_configs_.push_back(ice_config);
+
+  // TODO(terelius): Should we delta encode this event type?
+}
+
+void ParsedRtcEventLogNew::StoreIceCandidateEvent(
+    const rtclog2::IceCandidatePairEvent& proto) {
+  LoggedIceCandidatePairEvent ice_event;
+  RTC_CHECK(proto.has_timestamp_ms());
+  ice_event.timestamp_us = proto.timestamp_ms() * 1000;
+  RTC_CHECK(proto.has_event_type());
+  ice_event.type = GetRuntimeIceCandidatePairEventType(proto.event_type());
+  RTC_CHECK(proto.has_candidate_pair_id());
+  ice_event.candidate_pair_id = proto.candidate_pair_id();
+
+  ice_candidate_pair_events_.push_back(ice_event);
+
+  // TODO(terelius): Should we delta encode this event type?
+}
+
+void ParsedRtcEventLogNew::StoreVideoRecvConfig(
+    const rtclog2::VideoRecvStreamConfig& proto) {
+  LoggedVideoRecvConfig stream;
+  RTC_CHECK(proto.has_timestamp_ms());
+  stream.timestamp_us = proto.timestamp_ms() * 1000;
+  RTC_CHECK(proto.has_remote_ssrc());
+  stream.config.remote_ssrc = proto.remote_ssrc();
+  RTC_CHECK(proto.has_local_ssrc());
+  stream.config.local_ssrc = proto.local_ssrc();
+  if (proto.has_rtx_ssrc()) {
+    stream.config.rtx_ssrc = proto.rtx_ssrc();
+  }
+  if (proto.has_rsid()) {
+    stream.config.rsid = proto.rsid();
+  }
+  if (proto.has_header_extensions()) {
+    stream.config.rtp_extensions =
+        GetRuntimeRtpHeaderExtensionConfig(proto.header_extensions());
+  }
+  video_recv_configs_.push_back(stream);
+}
+
+void ParsedRtcEventLogNew::StoreVideoSendConfig(
+    const rtclog2::VideoSendStreamConfig& proto) {
+  LoggedVideoSendConfig stream;
+  RTC_CHECK(proto.has_timestamp_ms());
+  stream.timestamp_us = proto.timestamp_ms() * 1000;
+  rtclog::StreamConfig config;
+  RTC_CHECK(proto.has_ssrc());
+  config.local_ssrc = proto.ssrc();
+  if (proto.has_rtx_ssrc()) {
+    config.rtx_ssrc = proto.rtx_ssrc();
+  }
+  if (proto.has_rsid()) {
+    config.rsid = proto.rsid();
+  }
+  if (proto.has_header_extensions()) {
+    config.rtp_extensions =
+        GetRuntimeRtpHeaderExtensionConfig(proto.header_extensions());
+  }
+  stream.configs.push_back(config);
+  video_send_configs_.push_back(stream);
+}
+
+void ParsedRtcEventLogNew::StoreAudioRecvConfig(
+    const rtclog2::AudioRecvStreamConfig& proto) {
+  LoggedAudioRecvConfig stream;
+  RTC_CHECK(proto.has_timestamp_ms());
+  stream.timestamp_us = proto.timestamp_ms() * 1000;
+  RTC_CHECK(proto.has_remote_ssrc());
+  stream.config.remote_ssrc = proto.remote_ssrc();
+  RTC_CHECK(proto.has_local_ssrc());
+  stream.config.local_ssrc = proto.local_ssrc();
+  if (proto.has_rsid()) {
+    stream.config.rsid = proto.rsid();
+  }
+  if (proto.has_header_extensions()) {
+    stream.config.rtp_extensions =
+        GetRuntimeRtpHeaderExtensionConfig(proto.header_extensions());
+  }
+  audio_recv_configs_.push_back(stream);
+}
+
+void ParsedRtcEventLogNew::StoreAudioSendConfig(
+    const rtclog2::AudioSendStreamConfig& proto) {
+  LoggedAudioSendConfig stream;
+  RTC_CHECK(proto.has_timestamp_ms());
+  stream.timestamp_us = proto.timestamp_ms() * 1000;
+  RTC_CHECK(proto.has_ssrc());
+  stream.config.local_ssrc = proto.ssrc();
+  if (proto.has_rsid()) {
+    stream.config.rsid = proto.rsid();
+  }
+  if (proto.has_header_extensions()) {
+    stream.config.rtp_extensions =
+        GetRuntimeRtpHeaderExtensionConfig(proto.header_extensions());
+  }
+  audio_send_configs_.push_back(stream);
+}
+
 }  // namespace webrtc
diff --git a/logging/rtc_event_log/rtc_event_log_parser_new.h b/logging/rtc_event_log/rtc_event_log_parser_new.h
index 5ab0c15..7d24684 100644
--- a/logging/rtc_event_log/rtc_event_log_parser_new.h
+++ b/logging/rtc_event_log/rtc_event_log_parser_new.h
@@ -25,7 +25,7 @@
 #include "logging/rtc_event_log/events/rtc_event_probe_result_failure.h"
 #include "logging/rtc_event_log/rtc_event_log.h"
 #include "logging/rtc_event_log/rtc_stream_config.h"
-#include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor.h"
+#include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor_config.h"
 #include "modules/rtp_rtcp/include/rtp_header_extension_map.h"
 #include "modules/rtp_rtcp/source/rtcp_packet/common_header.h"
 #include "modules/rtp_rtcp/source/rtcp_packet/nack.h"
@@ -39,8 +39,10 @@
 RTC_PUSH_IGNORING_WUNDEF()
 #ifdef WEBRTC_ANDROID_PLATFORM_BUILD
 #include "external/webrtc/webrtc/logging/rtc_event_log/rtc_event_log.pb.h"
+#include "external/webrtc/webrtc/logging/rtc_event_log/rtc_event_log2.pb.h"
 #else
 #include "logging/rtc_event_log/rtc_event_log.pb.h"
+#include "logging/rtc_event_log/rtc_event_log2.pb.h"
 #endif
 RTC_POP_IGNORING_WUNDEF()
 
@@ -185,6 +187,7 @@
   LoggedRtcpPacket(uint64_t timestamp_us,
                    const uint8_t* packet,
                    size_t total_length);
+  LoggedRtcpPacket(uint64_t timestamp_us, const std::string& packet);
   LoggedRtcpPacket(const LoggedRtcpPacket&);
   ~LoggedRtcpPacket();
   int64_t timestamp_us;
@@ -198,6 +201,8 @@
                            const uint8_t* packet,
                            size_t total_length)
       : rtcp(timestamp_us, packet, total_length) {}
+  LoggedRtcpPacketIncoming(uint64_t timestamp_us, const std::string& packet)
+      : rtcp(timestamp_us, packet) {}
   LoggedRtcpPacket rtcp;
   int64_t log_time_us() const { return rtcp.timestamp_us; }
   int64_t log_time_ms() const { return rtcp.timestamp_us / 1000; }
@@ -208,6 +213,8 @@
                            const uint8_t* packet,
                            size_t total_length)
       : rtcp(timestamp_us, packet, total_length) {}
+  LoggedRtcpPacketOutgoing(uint64_t timestamp_us, const std::string& packet)
+      : rtcp(timestamp_us, packet) {}
   LoggedRtcpPacket rtcp;
   int64_t log_time_us() const { return rtcp.timestamp_us; }
   int64_t log_time_ms() const { return rtcp.timestamp_us / 1000; }
@@ -264,6 +271,7 @@
 };
 
 struct LoggedAudioRecvConfig {
+  LoggedAudioRecvConfig() = default;
   LoggedAudioRecvConfig(int64_t timestamp_us, const rtclog::StreamConfig config)
       : timestamp_us(timestamp_us), config(config) {}
   int64_t timestamp_us;
@@ -273,6 +281,7 @@
 };
 
 struct LoggedAudioSendConfig {
+  LoggedAudioSendConfig() = default;
   LoggedAudioSendConfig(int64_t timestamp_us, const rtclog::StreamConfig config)
       : timestamp_us(timestamp_us), config(config) {}
   int64_t timestamp_us;
@@ -282,6 +291,7 @@
 };
 
 struct LoggedVideoRecvConfig {
+  LoggedVideoRecvConfig() = default;
   LoggedVideoRecvConfig(int64_t timestamp_us, const rtclog::StreamConfig config)
       : timestamp_us(timestamp_us), config(config) {}
   int64_t timestamp_us;
@@ -291,6 +301,7 @@
 };
 
 struct LoggedVideoSendConfig {
+  LoggedVideoSendConfig();
   LoggedVideoSendConfig(int64_t timestamp_us,
                         const std::vector<rtclog::StreamConfig>& configs);
   LoggedVideoSendConfig(const LoggedVideoSendConfig&);
@@ -841,7 +852,7 @@
   bool ParseStreamInternal(
       std::istream& stream);  // no-presubmit-check TODO(webrtc:8982)
 
-  void StoreParsedEvent(const rtclog::Event& event);
+  void StoreParsedLegacyEvent(const rtclog::Event& event);
 
   rtclog::StreamConfig GetVideoReceiveConfig(const rtclog::Event& event) const;
   std::vector<rtclog::StreamConfig> GetVideoSendConfig(
@@ -873,8 +884,36 @@
   LoggedIceCandidatePairEvent GetIceCandidatePairEvent(
       const rtclog::Event& event) const;
 
+  // TODO(terelius): Remove
   std::vector<rtclog::Event> events_;
 
+  // Parsing functions for new format.
+  void StoreParsedNewFormatEvent(const rtclog2::EventStream& event);
+
+  void StoreIncomingRtpPackets(const rtclog2::IncomingRtpPackets& proto);
+  void StoreOutgoingRtpPacket(const rtclog2::OutgoingRtpPackets& proto);
+  void StoreIncomingRtcpPackets(const rtclog2::IncomingRtcpPackets& proto);
+  void StoreOutgoingRtcpPackets(const rtclog2::OutgoingRtcpPackets& proto);
+  void StoreAudioPlayoutEvent(const rtclog2::AudioPlayoutEvents& proto);
+  void StoreStartEvent(const rtclog2::BeginLogEvent& proto);
+  void StoreStopEvent(const rtclog2::EndLogEvent& proto);
+  void StoreBweLossBasedUpdate(const rtclog2::LossBasedBweUpdates& proto);
+  void StoreBweDelayBasedUpdate(const rtclog2::DelayBasedBweUpdates& proto);
+  void StoreAudioNetworkAdaptationEvent(
+      const rtclog2::AudioNetworkAdaptations& proto);
+  void StoreBweProbeClusterCreated(const rtclog2::BweProbeCluster& proto);
+  void StoreBweProbeSuccessEvent(const rtclog2::BweProbeResultSuccess& proto);
+  void StoreBweProbeFailureEvent(const rtclog2::BweProbeResultFailure& proto);
+  void StoreAlrStateEvent(const rtclog2::AlrState& proto);
+  void StoreIceCandidatePairConfig(
+      const rtclog2::IceCandidatePairConfig& proto);
+  void StoreIceCandidateEvent(const rtclog2::IceCandidatePairEvent& proto);
+  void StoreAudioRecvConfig(const rtclog2::AudioRecvStreamConfig& proto);
+  void StoreAudioSendConfig(const rtclog2::AudioSendStreamConfig& proto);
+  void StoreVideoRecvConfig(const rtclog2::VideoRecvStreamConfig& proto);
+  void StoreVideoSendConfig(const rtclog2::VideoSendStreamConfig& proto);
+  // End of new parsing functions.
+
   struct Stream {
     Stream(uint32_t ssrc,
            MediaType media_type,
diff --git a/logging/rtc_event_log/rtc_event_log_unittest.cc b/logging/rtc_event_log/rtc_event_log_unittest.cc
index 1b7fbce..bd136bb 100644
--- a/logging/rtc_event_log/rtc_event_log_unittest.cc
+++ b/logging/rtc_event_log/rtc_event_log_unittest.cc
@@ -101,13 +101,15 @@
 };
 
 class RtcEventLogSession
-    : public ::testing::TestWithParam<std::tuple<uint64_t, int64_t>> {
+    : public ::testing::TestWithParam<
+          std::tuple<uint64_t, int64_t, RtcEventLog::EncodingType>> {
  public:
   RtcEventLogSession()
       : seed_(std::get<0>(GetParam())),
         prng_(seed_),
         gen_(seed_ * 880001UL),
-        output_period_ms_(std::get<1>(GetParam())) {
+        output_period_ms_(std::get<1>(GetParam())),
+        encoding_type_(std::get<2>(GetParam())) {
     clock_.SetTimeMicros(prng_.Rand<uint32_t>());
     // Find the name of the current test, in order to use it as a temporary
     // filename.
@@ -171,7 +173,8 @@
   const uint64_t seed_;
   Random prng_;
   test::EventGenerator gen_;
-  int64_t output_period_ms_;
+  const int64_t output_period_ms_;
+  const RtcEventLog::EncodingType encoding_type_;
   rtc::ScopedFakeClock clock_;
   std::string temp_filename_;
 };
@@ -284,8 +287,7 @@
   // Maybe always use the ScopedFakeClock, but conditionally SleepMs()?
 
   // The log file will be flushed to disk when the event_log goes out of scope.
-  std::unique_ptr<RtcEventLog> event_log(
-      RtcEventLog::Create(RtcEventLog::EncodingType::Legacy));
+  std::unique_ptr<RtcEventLog> event_log(RtcEventLog::Create(encoding_type_));
 
   // We can't send or receive packets without configured streams.
   RTC_CHECK_GE(count.video_recv_streams, 1);
@@ -676,7 +678,23 @@
   ReadAndVerifyLog();
 }
 
-TEST(RtcEventLogTest, CircularBufferKeepsMostRecentEvents) {
+INSTANTIATE_TEST_CASE_P(
+    RtcEventLogTest,
+    RtcEventLogSession,
+    ::testing::Combine(
+        ::testing::Values(1234567, 7654321),
+        ::testing::Values(RtcEventLog::kImmediateOutput, 1, 5),
+        ::testing::Values(RtcEventLog::EncodingType::Legacy,
+                          RtcEventLog::EncodingType::NewFormat)));
+
+class RtcEventLogCircularBufferTest
+    : public ::testing::TestWithParam<RtcEventLog::EncodingType> {
+ public:
+  RtcEventLogCircularBufferTest() : encoding_type_(GetParam()) {}
+  const RtcEventLog::EncodingType encoding_type_;
+};
+
+TEST_P(RtcEventLogCircularBufferTest, KeepsMostRecentEvents) {
   // TODO(terelius): Maybe make a separate RtcEventLogImplTest that can access
   // the size of the cyclic buffer?
   constexpr size_t kNumEvents = 20000;
@@ -695,8 +713,7 @@
 
   // When log_dumper goes out of scope, it causes the log file to be flushed
   // to disk.
-  std::unique_ptr<RtcEventLog> log_dumper(
-      RtcEventLog::Create(RtcEventLog::EncodingType::Legacy));
+  std::unique_ptr<RtcEventLog> log_dumper(RtcEventLog::Create(encoding_type_));
 
   for (size_t i = 0; i < kNumEvents; i++) {
     // The purpose of the test is to verify that the log can handle
@@ -754,13 +771,14 @@
   }
 }
 
+INSTANTIATE_TEST_CASE_P(
+    RtcEventLogTest,
+    RtcEventLogCircularBufferTest,
+    ::testing::Values(RtcEventLog::EncodingType::Legacy,
+                      RtcEventLog::EncodingType::NewFormat));
+
 // TODO(terelius): Verify parser behavior if the timestamps are not
 // monotonically increasing in the log.
 
-INSTANTIATE_TEST_CASE_P(
-    RtcEventLogTest,
-    RtcEventLogSession,
-    ::testing::Combine(::testing::Values(1234567, 7654321),
-                       ::testing::Values(RtcEventLog::kImmediateOutput, 1, 5)));
 
 }  // namespace webrtc