Support GenericPacketReceived/Sent/AckReceived event logs.

This change does not include receive_timestamps for ACKs, because there is 1 problem.
That problem will be resolved in a separate change.

I am getting receive_timestamp errors that have to do with delta compression with optional fields.
Two failure modes that I noticed:
1) the base event does not have the timestamp: it crashes with length validation
# Check failed: base <= MaxUnsignedValueOfBitWidth(params_.value_width_bits()) (1820716 vs. 131071)
2) all events are null, it crashes with assert that X events were expected, but no events were deserialized.


Bug: webrtc:9719
Change-Id: I5d1bbb95dfd15ca7321667aad5e4d89c085e9c06
Reviewed-on: https://webrtc-review.googlesource.com/c/122360
Commit-Queue: Peter Slatala <psla@webrtc.org>
Reviewed-by: Björn Terelius <terelius@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#26668}
diff --git a/logging/BUILD.gn b/logging/BUILD.gn
index 4afb07f..f858531 100644
--- a/logging/BUILD.gn
+++ b/logging/BUILD.gn
@@ -347,6 +347,10 @@
       "//third_party/abseil-cpp/absl/memory",
       "//third_party/abseil-cpp/absl/types:optional",
     ]
+
+    if (!build_with_chromium && is_clang) {
+      suppressed_configs += [ "//build/config/clang:find_bad_constructs" ]
+    }
   }
 
   if (rtc_include_tests) {
@@ -369,6 +373,7 @@
         ":ice_log",
         ":rtc_event_audio",
         ":rtc_event_bwe",
+        ":rtc_event_generic_packet_events",
         ":rtc_event_log2_proto",
         ":rtc_event_log_api",
         ":rtc_event_log_impl_base",
diff --git a/logging/rtc_event_log/encoder/rtc_event_log_encoder_new_format.cc b/logging/rtc_event_log/encoder/rtc_event_log_encoder_new_format.cc
index c568ba4..2a1d26a 100644
--- a/logging/rtc_event_log/encoder/rtc_event_log_encoder_new_format.cc
+++ b/logging/rtc_event_log/encoder/rtc_event_log_encoder_new_format.cc
@@ -867,6 +867,9 @@
     EncodeVideoSendStreamConfig(video_send_stream_configs, &event_stream);
     EncodeIceCandidatePairConfig(ice_candidate_configs, &event_stream);
     EncodeIceCandidatePairEvent(ice_candidate_events, &event_stream);
+    EncodeGenericPacketsReceived(generic_packets_received, &event_stream);
+    EncodeGenericPacketsSent(generic_packets_sent, &event_stream);
+    EncodeGenericAcksReceived(generic_acks_received, &event_stream);
   }  // Deallocate the temporary vectors.
 
   return event_stream.SerializeAsString();
@@ -1326,6 +1329,212 @@
   }
 }
 
+void RtcEventLogEncoderNewFormat::EncodeGenericPacketsSent(
+    rtc::ArrayView<const RtcEventGenericPacketSent*> batch,
+    rtclog2::EventStream* event_stream) {
+  if (batch.empty()) {
+    return;
+  }
+  const RtcEventGenericPacketSent* const base_event = batch[0];
+  rtclog2::GenericPacketSent* proto_batch =
+      event_stream->add_generic_packets_sent();
+  proto_batch->set_timestamp_ms(base_event->timestamp_ms());
+  proto_batch->set_packet_number(base_event->packet_number());
+  proto_batch->set_overhead_length(base_event->overhead_length());
+  proto_batch->set_payload_length(base_event->payload_length());
+  proto_batch->set_padding_length(base_event->padding_length());
+
+  // Delta encoding
+  proto_batch->set_number_of_deltas(batch.size() - 1);
+  std::vector<absl::optional<uint64_t>> values(batch.size() - 1);
+  std::string encoded_deltas;
+
+  if (batch.size() == 1) {
+    return;
+  }
+
+  // timestamp_ms
+  for (size_t i = 0; i < values.size(); ++i) {
+    const RtcEventGenericPacketSent* event = batch[i + 1];
+    values[i] = ToUnsigned(event->timestamp_ms());
+  }
+  encoded_deltas = EncodeDeltas(ToUnsigned(base_event->timestamp_ms()), values);
+  if (!encoded_deltas.empty()) {
+    proto_batch->set_timestamp_ms_deltas(encoded_deltas);
+  }
+
+  // packet_number
+  for (size_t i = 0; i < values.size(); ++i) {
+    const RtcEventGenericPacketSent* event = batch[i + 1];
+    values[i] = ToUnsigned(event->packet_number());
+  }
+  encoded_deltas =
+      EncodeDeltas(ToUnsigned(base_event->packet_number()), values);
+  if (!encoded_deltas.empty()) {
+    proto_batch->set_packet_number_deltas(encoded_deltas);
+  }
+
+  // overhead_length
+  for (size_t i = 0; i < values.size(); ++i) {
+    const RtcEventGenericPacketSent* event = batch[i + 1];
+    values[i] = event->overhead_length();
+  }
+  encoded_deltas = EncodeDeltas(base_event->overhead_length(), values);
+  if (!encoded_deltas.empty()) {
+    proto_batch->set_overhead_length_deltas(encoded_deltas);
+  }
+
+  // payload_length
+  for (size_t i = 0; i < values.size(); ++i) {
+    const RtcEventGenericPacketSent* event = batch[i + 1];
+    values[i] = event->payload_length();
+  }
+  encoded_deltas = EncodeDeltas(base_event->payload_length(), values);
+  if (!encoded_deltas.empty()) {
+    proto_batch->set_payload_length_deltas(encoded_deltas);
+  }
+
+  // padding_length
+  for (size_t i = 0; i < values.size(); ++i) {
+    const RtcEventGenericPacketSent* event = batch[i + 1];
+    values[i] = event->padding_length();
+  }
+  encoded_deltas = EncodeDeltas(base_event->padding_length(), values);
+  if (!encoded_deltas.empty()) {
+    proto_batch->set_padding_length_deltas(encoded_deltas);
+  }
+}
+
+void RtcEventLogEncoderNewFormat::EncodeGenericPacketsReceived(
+    rtc::ArrayView<const RtcEventGenericPacketReceived*> batch,
+    rtclog2::EventStream* event_stream) {
+  if (batch.empty()) {
+    return;
+  }
+  const RtcEventGenericPacketReceived* const base_event = batch[0];
+  rtclog2::GenericPacketReceived* proto_batch =
+      event_stream->add_generic_packets_received();
+  proto_batch->set_timestamp_ms(base_event->timestamp_ms());
+  proto_batch->set_packet_number(base_event->packet_number());
+  proto_batch->set_packet_length(base_event->packet_length());
+
+  // Delta encoding
+  proto_batch->set_number_of_deltas(batch.size() - 1);
+  std::vector<absl::optional<uint64_t>> values(batch.size() - 1);
+  std::string encoded_deltas;
+
+  if (batch.size() == 1) {
+    return;
+  }
+
+  // timestamp_ms
+  for (size_t i = 0; i < values.size(); ++i) {
+    const RtcEventGenericPacketReceived* event = batch[i + 1];
+    values[i] = ToUnsigned(event->timestamp_ms());
+  }
+  encoded_deltas = EncodeDeltas(ToUnsigned(base_event->timestamp_ms()), values);
+  if (!encoded_deltas.empty()) {
+    proto_batch->set_timestamp_ms_deltas(encoded_deltas);
+  }
+
+  // packet_number
+  for (size_t i = 0; i < values.size(); ++i) {
+    const RtcEventGenericPacketReceived* event = batch[i + 1];
+    values[i] = ToUnsigned(event->packet_number());
+  }
+  encoded_deltas =
+      EncodeDeltas(ToUnsigned(base_event->packet_number()), values);
+  if (!encoded_deltas.empty()) {
+    proto_batch->set_packet_number_deltas(encoded_deltas);
+  }
+
+  // packet_length
+  for (size_t i = 0; i < values.size(); ++i) {
+    const RtcEventGenericPacketReceived* event = batch[i + 1];
+    values[i] = event->packet_length();
+  }
+  encoded_deltas = EncodeDeltas(base_event->packet_length(), values);
+  if (!encoded_deltas.empty()) {
+    proto_batch->set_packet_length_deltas(encoded_deltas);
+  }
+}
+
+void RtcEventLogEncoderNewFormat::EncodeGenericAcksReceived(
+    rtc::ArrayView<const RtcEventGenericAckReceived*> batch,
+    rtclog2::EventStream* event_stream) {
+  if (batch.empty()) {
+    return;
+  }
+  const RtcEventGenericAckReceived* const base_event = batch[0];
+  rtclog2::GenericAckReceived* proto_batch =
+      event_stream->add_generic_acks_received();
+  proto_batch->set_timestamp_ms(base_event->timestamp_ms());
+  proto_batch->set_packet_number(base_event->packet_number());
+  proto_batch->set_acked_packet_number(base_event->acked_packet_number());
+  absl::optional<uint64_t> base_receive_timestamp;
+  if (base_event->receive_acked_packet_time_ms()) {
+    int64_t receive_acked_packet_time_ms =
+        base_event->receive_acked_packet_time_ms().value();
+    base_receive_timestamp = ToUnsigned(receive_acked_packet_time_ms);
+    proto_batch->set_receive_acked_packet_time_ms(receive_acked_packet_time_ms);
+  }
+
+  // Delta encoding
+  proto_batch->set_number_of_deltas(batch.size() - 1);
+  std::vector<absl::optional<uint64_t>> values(batch.size() - 1);
+  std::string encoded_deltas;
+
+  if (batch.size() == 1) {
+    return;
+  }
+
+  // timestamp_ms
+  for (size_t i = 0; i < values.size(); ++i) {
+    const RtcEventGenericAckReceived* event = batch[i + 1];
+    values[i] = ToUnsigned(event->timestamp_ms());
+  }
+  encoded_deltas = EncodeDeltas(ToUnsigned(base_event->timestamp_ms()), values);
+  if (!encoded_deltas.empty()) {
+    proto_batch->set_timestamp_ms_deltas(encoded_deltas);
+  }
+
+  // packet_number
+  for (size_t i = 0; i < values.size(); ++i) {
+    const RtcEventGenericAckReceived* event = batch[i + 1];
+    values[i] = ToUnsigned(event->packet_number());
+  }
+  encoded_deltas =
+      EncodeDeltas(ToUnsigned(base_event->packet_number()), values);
+  if (!encoded_deltas.empty()) {
+    proto_batch->set_packet_number_deltas(encoded_deltas);
+  }
+
+  // acked packet number
+  for (size_t i = 0; i < values.size(); ++i) {
+    const RtcEventGenericAckReceived* event = batch[i + 1];
+    values[i] = ToUnsigned(event->acked_packet_number());
+  }
+  encoded_deltas =
+      EncodeDeltas(ToUnsigned(base_event->acked_packet_number()), values);
+  if (!encoded_deltas.empty()) {
+    proto_batch->set_acked_packet_number_deltas(encoded_deltas);
+  }
+
+  // receive timestamp
+  for (size_t i = 0; i < values.size(); ++i) {
+    const RtcEventGenericAckReceived* event = batch[i + 1];
+    if (event->receive_acked_packet_time_ms()) {
+      values[i] = ToUnsigned(event->receive_acked_packet_time_ms().value());
+    } else {
+      values[i] = absl::nullopt;
+    }
+  }
+  encoded_deltas = EncodeDeltas(base_receive_timestamp, values);
+  if (!encoded_deltas.empty()) {
+    proto_batch->set_receive_acked_packet_time_ms_deltas(encoded_deltas);
+  }
+}
+
 void RtcEventLogEncoderNewFormat::EncodeRtpPacketOutgoing(
     const std::map<uint32_t, std::vector<const RtcEventRtpPacketOutgoing*>>&
         batch,
diff --git a/logging/rtc_event_log/encoder/rtc_event_log_encoder_new_format.h b/logging/rtc_event_log/encoder/rtc_event_log_encoder_new_format.h
index 7a0491f..3490ce6 100644
--- a/logging/rtc_event_log/encoder/rtc_event_log_encoder_new_format.h
+++ b/logging/rtc_event_log/encoder/rtc_event_log_encoder_new_format.h
@@ -49,6 +49,9 @@
 class RtcEventIceCandidatePairConfig;
 class RtcEventIceCandidatePair;
 class RtpPacket;
+class RtcEventGenericAckReceived;
+class RtcEventGenericPacketReceived;
+class RtcEventGenericPacketSent;
 
 class RtcEventLogEncoderNewFormat final : public RtcEventLogEncoder {
  public:
@@ -116,6 +119,15 @@
       const std::map<uint32_t, std::vector<const RtcEventRtpPacketOutgoing*>>&
           batch,
       rtclog2::EventStream* event_stream);
+  void EncodeGenericAcksReceived(
+      rtc::ArrayView<const RtcEventGenericAckReceived*> batch,
+      rtclog2::EventStream* event_stream);
+  void EncodeGenericPacketsReceived(
+      rtc::ArrayView<const RtcEventGenericPacketReceived*> batch,
+      rtclog2::EventStream* event_stream);
+  void EncodeGenericPacketsSent(
+      rtc::ArrayView<const RtcEventGenericPacketSent*> batch,
+      rtclog2::EventStream* event_stream);
   void EncodeVideoRecvStreamConfig(
       rtc::ArrayView<const RtcEventVideoReceiveStreamConfig*> batch,
       rtclog2::EventStream* event_stream);
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 79bf045..b5a3a30 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
@@ -463,6 +463,77 @@
   }
 }
 
+TEST_P(RtcEventLogEncoderTest, RtcEventGenericPacketReceived) {
+  if (!new_encoding_) {
+    return;
+  }
+  std::vector<std::unique_ptr<RtcEventGenericPacketReceived>> events(
+      event_count_);
+  for (size_t i = 0; i < event_count_; ++i) {
+    events[i] = (i == 0 || !force_repeated_fields_)
+                    ? gen_.NewGenericPacketReceived()
+                    : events[0]->Copy();
+    history_.push_back(events[i]->Copy());
+  }
+
+  std::string encoded = encoder_->EncodeBatch(history_.begin(), history_.end());
+  ASSERT_TRUE(parsed_log_.ParseString(encoded));
+
+  const auto& packets_received = parsed_log_.generic_packets_received();
+  ASSERT_EQ(packets_received.size(), event_count_);
+
+  for (size_t i = 0; i < event_count_; ++i) {
+    verifier_.VerifyLoggedGenericPacketReceived(*events[i],
+                                                packets_received[i]);
+  }
+}
+
+TEST_P(RtcEventLogEncoderTest, RtcEventGenericPacketSent) {
+  if (!new_encoding_) {
+    return;
+  }
+  std::vector<std::unique_ptr<RtcEventGenericPacketSent>> events(event_count_);
+  for (size_t i = 0; i < event_count_; ++i) {
+    events[i] = (i == 0 || !force_repeated_fields_)
+                    ? gen_.NewGenericPacketSent()
+                    : events[0]->Copy();
+    history_.push_back(events[i]->Copy());
+  }
+
+  std::string encoded = encoder_->EncodeBatch(history_.begin(), history_.end());
+  ASSERT_TRUE(parsed_log_.ParseString(encoded));
+
+  const auto& packets_sent = parsed_log_.generic_packets_sent();
+  ASSERT_EQ(packets_sent.size(), event_count_);
+
+  for (size_t i = 0; i < event_count_; ++i) {
+    verifier_.VerifyLoggedGenericPacketSent(*events[i], packets_sent[i]);
+  }
+}
+
+TEST_P(RtcEventLogEncoderTest, RtcEventGenericAcksReceived) {
+  if (!new_encoding_) {
+    return;
+  }
+  std::vector<std::unique_ptr<RtcEventGenericAckReceived>> events(event_count_);
+  for (size_t i = 0; i < event_count_; ++i) {
+    events[i] = (i == 0 || !force_repeated_fields_)
+                    ? gen_.NewGenericAckReceived()
+                    : events[0]->Copy();
+    history_.push_back(events[i]->Copy());
+  }
+
+  std::string encoded = encoder_->EncodeBatch(history_.begin(), history_.end());
+  ASSERT_TRUE(parsed_log_.ParseString(encoded));
+
+  const auto& decoded_events = parsed_log_.generic_acks_received();
+  ASSERT_EQ(decoded_events.size(), event_count_);
+
+  for (size_t i = 0; i < event_count_; ++i) {
+    verifier_.VerifyLoggedGenericAckReceived(*events[i], decoded_events[i]);
+  }
+}
+
 TEST_P(RtcEventLogEncoderTest, RtcEventDtlsTransportState) {
   std::vector<std::unique_ptr<RtcEventDtlsTransportState>> events(event_count_);
   for (size_t i = 0; i < event_count_; ++i) {
diff --git a/logging/rtc_event_log/events/rtc_event_generic_ack_received.cc b/logging/rtc_event_log/events/rtc_event_generic_ack_received.cc
index f158069..0149887 100644
--- a/logging/rtc_event_log/events/rtc_event_generic_ack_received.cc
+++ b/logging/rtc_event_log/events/rtc_event_generic_ack_received.cc
@@ -13,16 +13,17 @@
 #include <vector>
 
 namespace webrtc {
+
 std::vector<std::unique_ptr<RtcEventGenericAckReceived>>
 RtcEventGenericAckReceived::CreateLogs(
     int64_t packet_number,
-    const std::vector<AckedPacket> acked_packets) {
+    const std::vector<AckedPacket>& acked_packets) {
   std::vector<std::unique_ptr<RtcEventGenericAckReceived>> result;
   int64_t time_us = rtc::TimeMicros();
   for (const AckedPacket& packet : acked_packets) {
     result.push_back(absl::WrapUnique(new RtcEventGenericAckReceived(
         time_us, packet_number, packet.packet_number,
-        packet.receive_timestamp_ms)));
+        packet.receive_acked_packet_time_ms)));
   }
   return result;
 }
@@ -31,11 +32,19 @@
     int64_t timestamp_us,
     int64_t packet_number,
     int64_t acked_packet_number,
-    absl::optional<int64_t> receive_timestamp_ms)
+    absl::optional<int64_t> receive_acked_packet_time_ms)
     : RtcEvent(timestamp_us),
       packet_number_(packet_number),
       acked_packet_number_(acked_packet_number),
-      receive_timestamp_ms_(receive_timestamp_ms) {}
+      receive_acked_packet_time_ms_(receive_acked_packet_time_ms) {}
+
+std::unique_ptr<RtcEventGenericAckReceived> RtcEventGenericAckReceived::Copy()
+    const {
+  return absl::WrapUnique(new RtcEventGenericAckReceived(*this));
+}
+
+RtcEventGenericAckReceived::RtcEventGenericAckReceived(
+    const RtcEventGenericAckReceived& packet) = default;
 
 RtcEventGenericAckReceived::~RtcEventGenericAckReceived() = default;
 
diff --git a/logging/rtc_event_log/events/rtc_event_generic_ack_received.h b/logging/rtc_event_log/events/rtc_event_generic_ack_received.h
index 38b36e5..7d42bbd 100644
--- a/logging/rtc_event_log/events/rtc_event_generic_ack_received.h
+++ b/logging/rtc_event_log/events/rtc_event_generic_ack_received.h
@@ -24,7 +24,7 @@
 
   // The time where the packet was received. Not every ACK will
   // include the receive timestamp.
-  absl::optional<int64_t> receive_timestamp_ms;
+  absl::optional<int64_t> receive_acked_packet_time_ms;
 };
 
 class RtcEventGenericAckReceived final : public RtcEvent {
@@ -33,11 +33,12 @@
   // the same timestamp.
   static std::vector<std::unique_ptr<RtcEventGenericAckReceived>> CreateLogs(
       int64_t packet_number,
-      const std::vector<AckedPacket> acked_packets);
+      const std::vector<AckedPacket>& acked_packets);
 
-  RtcEventGenericAckReceived(const RtcEventGenericAckReceived& packet);
   ~RtcEventGenericAckReceived() override;
 
+  std::unique_ptr<RtcEventGenericAckReceived> Copy() const;
+
   Type GetType() const override;
 
   bool IsConfigEvent() const override;
@@ -48,24 +49,32 @@
   // An identifier of the acked packet.
   int64_t acked_packet_number() const { return acked_packet_number_; }
 
-  // Collection of the received acks with their timestamps.
-  const absl::optional<int64_t> receive_timestamp_ms() const {
-    return receive_timestamp_ms_;
+  // Timestamp when the |acked_packet_number| was received by the remote side.
+  absl::optional<int64_t> receive_timestamp_ms() const {
+    return receive_acked_packet_time_ms_;
+  }
+
+  absl::optional<int64_t> receive_acked_packet_time_ms() const {
+    return receive_acked_packet_time_ms_;
   }
 
  private:
+  RtcEventGenericAckReceived(const RtcEventGenericAckReceived& packet);
+
   // When the ack is received, |packet_number| identifies the packet which
   // contained an ack for |acked_packet_number|, and contains the
-  // |receive_timestamp_ms| on which the |acked_packet_number| was received on
-  // the remote side. The |receive_timestamp_ms| may be null.
-  RtcEventGenericAckReceived(int64_t timestamp_us,
-                             int64_t packet_number,
-                             int64_t acked_packet_number,
-                             absl::optional<int64_t> receive_timestamp_ms);
+  // |receive_acked_packet_time_ms| on which the |acked_packet_number| was
+  // received on the remote side. The |receive_acked_packet_time_ms| may be
+  // null.
+  RtcEventGenericAckReceived(
+      int64_t timestamp_us,
+      int64_t packet_number,
+      int64_t acked_packet_number,
+      absl::optional<int64_t> receive_acked_packet_time_ms);
 
   const int64_t packet_number_;
   const int64_t acked_packet_number_;
-  const absl::optional<int64_t> receive_timestamp_ms_;
+  const absl::optional<int64_t> receive_acked_packet_time_ms_;
 };
 
 }  // namespace webrtc
diff --git a/logging/rtc_event_log/events/rtc_event_generic_packet_received.cc b/logging/rtc_event_log/events/rtc_event_generic_packet_received.cc
index 6a75cf2..9b87f14 100644
--- a/logging/rtc_event_log/events/rtc_event_generic_packet_received.cc
+++ b/logging/rtc_event_log/events/rtc_event_generic_packet_received.cc
@@ -17,8 +17,15 @@
     size_t packet_length)
     : packet_number_(packet_number), packet_length_(packet_length) {}
 
+RtcEventGenericPacketReceived::RtcEventGenericPacketReceived(
+    const RtcEventGenericPacketReceived& packet) = default;
+
 RtcEventGenericPacketReceived::~RtcEventGenericPacketReceived() = default;
 
+std::unique_ptr<RtcEventGenericPacketReceived>
+RtcEventGenericPacketReceived::Copy() const {
+  return absl::WrapUnique(new RtcEventGenericPacketReceived(*this));
+}
 RtcEvent::Type RtcEventGenericPacketReceived::GetType() const {
   return RtcEvent::Type::GenericPacketReceived;
 }
diff --git a/logging/rtc_event_log/events/rtc_event_generic_packet_received.h b/logging/rtc_event_log/events/rtc_event_generic_packet_received.h
index a7f95bc..9b16d88 100644
--- a/logging/rtc_event_log/events/rtc_event_generic_packet_received.h
+++ b/logging/rtc_event_log/events/rtc_event_generic_packet_received.h
@@ -11,6 +11,8 @@
 #ifndef LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_GENERIC_PACKET_RECEIVED_H_
 #define LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_GENERIC_PACKET_RECEIVED_H_
 
+#include <memory>
+
 #include "logging/rtc_event_log/events/rtc_event.h"
 
 namespace webrtc {
@@ -18,9 +20,10 @@
 class RtcEventGenericPacketReceived final : public RtcEvent {
  public:
   RtcEventGenericPacketReceived(int64_t packet_number, size_t packet_length);
-  RtcEventGenericPacketReceived(const RtcEventGenericPacketReceived& packet);
   ~RtcEventGenericPacketReceived() override;
 
+  std::unique_ptr<RtcEventGenericPacketReceived> Copy() const;
+
   Type GetType() const override;
 
   bool IsConfigEvent() const override;
@@ -33,6 +36,8 @@
   size_t packet_length() const { return packet_length_; }
 
  private:
+  RtcEventGenericPacketReceived(const RtcEventGenericPacketReceived& packet);
+
   const int64_t packet_number_;
   const size_t packet_length_;
 };
diff --git a/logging/rtc_event_log/events/rtc_event_generic_packet_sent.cc b/logging/rtc_event_log/events/rtc_event_generic_packet_sent.cc
index 25cc74e..f640d09 100644
--- a/logging/rtc_event_log/events/rtc_event_generic_packet_sent.cc
+++ b/logging/rtc_event_log/events/rtc_event_generic_packet_sent.cc
@@ -21,8 +21,16 @@
       payload_length_(payload_length),
       padding_length_(padding_length) {}
 
+RtcEventGenericPacketSent::RtcEventGenericPacketSent(
+    const RtcEventGenericPacketSent& packet) = default;
+
 RtcEventGenericPacketSent::~RtcEventGenericPacketSent() = default;
 
+std::unique_ptr<RtcEventGenericPacketSent> RtcEventGenericPacketSent::Copy()
+    const {
+  return absl::WrapUnique(new RtcEventGenericPacketSent(*this));
+}
+
 RtcEvent::Type RtcEventGenericPacketSent::GetType() const {
   return RtcEvent::Type::GenericPacketSent;
 }
diff --git a/logging/rtc_event_log/events/rtc_event_generic_packet_sent.h b/logging/rtc_event_log/events/rtc_event_generic_packet_sent.h
index 02528a0..3893680 100644
--- a/logging/rtc_event_log/events/rtc_event_generic_packet_sent.h
+++ b/logging/rtc_event_log/events/rtc_event_generic_packet_sent.h
@@ -11,6 +11,8 @@
 #ifndef LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_GENERIC_PACKET_SENT_H_
 #define LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_GENERIC_PACKET_SENT_H_
 
+#include <memory>
+
 #include "logging/rtc_event_log/events/rtc_event.h"
 
 namespace webrtc {
@@ -21,9 +23,10 @@
                             size_t overhead_length,
                             size_t payload_length,
                             size_t padding_length);
-  RtcEventGenericPacketSent(const RtcEventGenericPacketSent& packet);
   ~RtcEventGenericPacketSent() override;
 
+  std::unique_ptr<RtcEventGenericPacketSent> Copy() const;
+
   Type GetType() const override;
 
   bool IsConfigEvent() const override;
@@ -48,6 +51,8 @@
   size_t padding_length() const { return padding_length_; }
 
  private:
+  RtcEventGenericPacketSent(const RtcEventGenericPacketSent& packet);
+
   const int64_t packet_number_;
   const size_t overhead_length_;
   const size_t payload_length_;
diff --git a/logging/rtc_event_log/logged_events.h b/logging/rtc_event_log/logged_events.h
index 83978e0..6fe6fe4 100644
--- a/logging/rtc_event_log/logged_events.h
+++ b/logging/rtc_event_log/logged_events.h
@@ -522,5 +522,65 @@
   LoggedIceEventType event_type;
 };
 
+struct LoggedGenericPacketSent {
+  LoggedGenericPacketSent() = default;
+  LoggedGenericPacketSent(int64_t timestamp_us,
+                          int64_t packet_number,
+                          size_t overhead_length,
+                          size_t payload_length,
+                          size_t padding_length)
+      : timestamp_us(timestamp_us),
+        packet_number(packet_number),
+        overhead_length(overhead_length),
+        payload_length(payload_length),
+        padding_length(padding_length) {}
+
+  int64_t log_time_us() const { return timestamp_us; }
+  int64_t log_time_ms() const { return timestamp_us / 1000; }
+
+  int64_t timestamp_us;
+  int64_t packet_number;
+  size_t overhead_length;
+  size_t payload_length;
+  size_t padding_length;
+};
+
+struct LoggedGenericPacketReceived {
+  LoggedGenericPacketReceived() = default;
+  LoggedGenericPacketReceived(int64_t timestamp_us,
+                              int64_t packet_number,
+                              int packet_length)
+      : timestamp_us(timestamp_us),
+        packet_number(packet_number),
+        packet_length(packet_length) {}
+
+  int64_t log_time_us() const { return timestamp_us; }
+  int64_t log_time_ms() const { return timestamp_us / 1000; }
+
+  int64_t timestamp_us;
+  int64_t packet_number;
+  int packet_length;
+};
+
+struct LoggedGenericAckReceived {
+  LoggedGenericAckReceived() = default;
+  LoggedGenericAckReceived(int64_t timestamp_us,
+                           int64_t packet_number,
+                           int64_t acked_packet_number,
+                           absl::optional<int64_t> receive_acked_packet_time_ms)
+      : timestamp_us(timestamp_us),
+        packet_number(packet_number),
+        acked_packet_number(acked_packet_number),
+        receive_acked_packet_time_ms(receive_acked_packet_time_ms) {}
+
+  int64_t log_time_us() const { return timestamp_us; }
+  int64_t log_time_ms() const { return timestamp_us / 1000; }
+
+  int64_t timestamp_us;
+  int64_t packet_number;
+  int64_t acked_packet_number;
+  absl::optional<int64_t> receive_acked_packet_time_ms;
+};
+
 }  // namespace webrtc
 #endif  // LOGGING_RTC_EVENT_LOG_LOGGED_EVENTS_H_
diff --git a/logging/rtc_event_log/rtc_event_log2.proto b/logging/rtc_event_log/rtc_event_log2.proto
index a8f2f9d..6f04c18 100644
--- a/logging/rtc_event_log/rtc_event_log2.proto
+++ b/logging/rtc_event_log/rtc_event_log2.proto
@@ -34,6 +34,9 @@
   repeated IceCandidatePairEvent ice_candidate_events = 26;
   repeated DtlsTransportStateEvent dtls_transport_state_events = 27;
   repeated DtlsWritableState dtls_writable_states = 28;
+  repeated GenericPacketSent generic_packets_sent = 29;
+  repeated GenericPacketReceived generic_packets_received = 30;
+  repeated GenericAckReceived generic_acks_received = 31;
 
   repeated AudioRecvStreamConfig audio_recv_stream_configs = 101;
   repeated AudioSendStreamConfig audio_send_stream_configs = 102;
@@ -46,6 +49,56 @@
   // TODO(terelius): Do we want to preserve the old Event definition here?
 }
 
+message GenericPacketReceived {
+  // All fields are required.
+  optional int64 timestamp_ms = 1;
+  optional int64 packet_number = 2;
+  // Length of the packet in bytes.
+  optional int32 packet_length = 3;
+
+  // Provided if there are deltas in the batch.
+  optional uint32 number_of_deltas = 16;
+  optional bytes timestamp_ms_deltas = 17;
+  optional bytes packet_number_deltas = 18;
+  optional bytes packet_length_deltas = 19;
+}
+
+message GenericPacketSent {
+  // All fields are required. All lengths in bytes.
+  optional int64 timestamp_ms = 1;
+  optional int64 packet_number = 2;
+  // overhead+payload+padding length = packet_length in bytes.
+  optional int32 overhead_length = 3;
+  optional int32 payload_length = 4;
+  optional int32 padding_length = 5;
+
+  optional uint32 number_of_deltas = 16;
+  optional bytes timestamp_ms_deltas = 17;
+  optional bytes packet_number_deltas = 18;
+  optional bytes overhead_length_deltas = 19;
+  optional bytes payload_length_deltas = 20;
+  optional bytes padding_length_deltas = 21;
+}
+
+message GenericAckReceived {
+  optional int64 timestamp_ms = 1;
+
+  // ID of the received packet.
+  optional int64 packet_number = 2;
+
+  // ID of the packet that was acked.
+  optional int64 acked_packet_number = 3;
+
+  // Timestamp in ms when the packet was received by the other side.
+  optional int64 receive_acked_packet_time_ms = 4;
+
+  optional uint32 number_of_deltas = 16;
+  optional bytes timestamp_ms_deltas = 17;
+  optional bytes packet_number_deltas = 18;
+  optional bytes acked_packet_number_deltas = 19;
+  optional bytes receive_acked_packet_time_ms_deltas = 20;
+}
+
 message IncomingRtpPackets {
   // required
   optional int64 timestamp_ms = 1;
diff --git a/logging/rtc_event_log/rtc_event_log_parser.cc b/logging/rtc_event_log/rtc_event_log_parser.cc
index d9ac876..1bf99d2 100644
--- a/logging/rtc_event_log/rtc_event_log_parser.cc
+++ b/logging/rtc_event_log/rtc_event_log_parser.cc
@@ -1134,6 +1134,9 @@
   }
   StoreFirstAndLastTimestamp(incoming_rtcp_packets());
   StoreFirstAndLastTimestamp(outgoing_rtcp_packets());
+  StoreFirstAndLastTimestamp(generic_packets_sent_);
+  StoreFirstAndLastTimestamp(generic_packets_received_);
+  StoreFirstAndLastTimestamp(generic_acks_received_);
 
   return success;
 }
@@ -2079,7 +2082,10 @@
           stream.audio_recv_stream_configs_size() +
           stream.audio_send_stream_configs_size() +
           stream.video_recv_stream_configs_size() +
-          stream.video_send_stream_configs_size(),
+          stream.video_send_stream_configs_size() +
+          stream.generic_packets_sent_size() +
+          stream.generic_packets_received_size() +
+          stream.generic_acks_received_size(),
       1u);
 
   if (stream.incoming_rtp_packets_size() == 1) {
@@ -2126,6 +2132,12 @@
     StoreVideoRecvConfig(stream.video_recv_stream_configs(0));
   } else if (stream.video_send_stream_configs_size() == 1) {
     StoreVideoSendConfig(stream.video_send_stream_configs(0));
+  } else if (stream.generic_packets_received_size() == 1) {
+    StoreGenericPacketReceivedEvent(stream.generic_packets_received(0));
+  } else if (stream.generic_packets_sent_size() == 1) {
+    StoreGenericPacketSentEvent(stream.generic_packets_sent(0));
+  } else if (stream.generic_acks_received_size() == 1) {
+    StoreGenericAckReceivedEvent(stream.generic_acks_received(0));
   } else {
     RTC_NOTREACHED();
   }
@@ -2398,6 +2410,190 @@
   // TODO(terelius): Should we delta encode this event type?
 }
 
+void ParsedRtcEventLog::StoreGenericAckReceivedEvent(
+    const rtclog2::GenericAckReceived& proto) {
+  RTC_CHECK(proto.has_timestamp_ms());
+  RTC_CHECK(proto.has_packet_number());
+  RTC_CHECK(proto.has_acked_packet_number());
+  // receive_acked_packet_time_ms is optional.
+
+  absl::optional<int64_t> base_receive_acked_packet_time_ms;
+  if (proto.has_receive_acked_packet_time_ms()) {
+    base_receive_acked_packet_time_ms = proto.receive_acked_packet_time_ms();
+  }
+  generic_acks_received_.push_back(
+      {proto.timestamp_ms() * 1000, proto.packet_number(),
+       proto.acked_packet_number(), base_receive_acked_packet_time_ms});
+
+  const size_t number_of_deltas =
+      proto.has_number_of_deltas() ? proto.number_of_deltas() : 0u;
+  if (number_of_deltas == 0) {
+    return;
+  }
+
+  // timestamp_ms
+  std::vector<absl::optional<uint64_t>> timestamp_ms_values =
+      DecodeDeltas(proto.timestamp_ms_deltas(),
+                   ToUnsigned(proto.timestamp_ms()), number_of_deltas);
+  RTC_CHECK_EQ(timestamp_ms_values.size(), number_of_deltas);
+
+  // packet_number
+  std::vector<absl::optional<uint64_t>> packet_number_values =
+      DecodeDeltas(proto.packet_number_deltas(),
+                   ToUnsigned(proto.packet_number()), number_of_deltas);
+  RTC_CHECK_EQ(packet_number_values.size(), number_of_deltas);
+
+  // acked_packet_number
+  std::vector<absl::optional<uint64_t>> acked_packet_number_values =
+      DecodeDeltas(proto.acked_packet_number_deltas(),
+                   ToUnsigned(proto.acked_packet_number()), number_of_deltas);
+  RTC_CHECK_EQ(acked_packet_number_values.size(), number_of_deltas);
+
+  // optional receive_acked_packet_time_ms
+  const absl::optional<uint64_t> unsigned_receive_acked_packet_time_ms_base =
+      proto.has_receive_acked_packet_time_ms()
+          ? absl::optional<uint64_t>(
+                ToUnsigned(proto.receive_acked_packet_time_ms()))
+          : absl::optional<uint64_t>();
+  std::vector<absl::optional<uint64_t>> receive_acked_packet_time_ms_values =
+      DecodeDeltas(proto.receive_acked_packet_time_ms_deltas(),
+                   unsigned_receive_acked_packet_time_ms_base,
+                   number_of_deltas);
+  RTC_CHECK_EQ(receive_acked_packet_time_ms_values.size(), number_of_deltas);
+
+  for (size_t i = 0; i < number_of_deltas; i++) {
+    int64_t timestamp_ms;
+    RTC_CHECK(ToSigned(timestamp_ms_values[i].value(), &timestamp_ms));
+    int64_t packet_number;
+    RTC_CHECK(ToSigned(packet_number_values[i].value(), &packet_number));
+    int64_t acked_packet_number;
+    RTC_CHECK(
+        ToSigned(acked_packet_number_values[i].value(), &acked_packet_number));
+    absl::optional<int64_t> receive_acked_packet_time_ms;
+
+    if (receive_acked_packet_time_ms_values[i].has_value()) {
+      int64_t value;
+      RTC_CHECK(
+          ToSigned(receive_acked_packet_time_ms_values[i].value(), &value));
+      receive_acked_packet_time_ms = value;
+    }
+    generic_acks_received_.push_back({timestamp_ms * 1000, packet_number,
+                                      acked_packet_number,
+                                      receive_acked_packet_time_ms});
+  }
+}
+
+void ParsedRtcEventLog::StoreGenericPacketSentEvent(
+    const rtclog2::GenericPacketSent& proto) {
+  RTC_CHECK(proto.has_timestamp_ms());
+
+  // Base event
+  RTC_CHECK(proto.has_packet_number());
+  RTC_CHECK(proto.has_overhead_length());
+  RTC_CHECK(proto.has_payload_length());
+  RTC_CHECK(proto.has_padding_length());
+
+  generic_packets_sent_.push_back(
+      {proto.timestamp_ms() * 1000, proto.packet_number(),
+       static_cast<size_t>(proto.overhead_length()),
+       static_cast<size_t>(proto.payload_length()),
+       static_cast<size_t>(proto.padding_length())});
+
+  const size_t number_of_deltas =
+      proto.has_number_of_deltas() ? proto.number_of_deltas() : 0u;
+  if (number_of_deltas == 0) {
+    return;
+  }
+
+  // timestamp_ms
+  std::vector<absl::optional<uint64_t>> timestamp_ms_values =
+      DecodeDeltas(proto.timestamp_ms_deltas(),
+                   ToUnsigned(proto.timestamp_ms()), number_of_deltas);
+  RTC_CHECK_EQ(timestamp_ms_values.size(), number_of_deltas);
+
+  // packet_number
+  std::vector<absl::optional<uint64_t>> packet_number_values =
+      DecodeDeltas(proto.packet_number_deltas(),
+                   ToUnsigned(proto.packet_number()), number_of_deltas);
+  RTC_CHECK_EQ(packet_number_values.size(), number_of_deltas);
+
+  std::vector<absl::optional<uint64_t>> overhead_length_values =
+      DecodeDeltas(proto.overhead_length_deltas(), proto.overhead_length(),
+                   number_of_deltas);
+  RTC_CHECK_EQ(overhead_length_values.size(), number_of_deltas);
+
+  std::vector<absl::optional<uint64_t>> payload_length_values =
+      DecodeDeltas(proto.payload_length_deltas(),
+                   ToUnsigned(proto.payload_length()), number_of_deltas);
+  RTC_CHECK_EQ(payload_length_values.size(), number_of_deltas);
+
+  std::vector<absl::optional<uint64_t>> padding_length_values =
+      DecodeDeltas(proto.padding_length_deltas(),
+                   ToUnsigned(proto.padding_length()), number_of_deltas);
+  RTC_CHECK_EQ(padding_length_values.size(), number_of_deltas);
+
+  for (size_t i = 0; i < number_of_deltas; i++) {
+    int64_t timestamp_ms;
+    RTC_CHECK(ToSigned(timestamp_ms_values[i].value(), &timestamp_ms));
+    int64_t packet_number;
+    RTC_CHECK(ToSigned(packet_number_values[i].value(), &packet_number));
+    RTC_CHECK(overhead_length_values[i].has_value());
+    RTC_CHECK(payload_length_values[i].has_value());
+    RTC_CHECK(padding_length_values[i].has_value());
+    generic_packets_sent_.push_back(
+        {timestamp_ms * 1000, packet_number,
+         static_cast<size_t>(overhead_length_values[i].value()),
+         static_cast<size_t>(payload_length_values[i].value()),
+         static_cast<size_t>(padding_length_values[i].value())});
+  }
+}
+
+void ParsedRtcEventLog::StoreGenericPacketReceivedEvent(
+    const rtclog2::GenericPacketReceived& proto) {
+  RTC_CHECK(proto.has_timestamp_ms());
+
+  // Base event
+  RTC_CHECK(proto.has_packet_number());
+  RTC_CHECK(proto.has_packet_length());
+
+  generic_packets_received_.push_back({proto.timestamp_ms() * 1000,
+                                       proto.packet_number(),
+                                       proto.packet_length()});
+
+  const size_t number_of_deltas =
+      proto.has_number_of_deltas() ? proto.number_of_deltas() : 0u;
+  if (number_of_deltas == 0) {
+    return;
+  }
+
+  // timestamp_ms
+  std::vector<absl::optional<uint64_t>> timestamp_ms_values =
+      DecodeDeltas(proto.timestamp_ms_deltas(),
+                   ToUnsigned(proto.timestamp_ms()), number_of_deltas);
+  RTC_CHECK_EQ(timestamp_ms_values.size(), number_of_deltas);
+
+  // packet_number
+  std::vector<absl::optional<uint64_t>> packet_number_values =
+      DecodeDeltas(proto.packet_number_deltas(),
+                   ToUnsigned(proto.packet_number()), number_of_deltas);
+  RTC_CHECK_EQ(packet_number_values.size(), number_of_deltas);
+
+  std::vector<absl::optional<uint64_t>> packet_length_values = DecodeDeltas(
+      proto.packet_length_deltas(), proto.packet_length(), number_of_deltas);
+  RTC_CHECK_EQ(packet_length_values.size(), number_of_deltas);
+
+  for (size_t i = 0; i < number_of_deltas; i++) {
+    int64_t timestamp_ms;
+    RTC_CHECK(ToSigned(timestamp_ms_values[i].value(), &timestamp_ms));
+    int64_t packet_number;
+    RTC_CHECK(ToSigned(packet_number_values[i].value(), &packet_number));
+    int32_t packet_length;
+    RTC_CHECK(ToSigned(packet_length_values[i].value(), &packet_length));
+    generic_packets_received_.push_back(
+        {timestamp_ms * 1000, packet_number, packet_length});
+  }
+}
+
 void ParsedRtcEventLog::StoreAudioNetworkAdaptationEvent(
     const rtclog2::AudioNetworkAdaptations& proto) {
   RTC_CHECK(proto.has_timestamp_ms());
diff --git a/logging/rtc_event_log/rtc_event_log_parser.h b/logging/rtc_event_log/rtc_event_log_parser.h
index d0c15a1..3ed5d41 100644
--- a/logging/rtc_event_log/rtc_event_log_parser.h
+++ b/logging/rtc_event_log/rtc_event_log_parser.h
@@ -470,6 +470,17 @@
     }
   }
 
+  const std::vector<LoggedGenericPacketReceived>& generic_packets_received() {
+    return generic_packets_received_;
+  }
+  const std::vector<LoggedGenericPacketSent>& generic_packets_sent() {
+    return generic_packets_sent_;
+  }
+
+  const std::vector<LoggedGenericAckReceived>& generic_acks_received() {
+    return generic_acks_received_;
+  }
+
   int64_t first_timestamp() const { return first_timestamp_; }
   int64_t last_timestamp() const { return last_timestamp_; }
 
@@ -578,6 +589,10 @@
   void StoreAudioSendConfig(const rtclog2::AudioSendStreamConfig& proto);
   void StoreVideoRecvConfig(const rtclog2::VideoRecvStreamConfig& proto);
   void StoreVideoSendConfig(const rtclog2::VideoSendStreamConfig& proto);
+  void StoreGenericPacketReceivedEvent(
+      const rtclog2::GenericPacketReceived& proto);
+  void StoreGenericPacketSentEvent(const rtclog2::GenericPacketSent& proto);
+  void StoreGenericAckReceivedEvent(const rtclog2::GenericAckReceived& proto);
   // End of new parsing functions.
 
   struct Stream {
@@ -678,6 +693,10 @@
   std::vector<LoggedVideoRecvConfig> video_recv_configs_;
   std::vector<LoggedVideoSendConfig> video_send_configs_;
 
+  std::vector<LoggedGenericPacketReceived> generic_packets_received_;
+  std::vector<LoggedGenericPacketSent> generic_packets_sent_;
+  std::vector<LoggedGenericAckReceived> generic_acks_received_;
+
   uint8_t last_incoming_rtcp_packet_[IP_PACKET_SIZE];
   uint8_t last_incoming_rtcp_packet_length_;
 
diff --git a/logging/rtc_event_log/rtc_event_log_unittest.cc b/logging/rtc_event_log/rtc_event_log_unittest.cc
index 103789d..05d519b 100644
--- a/logging/rtc_event_log/rtc_event_log_unittest.cc
+++ b/logging/rtc_event_log/rtc_event_log_unittest.cc
@@ -26,6 +26,9 @@
 #include "logging/rtc_event_log/events/rtc_event_bwe_update_loss_based.h"
 #include "logging/rtc_event_log/events/rtc_event_dtls_transport_state.h"
 #include "logging/rtc_event_log/events/rtc_event_dtls_writable_state.h"
+#include "logging/rtc_event_log/events/rtc_event_generic_ack_received.h"
+#include "logging/rtc_event_log/events/rtc_event_generic_packet_received.h"
+#include "logging/rtc_event_log/events/rtc_event_generic_packet_sent.h"
 #include "logging/rtc_event_log/events/rtc_event_probe_cluster_created.h"
 #include "logging/rtc_event_log/events/rtc_event_probe_result_failure.h"
 #include "logging/rtc_event_log/events/rtc_event_probe_result_success.h"
@@ -73,13 +76,18 @@
   size_t outgoing_rtp_packets = 0;
   size_t incoming_rtcp_packets = 0;
   size_t outgoing_rtcp_packets = 0;
+  size_t generic_packets_sent = 0;
+  size_t generic_packets_received = 0;
+  size_t generic_acks_received = 0;
 
   size_t total_nonconfig_events() const {
     return alr_states + audio_playouts + ana_configs + bwe_loss_events +
            bwe_delay_events + dtls_transport_states + dtls_writable_states +
            probe_creations + probe_successes + probe_failures + ice_configs +
            ice_events + incoming_rtp_packets + outgoing_rtp_packets +
-           incoming_rtcp_packets + outgoing_rtcp_packets;
+           incoming_rtcp_packets + outgoing_rtcp_packets +
+           generic_packets_sent + generic_packets_received +
+           generic_acks_received;
   }
 
   size_t total_config_events() const {
@@ -120,6 +128,10 @@
   void WriteLog(EventCounts count, size_t num_events_before_log_start);
   void ReadAndVerifyLog();
 
+  bool IsNewFormat() {
+    return encoding_type_ == RtcEventLog::EncodingType::NewFormat;
+  }
+
  private:
   void WriteAudioRecvConfigs(size_t audio_recv_streams, RtcEventLog* event_log);
   void WriteAudioSendConfigs(size_t audio_send_streams, RtcEventLog* event_log);
@@ -163,6 +175,11 @@
       outgoing_rtp_map_;  // Groups outgoing RTP by SSRC.
   std::vector<std::unique_ptr<RtcEventRtcpPacketIncoming>> incoming_rtcp_list_;
   std::vector<std::unique_ptr<RtcEventRtcpPacketOutgoing>> outgoing_rtcp_list_;
+  std::vector<std::unique_ptr<RtcEventGenericPacketSent>> generic_packets_sent_;
+  std::vector<std::unique_ptr<RtcEventGenericPacketReceived>>
+      generic_packets_received_;
+  std::vector<std::unique_ptr<RtcEventGenericAckReceived>>
+      generic_acks_received_;
 
   int64_t start_time_us_;
   int64_t utc_start_time_us_;
@@ -471,6 +488,33 @@
     }
     selection -= count.outgoing_rtcp_packets;
 
+    if (selection < count.generic_packets_sent) {
+      auto event = gen_.NewGenericPacketSent();
+      generic_packets_sent_.push_back(event->Copy());
+      event_log->Log(std::move(event));
+      count.generic_packets_sent--;
+      continue;
+    }
+    selection -= count.generic_packets_sent;
+
+    if (selection < count.generic_packets_received) {
+      auto event = gen_.NewGenericPacketReceived();
+      generic_packets_received_.push_back(event->Copy());
+      event_log->Log(std::move(event));
+      count.generic_packets_received--;
+      continue;
+    }
+    selection -= count.generic_packets_received;
+
+    if (selection < count.generic_acks_received) {
+      auto event = gen_.NewGenericAckReceived();
+      generic_acks_received_.push_back(event->Copy());
+      event_log->Log(std::move(event));
+      count.generic_acks_received--;
+      continue;
+    }
+    selection -= count.generic_acks_received;
+
     RTC_NOTREACHED();
   }
 
@@ -648,6 +692,28 @@
                                           parsed_video_send_configs[i]);
   }
 
+  auto& parsed_generic_packets_received = parsed_log.generic_packets_received();
+  ASSERT_EQ(parsed_generic_packets_received.size(),
+            generic_packets_received_.size());
+  for (size_t i = 0; i < parsed_generic_packets_received.size(); i++) {
+    verifier_.VerifyLoggedGenericPacketReceived(
+        *generic_packets_received_[i], parsed_generic_packets_received[i]);
+  }
+
+  auto& parsed_generic_packets_sent = parsed_log.generic_packets_sent();
+  ASSERT_EQ(parsed_generic_packets_sent.size(), generic_packets_sent_.size());
+  for (size_t i = 0; i < parsed_generic_packets_sent.size(); i++) {
+    verifier_.VerifyLoggedGenericPacketSent(*generic_packets_sent_[i],
+                                            parsed_generic_packets_sent[i]);
+  }
+
+  auto& parsed_generic_acks_received = parsed_log.generic_acks_received();
+  ASSERT_EQ(parsed_generic_acks_received.size(), generic_acks_received_.size());
+  for (size_t i = 0; i < parsed_generic_acks_received.size(); i++) {
+    verifier_.VerifyLoggedGenericAckReceived(*generic_acks_received_[i],
+                                             parsed_generic_acks_received[i]);
+  }
+
   EXPECT_EQ(first_timestamp_ms_, parsed_log.first_timestamp() / 1000);
   EXPECT_EQ(last_timestamp_ms_, parsed_log.last_timestamp() / 1000);
 
@@ -679,6 +745,11 @@
   count.outgoing_rtp_packets = 100;
   count.incoming_rtcp_packets = 20;
   count.outgoing_rtcp_packets = 20;
+  if (IsNewFormat()) {
+    count.generic_packets_sent = 100;
+    count.generic_packets_received = 100;
+    count.generic_acks_received = 20;
+  }
 
   WriteLog(count, 0);
   ReadAndVerifyLog();
@@ -706,6 +777,11 @@
   count.outgoing_rtp_packets = 500;
   count.incoming_rtcp_packets = 50;
   count.outgoing_rtcp_packets = 50;
+  if (IsNewFormat()) {
+    count.generic_packets_sent = 500;
+    count.generic_packets_received = 500;
+    count.generic_acks_received = 50;
+  }
 
   WriteLog(count, 500);
   ReadAndVerifyLog();
diff --git a/logging/rtc_event_log/rtc_event_log_unittest_helper.cc b/logging/rtc_event_log/rtc_event_log_unittest_helper.cc
index dc694b5..10dd414 100644
--- a/logging/rtc_event_log/rtc_event_log_unittest_helper.cc
+++ b/logging/rtc_event_log/rtc_event_log_unittest_helper.cc
@@ -397,6 +397,28 @@
   }
 }
 
+std::unique_ptr<RtcEventGenericPacketSent>
+EventGenerator::NewGenericPacketSent() {
+  return absl::make_unique<RtcEventGenericPacketSent>(
+      sent_packet_number_++, prng_.Rand(40, 50), prng_.Rand(0, 150),
+      prng_.Rand(0, 1000));
+}
+std::unique_ptr<RtcEventGenericPacketReceived>
+EventGenerator::NewGenericPacketReceived() {
+  return absl::make_unique<RtcEventGenericPacketReceived>(
+      received_packet_number_++, prng_.Rand(40, 250));
+}
+std::unique_ptr<RtcEventGenericAckReceived>
+EventGenerator::NewGenericAckReceived() {
+  absl::optional<int64_t> receive_timestamp = absl::nullopt;
+  if (prng_.Rand(0, 2) > 0) {
+    receive_timestamp = prng_.Rand(0, 100000);
+  }
+  AckedPacket packet = {prng_.Rand(40, 250), receive_timestamp};
+  return std::move(RtcEventGenericAckReceived::CreateLogs(
+      received_packet_number_++, std::vector<AckedPacket>{packet})[0]);
+}
+
 void EventGenerator::RandomizeRtpPacket(
     size_t payload_size,
     size_t padding_size,
@@ -857,6 +879,36 @@
   VerifyLoggedRtpHeader(original_event.header(), logged_event.rtp.header);
 }
 
+void EventVerifier::VerifyLoggedGenericPacketSent(
+    const RtcEventGenericPacketSent& original_event,
+    const LoggedGenericPacketSent& logged_event) const {
+  EXPECT_EQ(original_event.timestamp_ms(), logged_event.log_time_ms());
+  EXPECT_EQ(original_event.packet_number(), logged_event.packet_number);
+  EXPECT_EQ(original_event.overhead_length(), logged_event.overhead_length);
+  EXPECT_EQ(original_event.payload_length(), logged_event.payload_length);
+  EXPECT_EQ(original_event.padding_length(), logged_event.padding_length);
+}
+
+void EventVerifier::VerifyLoggedGenericPacketReceived(
+    const RtcEventGenericPacketReceived& original_event,
+    const LoggedGenericPacketReceived& logged_event) const {
+  EXPECT_EQ(original_event.timestamp_ms(), logged_event.log_time_ms());
+  EXPECT_EQ(original_event.packet_number(), logged_event.packet_number);
+  EXPECT_EQ(static_cast<int>(original_event.packet_length()),
+            logged_event.packet_length);
+}
+
+void EventVerifier::VerifyLoggedGenericAckReceived(
+    const RtcEventGenericAckReceived& original_event,
+    const LoggedGenericAckReceived& logged_event) const {
+  EXPECT_EQ(original_event.timestamp_ms(), logged_event.log_time_ms());
+  EXPECT_EQ(original_event.packet_number(), logged_event.packet_number);
+  EXPECT_EQ(original_event.acked_packet_number(),
+            logged_event.acked_packet_number);
+  EXPECT_EQ(original_event.receive_acked_packet_time_ms(),
+            logged_event.receive_acked_packet_time_ms);
+}
+
 void EventVerifier::VerifyLoggedRtcpPacketIncoming(
     const RtcEventRtcpPacketIncoming& original_event,
     const LoggedRtcpPacketIncoming& logged_event) const {
diff --git a/logging/rtc_event_log/rtc_event_log_unittest_helper.h b/logging/rtc_event_log/rtc_event_log_unittest_helper.h
index 2a05ac5..b0e5117 100644
--- a/logging/rtc_event_log/rtc_event_log_unittest_helper.h
+++ b/logging/rtc_event_log/rtc_event_log_unittest_helper.h
@@ -24,6 +24,9 @@
 #include "logging/rtc_event_log/events/rtc_event_bwe_update_loss_based.h"
 #include "logging/rtc_event_log/events/rtc_event_dtls_transport_state.h"
 #include "logging/rtc_event_log/events/rtc_event_dtls_writable_state.h"
+#include "logging/rtc_event_log/events/rtc_event_generic_ack_received.h"
+#include "logging/rtc_event_log/events/rtc_event_generic_packet_received.h"
+#include "logging/rtc_event_log/events/rtc_event_generic_packet_sent.h"
 #include "logging/rtc_event_log/events/rtc_event_ice_candidate_pair.h"
 #include "logging/rtc_event_log/events/rtc_event_ice_candidate_pair_config.h"
 #include "logging/rtc_event_log/events/rtc_event_probe_cluster_created.h"
@@ -81,6 +84,10 @@
 
   std::unique_ptr<RtcEventRtcpPacketOutgoing> NewRtcpPacketOutgoing();
 
+  std::unique_ptr<RtcEventGenericPacketSent> NewGenericPacketSent();
+  std::unique_ptr<RtcEventGenericPacketReceived> NewGenericPacketReceived();
+  std::unique_ptr<RtcEventGenericAckReceived> NewGenericAckReceived();
+
   rtcp::SenderReport NewSenderReport();
   rtcp::ReceiverReport NewReceiverReport();
   rtcp::Nack NewNack();
@@ -133,6 +140,8 @@
 
  private:
   rtcp::ReportBlock NewReportBlock();
+  int sent_packet_number_ = 0;
+  int received_packet_number_ = 0;
 
   Random prng_;
 };
@@ -197,6 +206,18 @@
       const RtcEventRtpPacketOutgoing& original_event,
       const LoggedRtpPacketOutgoing& logged_event) const;
 
+  void VerifyLoggedGenericPacketSent(
+      const RtcEventGenericPacketSent& original_event,
+      const LoggedGenericPacketSent& logged_event) const;
+
+  void VerifyLoggedGenericPacketReceived(
+      const RtcEventGenericPacketReceived& original_event,
+      const LoggedGenericPacketReceived& logged_event) const;
+
+  void VerifyLoggedGenericAckReceived(
+      const RtcEventGenericAckReceived& original_event,
+      const LoggedGenericAckReceived& logged_event) const;
+
   template <typename EventType, typename ParsedType>
   void VerifyLoggedRtpPacket(const EventType& original_event,
                              const ParsedType& logged_event) {