Adds route changes in event logs.

Bug: webrtc:10614
Change-Id: Ifd859c977fc66cb606914ddb38a3fb3618e3ad90
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/135952
Commit-Queue: Sebastian Jansson <srte@webrtc.org>
Reviewed-by: Björn Terelius <terelius@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#27924}
diff --git a/call/BUILD.gn b/call/BUILD.gn
index dc89ab89..64cba50 100644
--- a/call/BUILD.gn
+++ b/call/BUILD.gn
@@ -136,6 +136,7 @@
     "../api/units:timestamp",
     "../api/video:video_frame",
     "../api/video_codecs:video_codecs_api",
+    "../logging:rtc_event_bwe",
     "../logging:rtc_event_log_api",
     "../modules/congestion_controller",
     "../modules/congestion_controller/rtp:control_handler",
diff --git a/call/rtp_transport_controller_send.cc b/call/rtp_transport_controller_send.cc
index 7c8c4c3..48a7736 100644
--- a/call/rtp_transport_controller_send.cc
+++ b/call/rtp_transport_controller_send.cc
@@ -19,6 +19,7 @@
 #include "api/units/timestamp.h"
 #include "call/rtp_transport_controller_send.h"
 #include "call/rtp_video_sender.h"
+#include "logging/rtc_event_log/events/rtc_event_route_change.h"
 #include "rtc_base/checks.h"
 #include "rtc_base/location.h"
 #include "rtc_base/logging.h"
@@ -64,6 +65,7 @@
     std::unique_ptr<ProcessThread> process_thread,
     TaskQueueFactory* task_queue_factory)
     : clock_(clock),
+      event_log_(event_log),
       pacer_(clock, &packet_router_, event_log),
       bitrate_configurator_(bitrate_config),
       process_thread_(std::move(process_thread)),
@@ -244,6 +246,10 @@
           network_route.local_network_id, network_route.remote_network_id);
     transport_overhead_bytes_per_packet_ = network_route.packet_overhead;
 
+    if (event_log_) {
+      event_log_->Log(absl::make_unique<RtcEventRouteChange>(
+          network_route.connected, network_route.packet_overhead));
+    }
     NetworkRouteChange msg;
     msg.at_time = Timestamp::ms(clock_->TimeInMilliseconds());
     msg.constraints = ConvertConstraints(bitrate_config, clock_);
diff --git a/call/rtp_transport_controller_send.h b/call/rtp_transport_controller_send.h
index 78617af..71608fe 100644
--- a/call/rtp_transport_controller_send.h
+++ b/call/rtp_transport_controller_send.h
@@ -129,6 +129,7 @@
   void UpdateControlState() RTC_RUN_ON(task_queue_);
 
   Clock* const clock_;
+  RtcEventLog* const event_log_;
   const FieldTrialBasedConfig trial_based_config_;
   PacketRouter packet_router_;
   std::vector<std::unique_ptr<RtpVideoSenderInterface>> video_rtp_senders_;
diff --git a/logging/BUILD.gn b/logging/BUILD.gn
index 6dc833f..13f3f34 100644
--- a/logging/BUILD.gn
+++ b/logging/BUILD.gn
@@ -105,6 +105,8 @@
     "rtc_event_log/events/rtc_event_probe_result_failure.h",
     "rtc_event_log/events/rtc_event_probe_result_success.cc",
     "rtc_event_log/events/rtc_event_probe_result_success.h",
+    "rtc_event_log/events/rtc_event_route_change.cc",
+    "rtc_event_log/events/rtc_event_route_change.h",
   ]
 
   deps = [
diff --git a/logging/rtc_event_log/encoder/rtc_event_log_encoder_legacy.cc b/logging/rtc_event_log/encoder/rtc_event_log_encoder_legacy.cc
index dac054c..ec39bf3 100644
--- a/logging/rtc_event_log/encoder/rtc_event_log_encoder_legacy.cc
+++ b/logging/rtc_event_log/encoder/rtc_event_log_encoder_legacy.cc
@@ -362,6 +362,7 @@
           static_cast<const RtcEventVideoSendStreamConfig&>(event);
       return EncodeVideoSendStreamConfig(rtc_event);
     }
+    case RtcEvent::Type::RouteChangeEvent:
     case RtcEvent::Type::GenericPacketReceived:
     case RtcEvent::Type::GenericPacketSent:
     case RtcEvent::Type::GenericAckReceived:
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 da8f787..d397680 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
@@ -32,6 +32,7 @@
 #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"
+#include "logging/rtc_event_log/events/rtc_event_route_change.h"
 #include "logging/rtc_event_log/events/rtc_event_rtcp_packet_incoming.h"
 #include "logging/rtc_event_log/events/rtc_event_rtcp_packet_outgoing.h"
 #include "logging/rtc_event_log/events/rtc_event_rtp_packet_incoming.h"
@@ -675,10 +676,16 @@
     std::vector<const RtcEventBweUpdateLossBased*> bwe_loss_based_updates;
     std::vector<const RtcEventDtlsTransportState*> dtls_transport_states;
     std::vector<const RtcEventDtlsWritableState*> dtls_writable_states;
+    std::vector<const RtcEventGenericAckReceived*> generic_acks_received;
+    std::vector<const RtcEventGenericPacketReceived*> generic_packets_received;
+    std::vector<const RtcEventGenericPacketSent*> generic_packets_sent;
+    std::vector<const RtcEventIceCandidatePair*> ice_candidate_events;
+    std::vector<const RtcEventIceCandidatePairConfig*> ice_candidate_configs;
     std::vector<const RtcEventProbeClusterCreated*>
         probe_cluster_created_events;
     std::vector<const RtcEventProbeResultFailure*> probe_result_failure_events;
     std::vector<const RtcEventProbeResultSuccess*> probe_result_success_events;
+    std::vector<const RtcEventRouteChange*> route_change_events;
     std::vector<const RtcEventRtcpPacketIncoming*> incoming_rtcp_packets;
     std::vector<const RtcEventRtcpPacketOutgoing*> outgoing_rtcp_packets;
     std::map<uint32_t /* SSRC */, std::vector<const RtcEventRtpPacketIncoming*>>
@@ -688,11 +695,6 @@
     std::vector<const RtcEventVideoReceiveStreamConfig*>
         video_recv_stream_configs;
     std::vector<const RtcEventVideoSendStreamConfig*> video_send_stream_configs;
-    std::vector<const RtcEventIceCandidatePairConfig*> ice_candidate_configs;
-    std::vector<const RtcEventIceCandidatePair*> ice_candidate_events;
-    std::vector<const RtcEventGenericPacketReceived*> generic_packets_received;
-    std::vector<const RtcEventGenericPacketSent*> generic_packets_sent;
-    std::vector<const RtcEventGenericAckReceived*> generic_acks_received;
 
     for (auto it = begin; it != end; ++it) {
       switch ((*it)->GetType()) {
@@ -771,6 +773,12 @@
           probe_result_success_events.push_back(rtc_event);
           break;
         }
+        case RtcEvent::Type::RouteChangeEvent: {
+          auto* rtc_event =
+              static_cast<const RtcEventRouteChange* const>(it->get());
+          route_change_events.push_back(rtc_event);
+          break;
+        }
         case RtcEvent::Type::RtcpPacketIncoming: {
           auto* rtc_event =
               static_cast<const RtcEventRtcpPacketIncoming* const>(it->get());
@@ -856,20 +864,21 @@
     EncodeBweUpdateLossBased(bwe_loss_based_updates, &event_stream);
     EncodeDtlsTransportState(dtls_transport_states, &event_stream);
     EncodeDtlsWritableState(dtls_writable_states, &event_stream);
+    EncodeGenericAcksReceived(generic_acks_received, &event_stream);
+    EncodeGenericPacketsReceived(generic_packets_received, &event_stream);
+    EncodeGenericPacketsSent(generic_packets_sent, &event_stream);
+    EncodeIceCandidatePairConfig(ice_candidate_configs, &event_stream);
+    EncodeIceCandidatePairEvent(ice_candidate_events, &event_stream);
     EncodeProbeClusterCreated(probe_cluster_created_events, &event_stream);
     EncodeProbeResultFailure(probe_result_failure_events, &event_stream);
     EncodeProbeResultSuccess(probe_result_success_events, &event_stream);
+    EncodeRouteChange(route_change_events, &event_stream);
     EncodeRtcpPacketIncoming(incoming_rtcp_packets, &event_stream);
     EncodeRtcpPacketOutgoing(outgoing_rtcp_packets, &event_stream);
     EncodeRtpPacketIncoming(incoming_rtp_packets, &event_stream);
     EncodeRtpPacketOutgoing(outgoing_rtp_packets, &event_stream);
     EncodeVideoRecvStreamConfig(video_recv_stream_configs, &event_stream);
     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();
@@ -1301,6 +1310,18 @@
   // TODO(terelius): Should we delta-compress this event type?
 }
 
+void RtcEventLogEncoderNewFormat::EncodeRouteChange(
+    rtc::ArrayView<const RtcEventRouteChange*> batch,
+    rtclog2::EventStream* event_stream) {
+  for (const RtcEventRouteChange* base_event : batch) {
+    rtclog2::RouteChange* proto_batch = event_stream->add_route_changes();
+    proto_batch->set_timestamp_ms(base_event->timestamp_ms());
+    proto_batch->set_connected(base_event->connected());
+    proto_batch->set_overhead(base_event->overhead());
+  }
+  // TODO(terelius): Should we delta-compress this event type?
+}
+
 void RtcEventLogEncoderNewFormat::EncodeRtcpPacketIncoming(
     rtc::ArrayView<const RtcEventRtcpPacketIncoming*> batch,
     rtclog2::EventStream* event_stream) {
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 3490ce6..7b410e5 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
@@ -27,6 +27,7 @@
 }  // namespace rtclog2
 
 class RtcEventAlrState;
+class RtcEventRouteChange;
 class RtcEventAudioNetworkAdaptation;
 class RtcEventAudioPlayout;
 class RtcEventAudioReceiveStreamConfig;
@@ -92,6 +93,21 @@
   void EncodeDtlsWritableState(
       rtc::ArrayView<const RtcEventDtlsWritableState*> 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 EncodeIceCandidatePairConfig(
+      rtc::ArrayView<const RtcEventIceCandidatePairConfig*> batch,
+      rtclog2::EventStream* event_stream);
+  void EncodeIceCandidatePairEvent(
+      rtc::ArrayView<const RtcEventIceCandidatePair*> batch,
+      rtclog2::EventStream* event_stream);
   void EncodeLoggingStarted(rtc::ArrayView<const RtcEventLoggingStarted*> batch,
                             rtclog2::EventStream* event_stream);
   void EncodeLoggingStopped(rtc::ArrayView<const RtcEventLoggingStopped*> batch,
@@ -105,6 +121,8 @@
   void EncodeProbeResultSuccess(
       rtc::ArrayView<const RtcEventProbeResultSuccess*> batch,
       rtclog2::EventStream* event_stream);
+  void EncodeRouteChange(rtc::ArrayView<const RtcEventRouteChange*> batch,
+                         rtclog2::EventStream* event_stream);
   void EncodeRtcpPacketIncoming(
       rtc::ArrayView<const RtcEventRtcpPacketIncoming*> batch,
       rtclog2::EventStream* event_stream);
@@ -119,27 +137,12 @@
       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);
   void EncodeVideoSendStreamConfig(
       rtc::ArrayView<const RtcEventVideoSendStreamConfig*> batch,
       rtclog2::EventStream* event_stream);
-  void EncodeIceCandidatePairConfig(
-      rtc::ArrayView<const RtcEventIceCandidatePairConfig*> batch,
-      rtclog2::EventStream* event_stream);
-  void EncodeIceCandidatePairEvent(
-      rtc::ArrayView<const RtcEventIceCandidatePair*> batch,
-      rtclog2::EventStream* event_stream);
 };
 
 }  // namespace webrtc
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 3e34d47..6bccf57 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
@@ -218,6 +218,27 @@
   }
 }
 
+TEST_P(RtcEventLogEncoderTest, RtcEventRouteChange) {
+  if (!new_encoding_) {
+    return;
+  }
+  std::vector<std::unique_ptr<RtcEventRouteChange>> events(event_count_);
+  for (size_t i = 0; i < event_count_; ++i) {
+    events[i] = (i == 0 || !force_repeated_fields_) ? gen_.NewRouteChange()
+                                                    : 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& route_change_events = parsed_log_.route_change_events();
+
+  ASSERT_EQ(route_change_events.size(), event_count_);
+  for (size_t i = 0; i < event_count_; ++i) {
+    verifier_.VerifyLoggedRouteChangeEvent(*events[i], route_change_events[i]);
+  }
+}
+
 TEST_P(RtcEventLogEncoderTest, RtcEventAudioNetworkAdaptationBitrate) {
   std::vector<std::unique_ptr<RtcEventAudioNetworkAdaptation>> events(
       event_count_);
diff --git a/logging/rtc_event_log/events/rtc_event.h b/logging/rtc_event_log/events/rtc_event.h
index a8b1d9e..c288bf3 100644
--- a/logging/rtc_event_log/events/rtc_event.h
+++ b/logging/rtc_event_log/events/rtc_event.h
@@ -31,6 +31,7 @@
   // is kept separate.
   enum class Type {
     AlrStateEvent,
+    RouteChangeEvent,
     AudioNetworkAdaptation,
     AudioPlayout,
     AudioReceiveStreamConfig,
diff --git a/logging/rtc_event_log/events/rtc_event_route_change.cc b/logging/rtc_event_log/events/rtc_event_route_change.cc
new file mode 100644
index 0000000..1370ec8
--- /dev/null
+++ b/logging/rtc_event_log/events/rtc_event_route_change.cc
@@ -0,0 +1,38 @@
+/*
+ *  Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "logging/rtc_event_log/events/rtc_event_route_change.h"
+#include "absl/memory/memory.h"
+
+namespace webrtc {
+
+RtcEventRouteChange::RtcEventRouteChange(bool connected, uint32_t overhead)
+    : connected_(connected), overhead_(overhead) {}
+
+RtcEventRouteChange::RtcEventRouteChange(const RtcEventRouteChange& other)
+    : RtcEvent(other.timestamp_us_),
+      connected_(other.connected_),
+      overhead_(other.overhead_) {}
+
+RtcEventRouteChange::~RtcEventRouteChange() = default;
+
+RtcEvent::Type RtcEventRouteChange::GetType() const {
+  return RtcEvent::Type::RouteChangeEvent;
+}
+
+bool RtcEventRouteChange::IsConfigEvent() const {
+  return false;
+}
+
+std::unique_ptr<RtcEventRouteChange> RtcEventRouteChange::Copy() const {
+  return absl::WrapUnique<RtcEventRouteChange>(new RtcEventRouteChange(*this));
+}
+
+}  // namespace webrtc
diff --git a/logging/rtc_event_log/events/rtc_event_route_change.h b/logging/rtc_event_log/events/rtc_event_route_change.h
new file mode 100644
index 0000000..3648891
--- /dev/null
+++ b/logging/rtc_event_log/events/rtc_event_route_change.h
@@ -0,0 +1,42 @@
+/*
+ *  Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_ROUTE_CHANGE_H_
+#define LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_ROUTE_CHANGE_H_
+
+#include <memory>
+
+#include "logging/rtc_event_log/events/rtc_event.h"
+
+namespace webrtc {
+
+class RtcEventRouteChange final : public RtcEvent {
+ public:
+  RtcEventRouteChange(bool connected, uint32_t overhead);
+  ~RtcEventRouteChange() override;
+
+  Type GetType() const override;
+
+  bool IsConfigEvent() const override;
+
+  std::unique_ptr<RtcEventRouteChange> Copy() const;
+
+  bool connected() const { return connected_; }
+  uint32_t overhead() const { return overhead_; }
+
+ private:
+  RtcEventRouteChange(const RtcEventRouteChange& other);
+
+  const bool connected_;
+  const uint32_t overhead_;
+};
+
+}  // namespace webrtc
+#endif  // LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_ROUTE_CHANGE_H_
diff --git a/logging/rtc_event_log/logged_events.h b/logging/rtc_event_log/logged_events.h
index bea399e..a67f17b 100644
--- a/logging/rtc_event_log/logged_events.h
+++ b/logging/rtc_event_log/logged_events.h
@@ -224,6 +224,21 @@
   uint32_t transaction_id;
 };
 
+struct LoggedRouteChangeEvent {
+  LoggedRouteChangeEvent() = default;
+  LoggedRouteChangeEvent(int64_t timestamp_ms,
+                         bool connected,
+                         uint32_t overhead)
+      : timestamp_ms(timestamp_ms), connected(connected), overhead(overhead) {}
+
+  int64_t log_time_us() const { return timestamp_ms * 1000; }
+  int64_t log_time_ms() const { return timestamp_ms; }
+
+  int64_t timestamp_ms;
+  bool connected;
+  uint32_t overhead;
+};
+
 struct LoggedRtpPacket {
   LoggedRtpPacket(uint64_t timestamp_us,
                   RTPHeader header,
@@ -501,8 +516,6 @@
   uint16_t return_overhead;
 };
 
-using LoggedRouteChangeEvent = InferredRouteChangeEvent;
-
 enum class LoggedMediaType : uint8_t { kUnknown, kAudio, kVideo };
 
 struct LoggedPacketInfo {
diff --git a/logging/rtc_event_log/rtc_event_log2.proto b/logging/rtc_event_log/rtc_event_log2.proto
index 6f04c18..64c9d24 100644
--- a/logging/rtc_event_log/rtc_event_log2.proto
+++ b/logging/rtc_event_log/rtc_event_log2.proto
@@ -37,6 +37,7 @@
   repeated GenericPacketSent generic_packets_sent = 29;
   repeated GenericPacketReceived generic_packets_received = 30;
   repeated GenericAckReceived generic_acks_received = 31;
+  repeated RouteChange route_changes = 32;
 
   repeated AudioRecvStreamConfig audio_recv_stream_configs = 101;
   repeated AudioSendStreamConfig audio_send_stream_configs = 102;
@@ -654,3 +655,12 @@
   // required
   optional bool writable = 2;
 }
+
+message RouteChange {
+  // required
+  optional int64 timestamp_ms = 1;
+  // required - True if the route is ready for sending packets.
+  optional bool connected = 2;
+  // required - The per packet data overhead for this route.
+  optional uint32 overhead = 3;
+}
diff --git a/logging/rtc_event_log/rtc_event_log_parser.cc b/logging/rtc_event_log/rtc_event_log_parser.cc
index 9881bc3..7e5bc48 100644
--- a/logging/rtc_event_log/rtc_event_log_parser.cc
+++ b/logging/rtc_event_log/rtc_event_log_parser.cc
@@ -1129,6 +1129,7 @@
   first_timestamp_ = std::numeric_limits<int64_t>::max();
   last_timestamp_ = std::numeric_limits<int64_t>::min();
   StoreFirstAndLastTimestamp(alr_state_events());
+  StoreFirstAndLastTimestamp(route_change_events());
   for (const auto& audio_stream : audio_playout_events()) {
     // Audio playout events are grouped by SSRC.
     StoreFirstAndLastTimestamp(audio_stream.second);
@@ -2146,7 +2147,7 @@
           stream.audio_network_adaptations_size() +
           stream.probe_clusters_size() + stream.probe_success_size() +
           stream.probe_failure_size() + stream.alr_states_size() +
-          stream.ice_candidate_configs_size() +
+          stream.route_changes_size() + stream.ice_candidate_configs_size() +
           stream.ice_candidate_events_size() +
           stream.audio_recv_stream_configs_size() +
           stream.audio_send_stream_configs_size() +
@@ -2189,6 +2190,8 @@
     StoreBweProbeFailureEvent(stream.probe_failure(0));
   } else if (stream.alr_states_size() == 1) {
     StoreAlrStateEvent(stream.alr_states(0));
+  } else if (stream.route_changes_size() == 1) {
+    StoreRouteChangeEvent(stream.route_changes(0));
   } else if (stream.ice_candidate_configs_size() == 1) {
     StoreIceCandidatePairConfig(stream.ice_candidate_configs(0));
   } else if (stream.ice_candidate_events_size() == 1) {
@@ -2223,6 +2226,20 @@
   // TODO(terelius): Should we delta encode this event type?
 }
 
+void ParsedRtcEventLog::StoreRouteChangeEvent(
+    const rtclog2::RouteChange& proto) {
+  RTC_CHECK(proto.has_timestamp_ms());
+  RTC_CHECK(proto.has_connected());
+  RTC_CHECK(proto.has_overhead());
+  LoggedRouteChangeEvent route_event;
+  route_event.timestamp_ms = proto.timestamp_ms();
+  route_event.connected = proto.connected();
+  route_event.overhead = proto.overhead();
+
+  route_change_events_.push_back(route_event);
+  // TODO(terelius): Should we delta encode this event type?
+}
+
 void ParsedRtcEventLog::StoreAudioPlayoutEvent(
     const rtclog2::AudioPlayoutEvents& 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 d5ea658..763c086 100644
--- a/logging/rtc_event_log/rtc_event_log_parser.h
+++ b/logging/rtc_event_log/rtc_event_log_parser.h
@@ -388,6 +388,10 @@
     return ice_candidate_pair_events_;
   }
 
+  const std::vector<LoggedRouteChangeEvent>& route_change_events() const {
+    return route_change_events_;
+  }
+
   // RTP
   const std::vector<LoggedRtpStreamIncoming>& incoming_rtp_packets_by_ssrc()
       const {
@@ -592,35 +596,36 @@
       const rtclog::Event& event) const;
 
   // Parsing functions for new format.
-  void StoreParsedNewFormatEvent(const rtclog2::EventStream& event);
-  void StoreIncomingRtpPackets(const rtclog2::IncomingRtpPackets& proto);
-  void StoreOutgoingRtpPackets(const rtclog2::OutgoingRtpPackets& proto);
-  void StoreIncomingRtcpPackets(const rtclog2::IncomingRtcpPackets& proto);
-  void StoreOutgoingRtcpPackets(const rtclog2::OutgoingRtcpPackets& proto);
-  void StoreStartEvent(const rtclog2::BeginLogEvent& proto);
-  void StoreStopEvent(const rtclog2::EndLogEvent& proto);
   void StoreAlrStateEvent(const rtclog2::AlrState& proto);
   void StoreAudioNetworkAdaptationEvent(
       const rtclog2::AudioNetworkAdaptations& proto);
   void StoreAudioPlayoutEvent(const rtclog2::AudioPlayoutEvents& proto);
-  void StoreBweLossBasedUpdate(const rtclog2::LossBasedBweUpdates& proto);
-  void StoreBweDelayBasedUpdate(const rtclog2::DelayBasedBweUpdates& proto);
-  void StoreBweProbeClusterCreated(const rtclog2::BweProbeCluster& proto);
-  void StoreBweProbeSuccessEvent(const rtclog2::BweProbeResultSuccess& proto);
-  void StoreBweProbeFailureEvent(const rtclog2::BweProbeResultFailure& proto);
-  void StoreDtlsTransportState(const rtclog2::DtlsTransportStateEvent& proto);
-  void StoreDtlsWritableState(const rtclog2::DtlsWritableState& 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);
+  void StoreBweDelayBasedUpdate(const rtclog2::DelayBasedBweUpdates& proto);
+  void StoreBweLossBasedUpdate(const rtclog2::LossBasedBweUpdates& proto);
+  void StoreBweProbeClusterCreated(const rtclog2::BweProbeCluster& proto);
+  void StoreBweProbeFailureEvent(const rtclog2::BweProbeResultFailure& proto);
+  void StoreBweProbeSuccessEvent(const rtclog2::BweProbeResultSuccess& proto);
+  void StoreDtlsTransportState(const rtclog2::DtlsTransportStateEvent& proto);
+  void StoreDtlsWritableState(const rtclog2::DtlsWritableState& proto);
+  void StoreGenericAckReceivedEvent(const rtclog2::GenericAckReceived& proto);
   void StoreGenericPacketReceivedEvent(
       const rtclog2::GenericPacketReceived& proto);
   void StoreGenericPacketSentEvent(const rtclog2::GenericPacketSent& proto);
-  void StoreGenericAckReceivedEvent(const rtclog2::GenericAckReceived& proto);
+  void StoreIceCandidateEvent(const rtclog2::IceCandidatePairEvent& proto);
+  void StoreIceCandidatePairConfig(
+      const rtclog2::IceCandidatePairConfig& proto);
+  void StoreIncomingRtcpPackets(const rtclog2::IncomingRtcpPackets& proto);
+  void StoreIncomingRtpPackets(const rtclog2::IncomingRtpPackets& proto);
+  void StoreOutgoingRtcpPackets(const rtclog2::OutgoingRtcpPackets& proto);
+  void StoreOutgoingRtpPackets(const rtclog2::OutgoingRtpPackets& proto);
+  void StoreParsedNewFormatEvent(const rtclog2::EventStream& event);
+  void StoreRouteChangeEvent(const rtclog2::RouteChange& proto);
+  void StoreStartEvent(const rtclog2::BeginLogEvent& proto);
+  void StoreStopEvent(const rtclog2::EndLogEvent& proto);
+  void StoreVideoRecvConfig(const rtclog2::VideoRecvStreamConfig& proto);
+  void StoreVideoSendConfig(const rtclog2::VideoSendStreamConfig& proto);
   // End of new parsing functions.
 
   struct Stream {
@@ -731,6 +736,8 @@
   std::vector<LoggedGenericPacketSent> generic_packets_sent_;
   std::vector<LoggedGenericAckReceived> generic_acks_received_;
 
+  std::vector<LoggedRouteChangeEvent> route_change_events_;
+
   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 66d8095..896a76d 100644
--- a/logging/rtc_event_log/rtc_event_log_unittest.cc
+++ b/logging/rtc_event_log/rtc_event_log_unittest.cc
@@ -63,6 +63,7 @@
   size_t video_send_streams = 0;
   size_t video_recv_streams = 0;
   size_t alr_states = 0;
+  size_t route_changes = 0;
   size_t audio_playouts = 0;
   size_t ana_configs = 0;
   size_t bwe_loss_events = 0;
@@ -83,13 +84,13 @@
   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 +
-           generic_packets_sent + generic_packets_received +
-           generic_acks_received;
+    return alr_states + route_changes + 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 + generic_packets_sent +
+           generic_packets_received + generic_acks_received;
   }
 
   size_t total_config_events() const {
@@ -159,29 +160,30 @@
       audio_playout_map_;  // Groups audio by SSRC.
   std::vector<std::unique_ptr<RtcEventAudioNetworkAdaptation>>
       ana_configs_list_;
-  std::vector<std::unique_ptr<RtcEventBweUpdateLossBased>> bwe_loss_list_;
   std::vector<std::unique_ptr<RtcEventBweUpdateDelayBased>> bwe_delay_list_;
+  std::vector<std::unique_ptr<RtcEventBweUpdateLossBased>> bwe_loss_list_;
   std::vector<std::unique_ptr<RtcEventDtlsTransportState>>
       dtls_transport_state_list_;
   std::vector<std::unique_ptr<RtcEventDtlsWritableState>>
       dtls_writable_state_list_;
+  std::vector<std::unique_ptr<RtcEventGenericAckReceived>>
+      generic_acks_received_;
+  std::vector<std::unique_ptr<RtcEventGenericPacketReceived>>
+      generic_packets_received_;
+  std::vector<std::unique_ptr<RtcEventGenericPacketSent>> generic_packets_sent_;
+  std::vector<std::unique_ptr<RtcEventIceCandidatePair>> ice_event_list_;
+  std::vector<std::unique_ptr<RtcEventIceCandidatePairConfig>> ice_config_list_;
   std::vector<std::unique_ptr<RtcEventProbeClusterCreated>>
       probe_creation_list_;
-  std::vector<std::unique_ptr<RtcEventProbeResultSuccess>> probe_success_list_;
   std::vector<std::unique_ptr<RtcEventProbeResultFailure>> probe_failure_list_;
-  std::vector<std::unique_ptr<RtcEventIceCandidatePairConfig>> ice_config_list_;
-  std::vector<std::unique_ptr<RtcEventIceCandidatePair>> ice_event_list_;
+  std::vector<std::unique_ptr<RtcEventProbeResultSuccess>> probe_success_list_;
+  std::vector<std::unique_ptr<RtcEventRouteChange>> route_change_list_;
+  std::vector<std::unique_ptr<RtcEventRtcpPacketIncoming>> incoming_rtcp_list_;
+  std::vector<std::unique_ptr<RtcEventRtcpPacketOutgoing>> outgoing_rtcp_list_;
   std::map<uint32_t, std::vector<std::unique_ptr<RtcEventRtpPacketIncoming>>>
       incoming_rtp_map_;  // Groups incoming RTP by SSRC.
   std::map<uint32_t, std::vector<std::unique_ptr<RtcEventRtpPacketOutgoing>>>
       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_;
@@ -349,6 +351,15 @@
     }
     selection -= count.alr_states;
 
+    if (selection < count.route_changes) {
+      auto event = gen_.NewRouteChange();
+      event_log->Log(event->Copy());
+      route_change_list_.push_back(std::move(event));
+      count.route_changes--;
+      continue;
+    }
+    selection -= count.route_changes;
+
     if (selection < count.audio_playouts) {
       size_t stream = prng_.Rand(incoming_extensions_.size() - 1);
       // This might be a video SSRC, but the parser does not use the config.
@@ -552,6 +563,12 @@
     verifier_.VerifyLoggedAlrStateEvent(*alr_state_list_[i],
                                         parsed_alr_state_events[i]);
   }
+  auto& parsed_route_change_events = parsed_log.route_change_events();
+  ASSERT_EQ(parsed_route_change_events.size(), route_change_list_.size());
+  for (size_t i = 0; i < parsed_route_change_events.size(); i++) {
+    verifier_.VerifyLoggedRouteChangeEvent(*route_change_list_[i],
+                                           parsed_route_change_events[i]);
+  }
 
   const auto& parsed_audio_playout_map = parsed_log.audio_playout_events();
   ASSERT_EQ(parsed_audio_playout_map.size(), audio_playout_map_.size());
@@ -751,6 +768,7 @@
   count.incoming_rtcp_packets = 20;
   count.outgoing_rtcp_packets = 20;
   if (IsNewFormat()) {
+    count.route_changes = 4;
     count.generic_packets_sent = 100;
     count.generic_packets_received = 100;
     count.generic_acks_received = 20;
@@ -783,6 +801,7 @@
   count.incoming_rtcp_packets = 50;
   count.outgoing_rtcp_packets = 50;
   if (IsNewFormat()) {
+    count.route_changes = 10;
     count.generic_packets_sent = 500;
     count.generic_packets_received = 500;
     count.generic_acks_received = 50;
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 651e023..3c4ca0d 100644
--- a/logging/rtc_event_log/rtc_event_log_unittest_helper.cc
+++ b/logging/rtc_event_log/rtc_event_log_unittest_helper.cc
@@ -350,6 +350,11 @@
   return loss_notification;
 }
 
+std::unique_ptr<RtcEventRouteChange> EventGenerator::NewRouteChange() {
+  return absl::make_unique<RtcEventRouteChange>(prng_.Rand<bool>(),
+                                                prng_.Rand(0, 128));
+}
+
 std::unique_ptr<RtcEventRtcpPacketIncoming>
 EventGenerator::NewRtcpPacketIncoming() {
   enum class SupportedRtcpTypes {
@@ -919,6 +924,14 @@
   }
 }
 
+void EventVerifier::VerifyLoggedRouteChangeEvent(
+    const RtcEventRouteChange& original_event,
+    const LoggedRouteChangeEvent& logged_event) const {
+  EXPECT_EQ(original_event.timestamp_ms(), logged_event.log_time_ms());
+  EXPECT_EQ(original_event.connected(), logged_event.connected);
+  EXPECT_EQ(original_event.overhead(), logged_event.overhead);
+}
+
 void EventVerifier::VerifyLoggedRtpPacketIncoming(
     const RtcEventRtpPacketIncoming& original_event,
     const LoggedRtpPacketIncoming& 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 ec03694..716d89f 100644
--- a/logging/rtc_event_log/rtc_event_log_unittest_helper.h
+++ b/logging/rtc_event_log/rtc_event_log_unittest_helper.h
@@ -32,6 +32,7 @@
 #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"
+#include "logging/rtc_event_log/events/rtc_event_route_change.h"
 #include "logging/rtc_event_log/events/rtc_event_rtcp_packet_incoming.h"
 #include "logging/rtc_event_log/events/rtc_event_rtcp_packet_outgoing.h"
 #include "logging/rtc_event_log/events/rtc_event_rtp_packet_incoming.h"
@@ -62,24 +63,24 @@
   explicit EventGenerator(uint64_t seed) : prng_(seed) {}
 
   std::unique_ptr<RtcEventAlrState> NewAlrState();
-  std::unique_ptr<RtcEventAudioPlayout> NewAudioPlayout(uint32_t ssrc);
   std::unique_ptr<RtcEventAudioNetworkAdaptation> NewAudioNetworkAdaptation();
+  std::unique_ptr<RtcEventAudioPlayout> NewAudioPlayout(uint32_t ssrc);
   std::unique_ptr<RtcEventBweUpdateDelayBased> NewBweUpdateDelayBased();
   std::unique_ptr<RtcEventBweUpdateLossBased> NewBweUpdateLossBased();
   std::unique_ptr<RtcEventDtlsTransportState> NewDtlsTransportState();
   std::unique_ptr<RtcEventDtlsWritableState> NewDtlsWritableState();
+  std::unique_ptr<RtcEventGenericAckReceived> NewGenericAckReceived();
+  std::unique_ptr<RtcEventGenericPacketReceived> NewGenericPacketReceived();
+  std::unique_ptr<RtcEventGenericPacketSent> NewGenericPacketSent();
+  std::unique_ptr<RtcEventIceCandidatePair> NewIceCandidatePair();
+  std::unique_ptr<RtcEventIceCandidatePairConfig> NewIceCandidatePairConfig();
   std::unique_ptr<RtcEventProbeClusterCreated> NewProbeClusterCreated();
   std::unique_ptr<RtcEventProbeResultFailure> NewProbeResultFailure();
   std::unique_ptr<RtcEventProbeResultSuccess> NewProbeResultSuccess();
-  std::unique_ptr<RtcEventIceCandidatePairConfig> NewIceCandidatePairConfig();
-  std::unique_ptr<RtcEventIceCandidatePair> NewIceCandidatePair();
+  std::unique_ptr<RtcEventRouteChange> NewRouteChange();
   std::unique_ptr<RtcEventRtcpPacketIncoming> NewRtcpPacketIncoming();
   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::ExtendedReports NewExtendedReports();
@@ -193,6 +194,10 @@
       const RtcEventIceCandidatePair& original_event,
       const LoggedIceCandidatePairEvent& logged_event) const;
 
+  void VerifyLoggedRouteChangeEvent(
+      const RtcEventRouteChange& original_event,
+      const LoggedRouteChangeEvent& logged_event) const;
+
   void VerifyLoggedRtpPacketIncoming(
       const RtcEventRtpPacketIncoming& original_event,
       const LoggedRtpPacketIncoming& logged_event) const;