summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/logging
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /third_party/libwebrtc/logging
parentInitial commit. (diff)
downloadfirefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz
firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/libwebrtc/logging')
-rw-r--r--third_party/libwebrtc/logging/BUILD.gn611
-rw-r--r--third_party/libwebrtc/logging/OWNERS2
-rw-r--r--third_party/libwebrtc/logging/g3doc/rtc_event_log.md85
-rw-r--r--third_party/libwebrtc/logging/rtc_event_audio_gn/moz.build229
-rw-r--r--third_party/libwebrtc/logging/rtc_event_bwe_gn/moz.build230
-rw-r--r--third_party/libwebrtc/logging/rtc_event_field_gn/moz.build228
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/DEPS7
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/encoder/bit_writer.cc49
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/encoder/bit_writer.h61
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/encoder/blob_encoding.cc92
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/encoder/blob_encoding.h53
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/encoder/blob_encoding_unittest.cc152
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/encoder/delta_encoding.cc839
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/encoder/delta_encoding.h49
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/encoder/delta_encoding_unittest.cc693
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder.h36
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder_common.cc40
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder_common.h93
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder_common_unittest.cc84
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder_legacy.cc814
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder_legacy.h110
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder_new_format.cc1941
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder_new_format.h164
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder_unittest.cc1401
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder_v3.cc164
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder_v3.h46
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/encoder/var_int.cc77
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/encoder/var_int.h50
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/fixed_length_encoding_parameters_v3.cc137
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/fixed_length_encoding_parameters_v3.h96
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/logged_rtp_rtcp.h259
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_alr_state.cc38
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_alr_state.h78
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_audio_network_adaptation.cc39
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_audio_network_adaptation.h78
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_audio_playout.cc32
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_audio_playout.h88
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_audio_receive_stream_config.cc40
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_audio_receive_stream_config.h76
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_audio_send_stream_config.cc40
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_audio_send_stream_config.h74
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_begin_log.cc73
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_begin_log.h74
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_bwe_update_delay_based.cc43
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_bwe_update_delay_based.h136
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_bwe_update_loss_based.cc39
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_bwe_update_loss_based.h89
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_definition.h152
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_dtls_transport_state.cc33
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_dtls_transport_state.h72
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_dtls_writable_state.cc32
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_dtls_writable_state.h72
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_end_log.cc58
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_end_log.h64
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_field_encoding.cc299
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_field_encoding.h179
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_field_encoding_parser.cc398
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_field_encoding_parser.h291
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_field_encoding_unittest.cc886
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_field_extraction.cc60
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_field_extraction.h84
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_field_extraction_unittest.cc97
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_frame_decoded.cc44
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_frame_decoded.h93
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_generic_ack_received.cc55
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_generic_ack_received.h118
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_generic_packet_received.cc32
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_generic_packet_received.h84
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_generic_packet_sent.cc36
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_generic_packet_sent.h110
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_ice_candidate_pair.cc40
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_ice_candidate_pair.h98
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_ice_candidate_pair_config.cc63
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_ice_candidate_pair_config.h152
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_neteq_set_minimum_delay.cc31
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_neteq_set_minimum_delay.h70
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_probe_cluster_created.cc40
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_probe_cluster_created.h95
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_probe_result_failure.cc34
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_probe_result_failure.h87
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_probe_result_success.cc33
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_probe_result_success.h80
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_remote_estimate.h68
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_route_change.cc31
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_route_change.h75
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_rtcp_packet_incoming.cc34
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_rtcp_packet_incoming.h64
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_rtcp_packet_outgoing.cc34
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_rtcp_packet_outgoing.h64
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_rtp_packet_incoming.cc35
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_rtp_packet_incoming.h89
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_rtp_packet_outgoing.cc38
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_rtp_packet_outgoing.h93
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_video_receive_stream_config.cc39
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_video_receive_stream_config.h76
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_video_send_stream_config.cc36
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_video_send_stream_config.h75
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/fake_rtc_event_log.cc38
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/fake_rtc_event_log.h42
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/fake_rtc_event_log_factory.cc33
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/fake_rtc_event_log_factory.h40
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/ice_logger.cc52
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/ice_logger.h56
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/logged_events.h18
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/mock/mock_rtc_event_log.cc18
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/mock/mock_rtc_event_log.h42
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/output/rtc_event_log_output_file.h19
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/rtc_event_log.proto427
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/rtc_event_log2.proto750
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/rtc_event_log2rtp_dump.cc258
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/rtc_event_log_impl.cc276
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/rtc_event_log_impl.h114
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/rtc_event_log_impl_unittest.cc188
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/rtc_event_log_parser.cc3635
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/rtc_event_log_parser.h941
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/rtc_event_log_unittest.cc1050
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/rtc_event_log_unittest_helper.cc1369
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/rtc_event_log_unittest_helper.h336
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/rtc_event_processor.cc41
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/rtc_event_processor.h131
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/rtc_event_processor_unittest.cc163
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/rtc_stream_config.cc49
-rw-r--r--third_party/libwebrtc/logging/rtc_event_log/rtc_stream_config.h62
-rw-r--r--third_party/libwebrtc/logging/rtc_event_number_encodings_gn/moz.build223
-rw-r--r--third_party/libwebrtc/logging/rtc_event_pacing_gn/moz.build225
-rw-r--r--third_party/libwebrtc/logging/rtc_event_rtp_rtcp_gn/moz.build235
-rw-r--r--third_party/libwebrtc/logging/rtc_event_video_gn/moz.build226
-rw-r--r--third_party/libwebrtc/logging/rtc_stream_config_gn/moz.build225
128 files changed, 26234 insertions, 0 deletions
diff --git a/third_party/libwebrtc/logging/BUILD.gn b/third_party/libwebrtc/logging/BUILD.gn
new file mode 100644
index 0000000000..408d4ecc51
--- /dev/null
+++ b/third_party/libwebrtc/logging/BUILD.gn
@@ -0,0 +1,611 @@
+# Copyright (c) 2016 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.
+
+import("../webrtc.gni")
+if (rtc_enable_protobuf) {
+ import("//third_party/protobuf/proto_library.gni")
+}
+if (is_android) {
+ import("//build/config/android/config.gni")
+ import("//build/config/android/rules.gni")
+}
+
+group("logging") {
+ deps = [
+ ":rtc_event_audio",
+ ":rtc_event_begin_end",
+ ":rtc_event_bwe",
+ ":rtc_event_log_impl_encoder",
+ ":rtc_event_pacing",
+ ":rtc_event_rtp_rtcp",
+ ":rtc_event_video",
+ ]
+}
+
+rtc_source_set("rtc_event_log_api") {
+ sources = [ "rtc_event_log/encoder/rtc_event_log_encoder.h" ]
+
+ deps = [ "../api/rtc_event_log" ]
+}
+
+rtc_library("rtc_event_field") {
+ sources = [
+ "rtc_event_log/events/fixed_length_encoding_parameters_v3.cc",
+ "rtc_event_log/events/fixed_length_encoding_parameters_v3.h",
+ "rtc_event_log/events/rtc_event_definition.h",
+ "rtc_event_log/events/rtc_event_field_encoding.cc",
+ "rtc_event_log/events/rtc_event_field_encoding.h",
+ "rtc_event_log/events/rtc_event_field_encoding_parser.cc",
+ "rtc_event_log/events/rtc_event_field_encoding_parser.h",
+ "rtc_event_log/events/rtc_event_field_extraction.cc",
+ "rtc_event_log/events/rtc_event_field_extraction.h",
+ ]
+
+ deps = [
+ ":rtc_event_number_encodings",
+ "../api:array_view",
+ "../api/rtc_event_log",
+ "../api/units:timestamp",
+ "../rtc_base:bitstream_reader",
+ "../rtc_base:checks",
+ "../rtc_base:logging",
+ ]
+ absl_deps = [
+ "//third_party/abseil-cpp/absl/strings",
+ "//third_party/abseil-cpp/absl/types:optional",
+ ]
+}
+
+rtc_library("rtc_stream_config") {
+ sources = [
+ "rtc_event_log/rtc_stream_config.cc",
+ "rtc_event_log/rtc_stream_config.h",
+ ]
+
+ deps = [
+ "../api:rtp_headers",
+ "../api:rtp_parameters",
+ ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/strings" ]
+}
+
+rtc_library("rtc_event_pacing") {
+ sources = [
+ "rtc_event_log/events/rtc_event_alr_state.cc",
+ "rtc_event_log/events/rtc_event_alr_state.h",
+ ]
+
+ deps = [
+ ":rtc_event_field",
+ "../api/rtc_event_log",
+ "../api/units:timestamp",
+ ]
+ absl_deps = [
+ "//third_party/abseil-cpp/absl/memory",
+ "//third_party/abseil-cpp/absl/strings",
+ ]
+}
+
+rtc_library("rtc_event_audio") {
+ sources = [
+ "rtc_event_log/events/rtc_event_audio_network_adaptation.cc",
+ "rtc_event_log/events/rtc_event_audio_network_adaptation.h",
+ "rtc_event_log/events/rtc_event_audio_playout.cc",
+ "rtc_event_log/events/rtc_event_audio_playout.h",
+ "rtc_event_log/events/rtc_event_audio_receive_stream_config.cc",
+ "rtc_event_log/events/rtc_event_audio_receive_stream_config.h",
+ "rtc_event_log/events/rtc_event_audio_send_stream_config.cc",
+ "rtc_event_log/events/rtc_event_audio_send_stream_config.h",
+ "rtc_event_log/events/rtc_event_neteq_set_minimum_delay.cc",
+ "rtc_event_log/events/rtc_event_neteq_set_minimum_delay.h",
+ ]
+
+ deps = [
+ ":rtc_event_field",
+ ":rtc_stream_config",
+ "../api/rtc_event_log",
+ "../api/units:timestamp",
+ "../modules/audio_coding:audio_network_adaptor_config",
+ "../rtc_base:checks",
+ ]
+ absl_deps = [
+ "//third_party/abseil-cpp/absl/memory",
+ "//third_party/abseil-cpp/absl/strings",
+ ]
+}
+
+rtc_library("rtc_event_begin_end") {
+ sources = [
+ "rtc_event_log/events/rtc_event_begin_log.cc",
+ "rtc_event_log/events/rtc_event_begin_log.h",
+ "rtc_event_log/events/rtc_event_end_log.cc",
+ "rtc_event_log/events/rtc_event_end_log.h",
+ ]
+ deps = [
+ ":rtc_event_field",
+ "../api:array_view",
+ "../api/rtc_event_log",
+ "../api/units:timestamp",
+ ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/strings" ]
+}
+
+rtc_library("rtc_event_bwe") {
+ sources = [
+ "rtc_event_log/events/rtc_event_bwe_update_delay_based.cc",
+ "rtc_event_log/events/rtc_event_bwe_update_delay_based.h",
+ "rtc_event_log/events/rtc_event_bwe_update_loss_based.cc",
+ "rtc_event_log/events/rtc_event_bwe_update_loss_based.h",
+ "rtc_event_log/events/rtc_event_probe_cluster_created.cc",
+ "rtc_event_log/events/rtc_event_probe_cluster_created.h",
+ "rtc_event_log/events/rtc_event_probe_result_failure.cc",
+ "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_remote_estimate.h",
+ "rtc_event_log/events/rtc_event_route_change.cc",
+ "rtc_event_log/events/rtc_event_route_change.h",
+ ]
+
+ deps = [
+ ":rtc_event_field",
+ "../api:network_state_predictor_api",
+ "../api/rtc_event_log",
+ "../api/units:data_rate",
+ "../api/units:timestamp",
+ ]
+ absl_deps = [
+ "//third_party/abseil-cpp/absl/memory",
+ "//third_party/abseil-cpp/absl/strings",
+ "//third_party/abseil-cpp/absl/types:optional",
+ ]
+}
+
+rtc_library("rtc_event_frame_events") {
+ sources = [
+ "rtc_event_log/events/rtc_event_frame_decoded.cc",
+ "rtc_event_log/events/rtc_event_frame_decoded.h",
+ ]
+ deps = [
+ ":rtc_event_field",
+ "../api/rtc_event_log",
+ "../api/units:timestamp",
+ "../api/video:video_frame",
+ "../rtc_base:timeutils",
+ ]
+ absl_deps = [
+ "//third_party/abseil-cpp/absl/memory",
+ "//third_party/abseil-cpp/absl/strings",
+ "//third_party/abseil-cpp/absl/types:optional",
+ ]
+}
+
+rtc_library("rtc_event_generic_packet_events") {
+ visibility = [ "*" ]
+ sources = [
+ "rtc_event_log/events/rtc_event_generic_ack_received.cc",
+ "rtc_event_log/events/rtc_event_generic_ack_received.h",
+ "rtc_event_log/events/rtc_event_generic_packet_received.cc",
+ "rtc_event_log/events/rtc_event_generic_packet_received.h",
+ "rtc_event_log/events/rtc_event_generic_packet_sent.cc",
+ "rtc_event_log/events/rtc_event_generic_packet_sent.h",
+ ]
+ deps = [
+ ":rtc_event_field",
+ "../api/rtc_event_log",
+ "../api/units:timestamp",
+ "../rtc_base:timeutils",
+ ]
+ absl_deps = [
+ "//third_party/abseil-cpp/absl/memory",
+ "//third_party/abseil-cpp/absl/strings",
+ "//third_party/abseil-cpp/absl/types:optional",
+ ]
+}
+
+rtc_library("rtc_event_rtp_rtcp") {
+ sources = [
+ "rtc_event_log/events/logged_rtp_rtcp.h",
+ "rtc_event_log/events/rtc_event_rtcp_packet_incoming.cc",
+ "rtc_event_log/events/rtc_event_rtcp_packet_incoming.h",
+ "rtc_event_log/events/rtc_event_rtcp_packet_outgoing.cc",
+ "rtc_event_log/events/rtc_event_rtcp_packet_outgoing.h",
+ "rtc_event_log/events/rtc_event_rtp_packet_incoming.cc",
+ "rtc_event_log/events/rtc_event_rtp_packet_incoming.h",
+ "rtc_event_log/events/rtc_event_rtp_packet_outgoing.cc",
+ "rtc_event_log/events/rtc_event_rtp_packet_outgoing.h",
+ ]
+
+ deps = [
+ ":rtc_event_field",
+ "../api:array_view",
+ "../api:rtp_headers",
+ "../api/rtc_event_log",
+ "../api/units:timestamp",
+ "../modules/rtp_rtcp:rtp_rtcp_format",
+ "../rtc_base:buffer",
+ "../rtc_base:checks",
+ ]
+ absl_deps = [
+ "//third_party/abseil-cpp/absl/memory",
+ "//third_party/abseil-cpp/absl/strings",
+ ]
+}
+
+rtc_library("rtc_event_video") {
+ sources = [
+ "rtc_event_log/events/rtc_event_video_receive_stream_config.cc",
+ "rtc_event_log/events/rtc_event_video_receive_stream_config.h",
+ "rtc_event_log/events/rtc_event_video_send_stream_config.cc",
+ "rtc_event_log/events/rtc_event_video_send_stream_config.h",
+ ]
+
+ deps = [
+ ":rtc_event_field",
+ ":rtc_stream_config",
+ "../api/rtc_event_log",
+ "../api/units:timestamp",
+ "../rtc_base:checks",
+ ]
+ absl_deps = [
+ "//third_party/abseil-cpp/absl/memory",
+ "//third_party/abseil-cpp/absl/strings",
+ ]
+}
+
+rtc_library("rtc_event_number_encodings") {
+ sources = [
+ "rtc_event_log/encoder/bit_writer.cc",
+ "rtc_event_log/encoder/bit_writer.h",
+ "rtc_event_log/encoder/rtc_event_log_encoder_common.cc",
+ "rtc_event_log/encoder/rtc_event_log_encoder_common.h",
+ "rtc_event_log/encoder/var_int.cc",
+ "rtc_event_log/encoder/var_int.h",
+ ]
+
+ defines = []
+
+ deps = [
+ "../rtc_base:bit_buffer",
+ "../rtc_base:bitstream_reader",
+ "../rtc_base:checks",
+ "../rtc_base:ignore_wundef",
+ "../rtc_base:macromagic",
+ ]
+ absl_deps = [
+ "//third_party/abseil-cpp/absl/memory",
+ "//third_party/abseil-cpp/absl/strings",
+ "//third_party/abseil-cpp/absl/types:optional",
+ ]
+}
+
+# TODO(eladalon): Break down into (1) encoder and (2) decoder; we don't need
+# the decoder code in the WebRTC library, only in unit tests and tools.
+rtc_library("rtc_event_log_impl_encoder") {
+ sources = [
+ "rtc_event_log/encoder/blob_encoding.cc",
+ "rtc_event_log/encoder/blob_encoding.h",
+ "rtc_event_log/encoder/delta_encoding.cc",
+ "rtc_event_log/encoder/delta_encoding.h",
+ ]
+
+ defines = []
+
+ deps = [
+ ":rtc_event_number_encodings",
+ "../api:rtp_headers",
+ "../api:rtp_parameters",
+ "../api/transport:network_control",
+ "../rtc_base:bit_buffer",
+ "../rtc_base:bitstream_reader",
+ "../rtc_base:buffer",
+ "../rtc_base:checks",
+ "../rtc_base:ignore_wundef",
+ "../rtc_base:logging",
+ "../rtc_base:safe_conversions",
+ "../system_wrappers:field_trial",
+ ]
+ absl_deps = [
+ "//third_party/abseil-cpp/absl/memory",
+ "//third_party/abseil-cpp/absl/strings",
+ "//third_party/abseil-cpp/absl/types:optional",
+ ]
+
+ if (rtc_enable_protobuf) {
+ deps += [
+ ":ice_log",
+ ":rtc_event_audio",
+ ":rtc_event_begin_end",
+ ":rtc_event_bwe",
+ ":rtc_event_field",
+ ":rtc_event_frame_events",
+ ":rtc_event_generic_packet_events",
+ ":rtc_event_log2_proto",
+ ":rtc_event_log_api",
+ ":rtc_event_log_proto",
+ ":rtc_event_pacing",
+ ":rtc_event_rtp_rtcp",
+ ":rtc_event_video",
+ ":rtc_stream_config",
+ "../api:array_view",
+ "../api:network_state_predictor_api",
+ "../modules/audio_coding:audio_network_adaptor",
+ "../modules/rtp_rtcp:rtp_rtcp_format",
+ ]
+ sources += [
+ "rtc_event_log/encoder/rtc_event_log_encoder_legacy.cc",
+ "rtc_event_log/encoder/rtc_event_log_encoder_legacy.h",
+ "rtc_event_log/encoder/rtc_event_log_encoder_new_format.cc",
+ "rtc_event_log/encoder/rtc_event_log_encoder_new_format.h",
+ "rtc_event_log/encoder/rtc_event_log_encoder_v3.cc",
+ "rtc_event_log/encoder/rtc_event_log_encoder_v3.h",
+ ]
+ }
+}
+
+# TODO(bugs.webrtc.org/6463): For backwards compatibility; delete as
+# soon as downstream dependencies are updated.
+rtc_source_set("rtc_event_log_impl_output") {
+ sources = [ "rtc_event_log/output/rtc_event_log_output_file.h" ]
+ deps = [ "../api:rtc_event_log_output_file" ]
+}
+
+if (rtc_enable_protobuf) {
+ rtc_library("rtc_event_log_impl") {
+ visibility = [
+ ":rtc_event_log_tests",
+ "../api/rtc_event_log:rtc_event_log_factory",
+ ]
+ sources = [
+ "rtc_event_log/rtc_event_log_impl.cc",
+ "rtc_event_log/rtc_event_log_impl.h",
+ ]
+ deps = [
+ ":ice_log",
+ ":rtc_event_log_api",
+ ":rtc_event_log_impl_encoder",
+ "../api:libjingle_logging_api",
+ "../api:sequence_checker",
+ "../api/rtc_event_log",
+ "../api/task_queue",
+ "../api/units:time_delta",
+ "../rtc_base:checks",
+ "../rtc_base:logging",
+ "../rtc_base:macromagic",
+ "../rtc_base:rtc_event",
+ "../rtc_base:rtc_task_queue",
+ "../rtc_base:safe_conversions",
+ "../rtc_base:safe_minmax",
+ "../rtc_base:timeutils",
+ "../rtc_base/system:no_unique_address",
+ ]
+ absl_deps = [
+ "//third_party/abseil-cpp/absl/strings",
+ "//third_party/abseil-cpp/absl/types:optional",
+ ]
+ }
+}
+
+rtc_library("fake_rtc_event_log") {
+ testonly = true
+ sources = [
+ "rtc_event_log/fake_rtc_event_log.cc",
+ "rtc_event_log/fake_rtc_event_log.h",
+ "rtc_event_log/fake_rtc_event_log_factory.cc",
+ "rtc_event_log/fake_rtc_event_log_factory.h",
+ ]
+
+ deps = [
+ "../api/rtc_event_log",
+ "../rtc_base:macromagic",
+ "../rtc_base/synchronization:mutex",
+ ]
+}
+
+if (rtc_enable_protobuf) {
+ proto_library("rtc_event_log_proto") {
+ visibility = [ "*" ]
+ sources = [ "rtc_event_log/rtc_event_log.proto" ]
+ proto_out_dir = "logging/rtc_event_log"
+ }
+
+ proto_library("rtc_event_log2_proto") {
+ visibility = [ "*" ]
+ sources = [ "rtc_event_log/rtc_event_log2.proto" ]
+ proto_out_dir = "logging/rtc_event_log"
+ }
+
+ rtc_library("rtc_event_log_parser") {
+ visibility = [ "*" ]
+ sources = [
+ "rtc_event_log/logged_events.h",
+ "rtc_event_log/rtc_event_log_parser.cc",
+ "rtc_event_log/rtc_event_log_parser.h",
+ "rtc_event_log/rtc_event_processor.cc",
+ "rtc_event_log/rtc_event_processor.h",
+ ]
+
+ deps = [
+ ":ice_log",
+ ":rtc_event_audio",
+ ":rtc_event_begin_end",
+ ":rtc_event_bwe",
+ ":rtc_event_frame_events",
+ ":rtc_event_generic_packet_events",
+ ":rtc_event_log2_proto",
+ ":rtc_event_log_impl_encoder",
+ ":rtc_event_log_proto",
+ ":rtc_event_number_encodings",
+ ":rtc_event_pacing",
+ ":rtc_event_rtp_rtcp",
+ ":rtc_event_video",
+ ":rtc_stream_config",
+ "../api:function_view",
+ "../api:network_state_predictor_api",
+ "../api:rtp_headers",
+ "../api:rtp_parameters",
+ "../api/rtc_event_log",
+ "../api/units:data_rate",
+ "../api/units:time_delta",
+ "../api/units:timestamp",
+ "../api/video:video_frame",
+ "../call:video_stream_api",
+ "../modules:module_api_public",
+ "../modules/audio_coding:audio_network_adaptor",
+ "../modules/rtp_rtcp:rtp_rtcp_format",
+ "../rtc_base:checks",
+ "../rtc_base:copy_on_write_buffer",
+ "../rtc_base:ignore_wundef",
+ "../rtc_base:logging",
+ "../rtc_base:protobuf_utils",
+ "../rtc_base:rtc_numerics",
+ "../rtc_base:safe_conversions",
+ "../rtc_base/system:file_wrapper",
+ ]
+ absl_deps = [
+ "//third_party/abseil-cpp/absl/base:core_headers",
+ "//third_party/abseil-cpp/absl/memory",
+ "//third_party/abseil-cpp/absl/strings",
+ "//third_party/abseil-cpp/absl/types:optional",
+ ]
+ }
+
+ if (rtc_include_tests) {
+ rtc_library("rtc_event_log_tests") {
+ testonly = true
+ assert(rtc_enable_protobuf)
+ sources = [
+ "rtc_event_log/encoder/blob_encoding_unittest.cc",
+ "rtc_event_log/encoder/delta_encoding_unittest.cc",
+ "rtc_event_log/encoder/rtc_event_log_encoder_common_unittest.cc",
+ "rtc_event_log/encoder/rtc_event_log_encoder_unittest.cc",
+ "rtc_event_log/events/rtc_event_field_encoding_unittest.cc",
+ "rtc_event_log/events/rtc_event_field_extraction_unittest.cc",
+ "rtc_event_log/rtc_event_log_impl_unittest.cc",
+ "rtc_event_log/rtc_event_log_unittest.cc",
+ "rtc_event_log/rtc_event_log_unittest_helper.cc",
+ "rtc_event_log/rtc_event_log_unittest_helper.h",
+ "rtc_event_log/rtc_event_processor_unittest.cc",
+ ]
+ deps = [
+ ":ice_log",
+ ":rtc_event_audio",
+ ":rtc_event_bwe",
+ ":rtc_event_field",
+ ":rtc_event_frame_events",
+ ":rtc_event_generic_packet_events",
+ ":rtc_event_log2_proto",
+ ":rtc_event_log_impl",
+ ":rtc_event_log_impl_encoder",
+ ":rtc_event_log_parser",
+ ":rtc_event_log_proto",
+ ":rtc_event_number_encodings",
+ ":rtc_event_pacing",
+ ":rtc_event_rtp_rtcp",
+ ":rtc_event_video",
+ ":rtc_stream_config",
+ "../api:array_view",
+ "../api:network_state_predictor_api",
+ "../api:rtc_event_log_output_file",
+ "../api:rtp_headers",
+ "../api:rtp_parameters",
+ "../api/rtc_event_log",
+ "../api/rtc_event_log:rtc_event_log_factory",
+ "../api/task_queue:default_task_queue_factory",
+ "../api/units:time_delta",
+ "../api/units:timestamp",
+ "../call",
+ "../call:call_interfaces",
+ "../modules/audio_coding:audio_network_adaptor",
+ "../modules/rtp_rtcp:rtp_rtcp_format",
+ "../rtc_base:buffer",
+ "../rtc_base:checks",
+ "../rtc_base:macromagic",
+ "../rtc_base:random",
+ "../rtc_base:rtc_base_tests_utils",
+ "../rtc_base:timeutils",
+ "../system_wrappers",
+ "../test:fileutils",
+ "../test:test_support",
+ "../test/logging:log_writer",
+ "../test/time_controller",
+ "//testing/gtest",
+ ]
+ absl_deps = [
+ "//third_party/abseil-cpp/absl/memory",
+ "//third_party/abseil-cpp/absl/strings",
+ "//third_party/abseil-cpp/absl/types:optional",
+ ]
+ }
+
+ if (!build_with_chromium) {
+ rtc_executable("rtc_event_log_rtp_dump") {
+ testonly = true
+ sources = [ "rtc_event_log/rtc_event_log2rtp_dump.cc" ]
+ deps = [
+ ":rtc_event_log_parser",
+ "../api:array_view",
+ "../api:rtp_headers",
+ "../api/rtc_event_log",
+ "../modules/rtp_rtcp",
+ "../modules/rtp_rtcp:rtp_rtcp_format",
+ "../rtc_base:checks",
+ "../rtc_base:protobuf_utils",
+ "../test:rtp_test_utils",
+ "//third_party/abseil-cpp/absl/flags:flag",
+ "//third_party/abseil-cpp/absl/flags:parse",
+ "//third_party/abseil-cpp/absl/flags:usage",
+ "//third_party/abseil-cpp/absl/memory",
+ "//third_party/abseil-cpp/absl/strings",
+ "//third_party/abseil-cpp/absl/types:optional",
+ ]
+ }
+ }
+ }
+}
+
+rtc_library("ice_log") {
+ sources = [
+ "rtc_event_log/events/rtc_event_dtls_transport_state.cc",
+ "rtc_event_log/events/rtc_event_dtls_transport_state.h",
+ "rtc_event_log/events/rtc_event_dtls_writable_state.cc",
+ "rtc_event_log/events/rtc_event_dtls_writable_state.h",
+ "rtc_event_log/events/rtc_event_ice_candidate_pair.cc",
+ "rtc_event_log/events/rtc_event_ice_candidate_pair.h",
+ "rtc_event_log/events/rtc_event_ice_candidate_pair_config.cc",
+ "rtc_event_log/events/rtc_event_ice_candidate_pair_config.h",
+ "rtc_event_log/ice_logger.cc",
+ "rtc_event_log/ice_logger.h",
+ ]
+
+ deps = [
+ ":rtc_event_field",
+ "../api:dtls_transport_interface",
+ "../api:libjingle_logging_api",
+ "../api/rtc_event_log",
+ "../api/units:timestamp",
+ ]
+ absl_deps = [
+ "//third_party/abseil-cpp/absl/memory",
+ "//third_party/abseil-cpp/absl/strings",
+ ]
+}
+
+if (rtc_include_tests) {
+ rtc_library("mocks") {
+ testonly = true
+ sources = [
+ "rtc_event_log/mock/mock_rtc_event_log.cc",
+ "rtc_event_log/mock/mock_rtc_event_log.h",
+ ]
+ deps = [
+ "../api/rtc_event_log",
+ "../test:test_support",
+ ]
+ }
+}
diff --git a/third_party/libwebrtc/logging/OWNERS b/third_party/libwebrtc/logging/OWNERS
new file mode 100644
index 0000000000..96b781d87d
--- /dev/null
+++ b/third_party/libwebrtc/logging/OWNERS
@@ -0,0 +1,2 @@
+stefan@webrtc.org
+terelius@webrtc.org
diff --git a/third_party/libwebrtc/logging/g3doc/rtc_event_log.md b/third_party/libwebrtc/logging/g3doc/rtc_event_log.md
new file mode 100644
index 0000000000..7ffeb68840
--- /dev/null
+++ b/third_party/libwebrtc/logging/g3doc/rtc_event_log.md
@@ -0,0 +1,85 @@
+<!-- go/cmark -->
+<!--* freshness: {owner: 'terelius' reviewed: '2021-06-02'} *-->
+
+# RTC event log
+
+## Overview
+
+RTC event logs can be enabled to capture in-depth inpformation about sent and
+received packets and the internal state of some WebRTC components. The logs are
+useful to understand network behavior and to debug issues around connectivity,
+bandwidth estimation and audio jitter buffers.
+
+The contents include:
+
+* Sent and received RTP headers
+* Full RTCP feedback
+* ICE candidates, pings and responses
+* Bandwidth estimator events, including loss-based estimate, delay-based
+ estimate, probe results and ALR state
+* Audio network adaptation settings
+* Audio playout events
+
+## Binary wire format
+
+No guarantees are made on the wire format, and the format may change without
+prior notice. To maintain compatibility with past and future formats, analysis
+tools should be built on top of the provided
+[rtc_event_log_parser.h](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/logging/rtc_event_log/rtc_event_log_parser.h)
+
+In particular, an analysis tool should *not* read the log as a protobuf.
+
+## Visualization
+
+Since the logs contain a substantial amount of data, it is usually convenient to
+get an overview by visualizing them as a set of plots. Use the command:
+
+```
+out/Default/event_log_visualizer /path/to/log_file | python
+```
+
+This visualization requires matplotlib to be installed. The tool is capable of
+producing a substantial number of plots, of which only a handful are generated
+by default. You can select which plots are generated though the `--plot=`
+command line argument. For example, the command
+
+```
+out/Default/event_log_visualizer \
+ --plot=incoming_packet_sizes,incoming_stream_bitrate \
+ /path/to/log_file | python
+```
+
+plots the sizes of incoming packets and the bitrate per incoming stream.
+
+You can get a full list of options for the `--plot` argument through
+
+```
+out/Default/event_log_visualizer --list_plots /path/to/log_file
+```
+
+You can also synchronize the x-axis between all plots (so zooming or
+panning in one plot affects all of them), by adding the command line
+argument `--shared_xaxis`.
+
+
+## Viewing the raw log contents as text
+
+If you know which format version the log file uses, you can view the raw
+contents as text. For version 1, you can use the command
+
+```
+out/Default/protoc --decode webrtc.rtclog.EventStream \
+ ./logging/rtc_event_log/rtc_event_log.proto < /path/to/log_file
+```
+
+Similarly, you can use
+
+```
+out/Default/protoc --decode webrtc.rtclog2.EventStream \
+ ./logging/rtc_event_log/rtc_event_log2.proto < /path/to/log_file
+```
+
+for logs that use version 2. However, note that not all of the contents will be
+human readable. Some fields are based on the raw RTP format or may be encoded as
+deltas relative to previous fields. Such fields will be printed as a list of
+bytes.
diff --git a/third_party/libwebrtc/logging/rtc_event_audio_gn/moz.build b/third_party/libwebrtc/logging/rtc_event_audio_gn/moz.build
new file mode 100644
index 0000000000..ddc4a9cc8b
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_audio_gn/moz.build
@@ -0,0 +1,229 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+ ### This moz.build was AUTOMATICALLY GENERATED from a GN config, ###
+ ### DO NOT edit it by hand. ###
+
+COMPILE_FLAGS["OS_INCLUDES"] = []
+AllowCompilerWarnings()
+
+DEFINES["ABSL_ALLOCATOR_NOTHROW"] = "1"
+DEFINES["RTC_DAV1D_IN_INTERNAL_DECODER_FACTORY"] = True
+DEFINES["RTC_ENABLE_VP9"] = True
+DEFINES["WEBRTC_ENABLE_PROTOBUF"] = "0"
+DEFINES["WEBRTC_LIBRARY_IMPL"] = True
+DEFINES["WEBRTC_MOZILLA_BUILD"] = True
+DEFINES["WEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS"] = "0"
+DEFINES["WEBRTC_STRICT_FIELD_TRIALS"] = "0"
+
+FINAL_LIBRARY = "webrtc"
+
+
+LOCAL_INCLUDES += [
+ "!/ipc/ipdl/_ipdlheaders",
+ "!/third_party/libwebrtc/gen",
+ "/ipc/chromium/src",
+ "/third_party/libwebrtc/",
+ "/third_party/libwebrtc/third_party/abseil-cpp/",
+ "/tools/profiler/public"
+]
+
+UNIFIED_SOURCES += [
+ "/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_audio_network_adaptation.cc",
+ "/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_audio_playout.cc",
+ "/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_audio_receive_stream_config.cc",
+ "/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_audio_send_stream_config.cc",
+ "/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_neteq_set_minimum_delay.cc"
+]
+
+if not CONFIG["MOZ_DEBUG"]:
+
+ DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "0"
+ DEFINES["NDEBUG"] = True
+ DEFINES["NVALGRIND"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1":
+
+ DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "1"
+
+if CONFIG["OS_TARGET"] == "Android":
+
+ DEFINES["ANDROID"] = True
+ DEFINES["ANDROID_NDK_VERSION_ROLL"] = "r22_1"
+ DEFINES["HAVE_SYS_UIO_H"] = True
+ DEFINES["WEBRTC_ANDROID"] = True
+ DEFINES["WEBRTC_ANDROID_OPENSLES"] = True
+ DEFINES["WEBRTC_LINUX"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_GNU_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+ OS_LIBS += [
+ "log"
+ ]
+
+if CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["WEBRTC_MAC"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_LIBCPP_HAS_NO_ALIGNED_ALLOCATION"] = True
+ DEFINES["__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES"] = "0"
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["USE_AURA"] = "1"
+ DEFINES["USE_GLIB"] = "1"
+ DEFINES["USE_NSS_CERTS"] = "1"
+ DEFINES["USE_OZONE"] = "1"
+ DEFINES["USE_UDEV"] = True
+ DEFINES["WEBRTC_LINUX"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+ DEFINES["_LARGEFILE64_SOURCE"] = True
+ DEFINES["_LARGEFILE_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "OpenBSD":
+
+ DEFINES["USE_GLIB"] = "1"
+ DEFINES["USE_OZONE"] = "1"
+ DEFINES["USE_X11"] = "1"
+ DEFINES["WEBRTC_BSD"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+ DEFINES["_LARGEFILE64_SOURCE"] = True
+ DEFINES["_LARGEFILE_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "WINNT":
+
+ DEFINES["CERT_CHAIN_PARA_HAS_EXTRA_FIELDS"] = True
+ DEFINES["NOMINMAX"] = True
+ DEFINES["NTDDI_VERSION"] = "0x0A000000"
+ DEFINES["PSAPI_VERSION"] = "2"
+ DEFINES["UNICODE"] = True
+ DEFINES["USE_AURA"] = "1"
+ DEFINES["WEBRTC_WIN"] = True
+ DEFINES["WIN32"] = True
+ DEFINES["WIN32_LEAN_AND_MEAN"] = True
+ DEFINES["WINAPI_FAMILY"] = "WINAPI_FAMILY_DESKTOP_APP"
+ DEFINES["WINVER"] = "0x0A00"
+ DEFINES["_ATL_NO_OPENGL"] = True
+ DEFINES["_CRT_RAND_S"] = True
+ DEFINES["_CRT_SECURE_NO_DEPRECATE"] = True
+ DEFINES["_ENABLE_EXTENDED_ALIGNED_STORAGE"] = True
+ DEFINES["_HAS_EXCEPTIONS"] = "0"
+ DEFINES["_HAS_NODISCARD"] = True
+ DEFINES["_SCL_SECURE_NO_DEPRECATE"] = True
+ DEFINES["_SECURE_ATL"] = True
+ DEFINES["_UNICODE"] = True
+ DEFINES["_WIN32_WINNT"] = "0x0A00"
+ DEFINES["_WINDOWS"] = True
+ DEFINES["__STD_C"] = True
+
+ OS_LIBS += [
+ "winmm"
+ ]
+
+if CONFIG["CPU_ARCH"] == "aarch64":
+
+ DEFINES["WEBRTC_ARCH_ARM64"] = True
+ DEFINES["WEBRTC_HAS_NEON"] = True
+
+if CONFIG["CPU_ARCH"] == "arm":
+
+ CXXFLAGS += [
+ "-mfpu=neon"
+ ]
+
+ DEFINES["WEBRTC_ARCH_ARM"] = True
+ DEFINES["WEBRTC_ARCH_ARM_V7"] = True
+ DEFINES["WEBRTC_HAS_NEON"] = True
+
+if CONFIG["CPU_ARCH"] == "mips32":
+
+ DEFINES["MIPS32_LE"] = True
+ DEFINES["MIPS_FPU_LE"] = True
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "mips64":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86":
+
+ DEFINES["WEBRTC_ENABLE_AVX2"] = True
+
+if CONFIG["CPU_ARCH"] == "x86_64":
+
+ DEFINES["WEBRTC_ENABLE_AVX2"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Android":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "OpenBSD":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "WINNT":
+
+ DEFINES["_HAS_ITERATOR_DEBUGGING"] = "0"
+
+if CONFIG["MOZ_X11"] == "1" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["USE_X11"] = "1"
+
+if CONFIG["CPU_ARCH"] == "arm" and CONFIG["OS_TARGET"] == "Android":
+
+ OS_LIBS += [
+ "android_support",
+ "unwind"
+ ]
+
+if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Android":
+
+ CXXFLAGS += [
+ "-msse2"
+ ]
+
+ OS_LIBS += [
+ "android_support"
+ ]
+
+if CONFIG["CPU_ARCH"] == "aarch64" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "arm" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Linux":
+
+ CXXFLAGS += [
+ "-msse2"
+ ]
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86_64" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+Library("rtc_event_audio_gn")
diff --git a/third_party/libwebrtc/logging/rtc_event_bwe_gn/moz.build b/third_party/libwebrtc/logging/rtc_event_bwe_gn/moz.build
new file mode 100644
index 0000000000..270182b2be
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_bwe_gn/moz.build
@@ -0,0 +1,230 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+ ### This moz.build was AUTOMATICALLY GENERATED from a GN config, ###
+ ### DO NOT edit it by hand. ###
+
+COMPILE_FLAGS["OS_INCLUDES"] = []
+AllowCompilerWarnings()
+
+DEFINES["ABSL_ALLOCATOR_NOTHROW"] = "1"
+DEFINES["RTC_DAV1D_IN_INTERNAL_DECODER_FACTORY"] = True
+DEFINES["RTC_ENABLE_VP9"] = True
+DEFINES["WEBRTC_ENABLE_PROTOBUF"] = "0"
+DEFINES["WEBRTC_LIBRARY_IMPL"] = True
+DEFINES["WEBRTC_MOZILLA_BUILD"] = True
+DEFINES["WEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS"] = "0"
+DEFINES["WEBRTC_STRICT_FIELD_TRIALS"] = "0"
+
+FINAL_LIBRARY = "webrtc"
+
+
+LOCAL_INCLUDES += [
+ "!/ipc/ipdl/_ipdlheaders",
+ "!/third_party/libwebrtc/gen",
+ "/ipc/chromium/src",
+ "/third_party/libwebrtc/",
+ "/third_party/libwebrtc/third_party/abseil-cpp/",
+ "/tools/profiler/public"
+]
+
+UNIFIED_SOURCES += [
+ "/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_bwe_update_delay_based.cc",
+ "/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_bwe_update_loss_based.cc",
+ "/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_probe_cluster_created.cc",
+ "/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_probe_result_failure.cc",
+ "/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_probe_result_success.cc",
+ "/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_route_change.cc"
+]
+
+if not CONFIG["MOZ_DEBUG"]:
+
+ DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "0"
+ DEFINES["NDEBUG"] = True
+ DEFINES["NVALGRIND"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1":
+
+ DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "1"
+
+if CONFIG["OS_TARGET"] == "Android":
+
+ DEFINES["ANDROID"] = True
+ DEFINES["ANDROID_NDK_VERSION_ROLL"] = "r22_1"
+ DEFINES["HAVE_SYS_UIO_H"] = True
+ DEFINES["WEBRTC_ANDROID"] = True
+ DEFINES["WEBRTC_ANDROID_OPENSLES"] = True
+ DEFINES["WEBRTC_LINUX"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_GNU_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+ OS_LIBS += [
+ "log"
+ ]
+
+if CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["WEBRTC_MAC"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_LIBCPP_HAS_NO_ALIGNED_ALLOCATION"] = True
+ DEFINES["__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES"] = "0"
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["USE_AURA"] = "1"
+ DEFINES["USE_GLIB"] = "1"
+ DEFINES["USE_NSS_CERTS"] = "1"
+ DEFINES["USE_OZONE"] = "1"
+ DEFINES["USE_UDEV"] = True
+ DEFINES["WEBRTC_LINUX"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+ DEFINES["_LARGEFILE64_SOURCE"] = True
+ DEFINES["_LARGEFILE_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "OpenBSD":
+
+ DEFINES["USE_GLIB"] = "1"
+ DEFINES["USE_OZONE"] = "1"
+ DEFINES["USE_X11"] = "1"
+ DEFINES["WEBRTC_BSD"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+ DEFINES["_LARGEFILE64_SOURCE"] = True
+ DEFINES["_LARGEFILE_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "WINNT":
+
+ DEFINES["CERT_CHAIN_PARA_HAS_EXTRA_FIELDS"] = True
+ DEFINES["NOMINMAX"] = True
+ DEFINES["NTDDI_VERSION"] = "0x0A000000"
+ DEFINES["PSAPI_VERSION"] = "2"
+ DEFINES["UNICODE"] = True
+ DEFINES["USE_AURA"] = "1"
+ DEFINES["WEBRTC_WIN"] = True
+ DEFINES["WIN32"] = True
+ DEFINES["WIN32_LEAN_AND_MEAN"] = True
+ DEFINES["WINAPI_FAMILY"] = "WINAPI_FAMILY_DESKTOP_APP"
+ DEFINES["WINVER"] = "0x0A00"
+ DEFINES["_ATL_NO_OPENGL"] = True
+ DEFINES["_CRT_RAND_S"] = True
+ DEFINES["_CRT_SECURE_NO_DEPRECATE"] = True
+ DEFINES["_ENABLE_EXTENDED_ALIGNED_STORAGE"] = True
+ DEFINES["_HAS_EXCEPTIONS"] = "0"
+ DEFINES["_HAS_NODISCARD"] = True
+ DEFINES["_SCL_SECURE_NO_DEPRECATE"] = True
+ DEFINES["_SECURE_ATL"] = True
+ DEFINES["_UNICODE"] = True
+ DEFINES["_WIN32_WINNT"] = "0x0A00"
+ DEFINES["_WINDOWS"] = True
+ DEFINES["__STD_C"] = True
+
+ OS_LIBS += [
+ "winmm"
+ ]
+
+if CONFIG["CPU_ARCH"] == "aarch64":
+
+ DEFINES["WEBRTC_ARCH_ARM64"] = True
+ DEFINES["WEBRTC_HAS_NEON"] = True
+
+if CONFIG["CPU_ARCH"] == "arm":
+
+ CXXFLAGS += [
+ "-mfpu=neon"
+ ]
+
+ DEFINES["WEBRTC_ARCH_ARM"] = True
+ DEFINES["WEBRTC_ARCH_ARM_V7"] = True
+ DEFINES["WEBRTC_HAS_NEON"] = True
+
+if CONFIG["CPU_ARCH"] == "mips32":
+
+ DEFINES["MIPS32_LE"] = True
+ DEFINES["MIPS_FPU_LE"] = True
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "mips64":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86":
+
+ DEFINES["WEBRTC_ENABLE_AVX2"] = True
+
+if CONFIG["CPU_ARCH"] == "x86_64":
+
+ DEFINES["WEBRTC_ENABLE_AVX2"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Android":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "OpenBSD":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "WINNT":
+
+ DEFINES["_HAS_ITERATOR_DEBUGGING"] = "0"
+
+if CONFIG["MOZ_X11"] == "1" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["USE_X11"] = "1"
+
+if CONFIG["CPU_ARCH"] == "arm" and CONFIG["OS_TARGET"] == "Android":
+
+ OS_LIBS += [
+ "android_support",
+ "unwind"
+ ]
+
+if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Android":
+
+ CXXFLAGS += [
+ "-msse2"
+ ]
+
+ OS_LIBS += [
+ "android_support"
+ ]
+
+if CONFIG["CPU_ARCH"] == "aarch64" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "arm" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Linux":
+
+ CXXFLAGS += [
+ "-msse2"
+ ]
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86_64" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+Library("rtc_event_bwe_gn")
diff --git a/third_party/libwebrtc/logging/rtc_event_field_gn/moz.build b/third_party/libwebrtc/logging/rtc_event_field_gn/moz.build
new file mode 100644
index 0000000000..7a816f4328
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_field_gn/moz.build
@@ -0,0 +1,228 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+ ### This moz.build was AUTOMATICALLY GENERATED from a GN config, ###
+ ### DO NOT edit it by hand. ###
+
+COMPILE_FLAGS["OS_INCLUDES"] = []
+AllowCompilerWarnings()
+
+DEFINES["ABSL_ALLOCATOR_NOTHROW"] = "1"
+DEFINES["RTC_DAV1D_IN_INTERNAL_DECODER_FACTORY"] = True
+DEFINES["RTC_ENABLE_VP9"] = True
+DEFINES["WEBRTC_ENABLE_PROTOBUF"] = "0"
+DEFINES["WEBRTC_LIBRARY_IMPL"] = True
+DEFINES["WEBRTC_MOZILLA_BUILD"] = True
+DEFINES["WEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS"] = "0"
+DEFINES["WEBRTC_STRICT_FIELD_TRIALS"] = "0"
+
+FINAL_LIBRARY = "webrtc"
+
+
+LOCAL_INCLUDES += [
+ "!/ipc/ipdl/_ipdlheaders",
+ "!/third_party/libwebrtc/gen",
+ "/ipc/chromium/src",
+ "/third_party/libwebrtc/",
+ "/third_party/libwebrtc/third_party/abseil-cpp/",
+ "/tools/profiler/public"
+]
+
+UNIFIED_SOURCES += [
+ "/third_party/libwebrtc/logging/rtc_event_log/events/fixed_length_encoding_parameters_v3.cc",
+ "/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_field_encoding.cc",
+ "/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_field_encoding_parser.cc",
+ "/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_field_extraction.cc"
+]
+
+if not CONFIG["MOZ_DEBUG"]:
+
+ DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "0"
+ DEFINES["NDEBUG"] = True
+ DEFINES["NVALGRIND"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1":
+
+ DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "1"
+
+if CONFIG["OS_TARGET"] == "Android":
+
+ DEFINES["ANDROID"] = True
+ DEFINES["ANDROID_NDK_VERSION_ROLL"] = "r22_1"
+ DEFINES["HAVE_SYS_UIO_H"] = True
+ DEFINES["WEBRTC_ANDROID"] = True
+ DEFINES["WEBRTC_ANDROID_OPENSLES"] = True
+ DEFINES["WEBRTC_LINUX"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_GNU_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+ OS_LIBS += [
+ "log"
+ ]
+
+if CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["WEBRTC_MAC"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_LIBCPP_HAS_NO_ALIGNED_ALLOCATION"] = True
+ DEFINES["__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES"] = "0"
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["USE_AURA"] = "1"
+ DEFINES["USE_GLIB"] = "1"
+ DEFINES["USE_NSS_CERTS"] = "1"
+ DEFINES["USE_OZONE"] = "1"
+ DEFINES["USE_UDEV"] = True
+ DEFINES["WEBRTC_LINUX"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+ DEFINES["_LARGEFILE64_SOURCE"] = True
+ DEFINES["_LARGEFILE_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "OpenBSD":
+
+ DEFINES["USE_GLIB"] = "1"
+ DEFINES["USE_OZONE"] = "1"
+ DEFINES["USE_X11"] = "1"
+ DEFINES["WEBRTC_BSD"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+ DEFINES["_LARGEFILE64_SOURCE"] = True
+ DEFINES["_LARGEFILE_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "WINNT":
+
+ DEFINES["CERT_CHAIN_PARA_HAS_EXTRA_FIELDS"] = True
+ DEFINES["NOMINMAX"] = True
+ DEFINES["NTDDI_VERSION"] = "0x0A000000"
+ DEFINES["PSAPI_VERSION"] = "2"
+ DEFINES["UNICODE"] = True
+ DEFINES["USE_AURA"] = "1"
+ DEFINES["WEBRTC_WIN"] = True
+ DEFINES["WIN32"] = True
+ DEFINES["WIN32_LEAN_AND_MEAN"] = True
+ DEFINES["WINAPI_FAMILY"] = "WINAPI_FAMILY_DESKTOP_APP"
+ DEFINES["WINVER"] = "0x0A00"
+ DEFINES["_ATL_NO_OPENGL"] = True
+ DEFINES["_CRT_RAND_S"] = True
+ DEFINES["_CRT_SECURE_NO_DEPRECATE"] = True
+ DEFINES["_ENABLE_EXTENDED_ALIGNED_STORAGE"] = True
+ DEFINES["_HAS_EXCEPTIONS"] = "0"
+ DEFINES["_HAS_NODISCARD"] = True
+ DEFINES["_SCL_SECURE_NO_DEPRECATE"] = True
+ DEFINES["_SECURE_ATL"] = True
+ DEFINES["_UNICODE"] = True
+ DEFINES["_WIN32_WINNT"] = "0x0A00"
+ DEFINES["_WINDOWS"] = True
+ DEFINES["__STD_C"] = True
+
+ OS_LIBS += [
+ "winmm"
+ ]
+
+if CONFIG["CPU_ARCH"] == "aarch64":
+
+ DEFINES["WEBRTC_ARCH_ARM64"] = True
+ DEFINES["WEBRTC_HAS_NEON"] = True
+
+if CONFIG["CPU_ARCH"] == "arm":
+
+ CXXFLAGS += [
+ "-mfpu=neon"
+ ]
+
+ DEFINES["WEBRTC_ARCH_ARM"] = True
+ DEFINES["WEBRTC_ARCH_ARM_V7"] = True
+ DEFINES["WEBRTC_HAS_NEON"] = True
+
+if CONFIG["CPU_ARCH"] == "mips32":
+
+ DEFINES["MIPS32_LE"] = True
+ DEFINES["MIPS_FPU_LE"] = True
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "mips64":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86":
+
+ DEFINES["WEBRTC_ENABLE_AVX2"] = True
+
+if CONFIG["CPU_ARCH"] == "x86_64":
+
+ DEFINES["WEBRTC_ENABLE_AVX2"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Android":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "OpenBSD":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "WINNT":
+
+ DEFINES["_HAS_ITERATOR_DEBUGGING"] = "0"
+
+if CONFIG["MOZ_X11"] == "1" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["USE_X11"] = "1"
+
+if CONFIG["CPU_ARCH"] == "arm" and CONFIG["OS_TARGET"] == "Android":
+
+ OS_LIBS += [
+ "android_support",
+ "unwind"
+ ]
+
+if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Android":
+
+ CXXFLAGS += [
+ "-msse2"
+ ]
+
+ OS_LIBS += [
+ "android_support"
+ ]
+
+if CONFIG["CPU_ARCH"] == "aarch64" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "arm" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Linux":
+
+ CXXFLAGS += [
+ "-msse2"
+ ]
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86_64" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+Library("rtc_event_field_gn")
diff --git a/third_party/libwebrtc/logging/rtc_event_log/DEPS b/third_party/libwebrtc/logging/rtc_event_log/DEPS
new file mode 100644
index 0000000000..fe8a9114ed
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/DEPS
@@ -0,0 +1,7 @@
+include_rules = [
+ "+call",
+ "+modules/audio_coding/audio_network_adaptor",
+ "+modules/congestion_controller",
+ "+modules/rtp_rtcp",
+ "+system_wrappers",
+]
diff --git a/third_party/libwebrtc/logging/rtc_event_log/encoder/bit_writer.cc b/third_party/libwebrtc/logging/rtc_event_log/encoder/bit_writer.cc
new file mode 100644
index 0000000000..e8748d3db3
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/encoder/bit_writer.cc
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "logging/rtc_event_log/encoder/bit_writer.h"
+
+namespace webrtc {
+
+namespace {
+size_t BitsToBytes(size_t bits) {
+ return (bits / 8) + (bits % 8 > 0 ? 1 : 0);
+}
+} // namespace
+
+void BitWriter::WriteBits(uint64_t val, size_t bit_count) {
+ RTC_DCHECK(valid_);
+ const bool success = bit_writer_.WriteBits(val, bit_count);
+ RTC_DCHECK(success);
+ written_bits_ += bit_count;
+}
+
+void BitWriter::WriteBits(absl::string_view input) {
+ RTC_DCHECK(valid_);
+ for (char c : input) {
+ WriteBits(static_cast<unsigned char>(c), CHAR_BIT);
+ }
+}
+
+// Returns everything that was written so far.
+// Nothing more may be written after this is called.
+std::string BitWriter::GetString() {
+ RTC_DCHECK(valid_);
+ valid_ = false;
+
+ buffer_.resize(BitsToBytes(written_bits_));
+ written_bits_ = 0;
+
+ std::string result;
+ std::swap(buffer_, result);
+ return result;
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/logging/rtc_event_log/encoder/bit_writer.h b/third_party/libwebrtc/logging/rtc_event_log/encoder/bit_writer.h
new file mode 100644
index 0000000000..421e7c4370
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/encoder/bit_writer.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef LOGGING_RTC_EVENT_LOG_ENCODER_BIT_WRITER_H_
+#define LOGGING_RTC_EVENT_LOG_ENCODER_BIT_WRITER_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+#include <utility>
+
+#include "absl/strings/string_view.h"
+#include "rtc_base/bit_buffer.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+// Wrap BitBufferWriter and extend its functionality by (1) keeping track of
+// the number of bits written and (2) owning its buffer.
+class BitWriter final {
+ public:
+ explicit BitWriter(size_t byte_count)
+ : buffer_(byte_count, '\0'),
+ bit_writer_(reinterpret_cast<uint8_t*>(&buffer_[0]), buffer_.size()),
+ written_bits_(0),
+ valid_(true) {
+ RTC_DCHECK_GT(byte_count, 0);
+ }
+
+ BitWriter(const BitWriter&) = delete;
+ BitWriter& operator=(const BitWriter&) = delete;
+
+ void WriteBits(uint64_t val, size_t bit_count);
+
+ void WriteBits(absl::string_view input);
+
+ // Returns everything that was written so far.
+ // Nothing more may be written after this is called.
+ std::string GetString();
+
+ private:
+ std::string buffer_;
+ rtc::BitBufferWriter bit_writer_;
+ // Note: Counting bits instead of bytes wraps around earlier than it has to,
+ // which means the maximum length is lower than it could be. We don't expect
+ // to go anywhere near the limit, though, so this is good enough.
+ size_t written_bits_;
+ bool valid_;
+};
+
+} // namespace webrtc
+
+#endif // LOGGING_RTC_EVENT_LOG_ENCODER_BIT_WRITER_H_
diff --git a/third_party/libwebrtc/logging/rtc_event_log/encoder/blob_encoding.cc b/third_party/libwebrtc/logging/rtc_event_log/encoder/blob_encoding.cc
new file mode 100644
index 0000000000..96699dc96a
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/encoder/blob_encoding.cc
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2018 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/encoder/blob_encoding.h"
+
+#include <cstdint>
+
+#include "logging/rtc_event_log/encoder/var_int.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+
+namespace webrtc {
+
+std::string EncodeBlobs(const std::vector<std::string>& blobs) {
+ RTC_DCHECK(!blobs.empty());
+
+ size_t result_length_bound = kMaxVarIntLengthBytes * blobs.size();
+ for (const auto& blob : blobs) {
+ // Providing an input so long that it would cause a wrap-around is an error.
+ RTC_DCHECK_GE(result_length_bound + blob.length(), result_length_bound);
+ result_length_bound += blob.length();
+ }
+
+ std::string result;
+ result.reserve(result_length_bound);
+
+ // First, encode all of the lengths.
+ for (absl::string_view blob : blobs) {
+ result += EncodeVarInt(blob.length());
+ }
+
+ // Second, encode the actual blobs.
+ for (absl::string_view blob : blobs) {
+ result.append(blob.data(), blob.length());
+ }
+
+ RTC_DCHECK_LE(result.size(), result_length_bound);
+ return result;
+}
+
+std::vector<absl::string_view> DecodeBlobs(absl::string_view encoded_blobs,
+ size_t num_of_blobs) {
+ if (encoded_blobs.empty()) {
+ RTC_LOG(LS_WARNING) << "Corrupt input; empty input.";
+ return std::vector<absl::string_view>();
+ }
+
+ if (num_of_blobs == 0u) {
+ RTC_LOG(LS_WARNING)
+ << "Corrupt input; number of blobs must be greater than 0.";
+ return std::vector<absl::string_view>();
+ }
+
+ // Read the lengths of all blobs.
+ std::vector<uint64_t> lengths(num_of_blobs);
+ for (size_t i = 0; i < num_of_blobs; ++i) {
+ bool success = false;
+ std::tie(success, encoded_blobs) = DecodeVarInt(encoded_blobs, &lengths[i]);
+ if (!success) {
+ RTC_LOG(LS_WARNING) << "Corrupt input; varint decoding failed.";
+ return std::vector<absl::string_view>();
+ }
+ }
+
+ // Read the blobs themselves.
+ std::vector<absl::string_view> blobs(num_of_blobs);
+ for (size_t i = 0; i < num_of_blobs; ++i) {
+ if (lengths[i] > encoded_blobs.length()) {
+ RTC_LOG(LS_WARNING) << "Corrupt input; blob sizes exceed input size.";
+ return std::vector<absl::string_view>();
+ }
+
+ blobs[i] = encoded_blobs.substr(0, lengths[i]);
+ encoded_blobs = encoded_blobs.substr(lengths[i]);
+ }
+
+ if (!encoded_blobs.empty()) {
+ RTC_LOG(LS_WARNING) << "Corrupt input; unrecognized trailer.";
+ return std::vector<absl::string_view>();
+ }
+
+ return blobs;
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/logging/rtc_event_log/encoder/blob_encoding.h b/third_party/libwebrtc/logging/rtc_event_log/encoder/blob_encoding.h
new file mode 100644
index 0000000000..123fffe8e8
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/encoder/blob_encoding.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2018 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_ENCODER_BLOB_ENCODING_H_
+#define LOGGING_RTC_EVENT_LOG_ENCODER_BLOB_ENCODING_H_
+
+#include <stddef.h>
+
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+
+namespace webrtc {
+
+// Encode/decode a sequence of strings, whose length is not known to be
+// discernable from the blob itself (i.e. without being transmitted OOB),
+// in a way that would allow us to separate them again on the decoding side.
+// The number of blobs is assumed to be transmitted OOB. For example, if
+// multiple sequences of different blobs are sent, but all sequences contain
+// the same number of blobs, it is beneficial to not encode the number of blobs.
+//
+// EncodeBlobs() must be given a non-empty vector. The blobs themselves may
+// be equal to "", though.
+// EncodeBlobs() may not fail.
+// EncodeBlobs() never returns the empty string.
+//
+// Calling DecodeBlobs() on an empty string, or with `num_of_blobs` set to 0,
+// is an error.
+// DecodeBlobs() returns an empty vector if it fails, e.g. due to a mismatch
+// between `num_of_blobs` and `encoded_blobs`, which can happen if
+// `encoded_blobs` is corrupted.
+// When successful, DecodeBlobs() returns a vector of string_view objects,
+// which refer to the original input (`encoded_blobs`), and therefore may
+// not outlive it.
+//
+// Note that the returned std::string might have been reserved for significantly
+// more memory than it ends up using. If the caller to EncodeBlobs() intends
+// to store the result long-term, they should consider shrink_to_fit()-ing it.
+std::string EncodeBlobs(const std::vector<std::string>& blobs);
+std::vector<absl::string_view> DecodeBlobs(absl::string_view encoded_blobs,
+ size_t num_of_blobs);
+
+} // namespace webrtc
+
+#endif // LOGGING_RTC_EVENT_LOG_ENCODER_BLOB_ENCODING_H_
diff --git a/third_party/libwebrtc/logging/rtc_event_log/encoder/blob_encoding_unittest.cc b/third_party/libwebrtc/logging/rtc_event_log/encoder/blob_encoding_unittest.cc
new file mode 100644
index 0000000000..a25923f22d
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/encoder/blob_encoding_unittest.cc
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2018 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/encoder/blob_encoding.h"
+
+#include <string>
+#include <vector>
+
+#include "logging/rtc_event_log/encoder/var_int.h"
+#include "rtc_base/checks.h"
+#include "test/gtest.h"
+
+using CharT = std::string::value_type;
+
+namespace webrtc {
+
+namespace {
+
+void TestEncodingAndDecoding(const std::vector<std::string>& blobs) {
+ RTC_DCHECK(!blobs.empty());
+
+ const std::string encoded = EncodeBlobs(blobs);
+ ASSERT_FALSE(encoded.empty());
+
+ const std::vector<absl::string_view> decoded =
+ DecodeBlobs(encoded, blobs.size());
+
+ ASSERT_EQ(decoded.size(), blobs.size());
+ for (size_t i = 0; i < decoded.size(); ++i) {
+ ASSERT_EQ(decoded[i], blobs[i]);
+ }
+}
+
+void TestGracefulErrorHandling(absl::string_view encoded_blobs,
+ size_t num_of_blobs) {
+ const std::vector<absl::string_view> decoded =
+ DecodeBlobs(encoded_blobs, num_of_blobs);
+ EXPECT_TRUE(decoded.empty());
+}
+
+} // namespace
+
+TEST(BlobEncoding, EmptyBlob) {
+ TestEncodingAndDecoding({""});
+}
+
+TEST(BlobEncoding, SingleCharacterBlob) {
+ TestEncodingAndDecoding({"a"});
+}
+
+TEST(BlobEncoding, LongBlob) {
+ std::string blob = "";
+ for (size_t i = 0; i < 100000; ++i) {
+ blob += std::to_string(i + 1) + " Mississippi\n";
+ }
+ TestEncodingAndDecoding({blob});
+}
+
+TEST(BlobEncoding, BlobsOfVariousLengths) {
+ constexpr size_t kJump = 0xf032d; // Arbitrary.
+ constexpr size_t kMax = 0xffffff; // Arbitrary.
+
+ std::string blob;
+ blob.reserve(kMax);
+
+ for (size_t i = 0; i < kMax; i += kJump) {
+ blob.append(kJump, 'x');
+ TestEncodingAndDecoding({blob});
+ }
+}
+
+TEST(BlobEncoding, MultipleBlobs) {
+ std::vector<std::string> blobs;
+ for (size_t i = 0; i < 100000; ++i) {
+ blobs.push_back(std::to_string(i + 1) + " Mississippi\n");
+ }
+ TestEncodingAndDecoding(blobs);
+}
+
+TEST(BlobEncoding, DecodeBlobsHandlesErrorsGracefullyEmptyInput) {
+ TestGracefulErrorHandling("", 1);
+}
+
+TEST(BlobEncoding, DecodeBlobsHandlesErrorsGracefullyZeroBlobs) {
+ const std::string encoded = EncodeBlobs({"a"});
+ ASSERT_FALSE(encoded.empty());
+ TestGracefulErrorHandling(encoded, 0);
+}
+
+TEST(BlobEncoding, DecodeBlobsHandlesErrorsGracefullyBlobLengthTooSmall) {
+ std::string encoded = EncodeBlobs({"ab"});
+ ASSERT_FALSE(encoded.empty());
+ ASSERT_EQ(encoded[0], 0x02);
+ encoded[0] = 0x01;
+ TestGracefulErrorHandling(encoded, 1);
+}
+
+TEST(BlobEncoding, DecodeBlobsHandlesErrorsGracefullyBlobLengthTooLarge) {
+ std::string encoded = EncodeBlobs({"a"});
+ ASSERT_FALSE(encoded.empty());
+ ASSERT_EQ(encoded[0], 0x01);
+ encoded[0] = 0x02;
+ TestGracefulErrorHandling(encoded, 1);
+}
+
+TEST(BlobEncoding,
+ DecodeBlobsHandlesErrorsGracefullyNumberOfBlobsIncorrectlyHigh) {
+ const std::vector<std::string> blobs = {"a", "b"};
+ const std::string encoded = EncodeBlobs(blobs);
+ // Test focus - two empty strings encoded, but DecodeBlobs() told way more
+ // blobs are in the strings than could be expected.
+ TestGracefulErrorHandling(encoded, 1000);
+
+ // Test sanity - show that DecodeBlobs() would have worked if it got the
+ // correct input.
+ TestEncodingAndDecoding(blobs);
+}
+
+TEST(BlobEncoding, DecodeBlobsHandlesErrorsGracefullyDefectiveVarInt) {
+ std::string defective_varint;
+ for (size_t i = 0; i < kMaxVarIntLengthBytes; ++i) {
+ ASSERT_LE(kMaxVarIntLengthBytes, 0xffu);
+ defective_varint += static_cast<CharT>(static_cast<size_t>(0x80u) | i);
+ }
+ defective_varint += 0x01u;
+
+ const std::string defective_encoded = defective_varint + "whatever";
+
+ TestGracefulErrorHandling(defective_encoded, 1);
+}
+
+TEST(BlobEncoding, DecodeBlobsHandlesErrorsGracefullyLengthSumWrapAround) {
+ std::string max_size_varint;
+ for (size_t i = 0; i < kMaxVarIntLengthBytes - 1; ++i) {
+ max_size_varint += 0xffu;
+ }
+ max_size_varint += 0x7fu;
+
+ const std::string defective_encoded =
+ max_size_varint + max_size_varint + "whatever";
+
+ TestGracefulErrorHandling(defective_encoded, 2);
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/logging/rtc_event_log/encoder/delta_encoding.cc b/third_party/libwebrtc/logging/rtc_event_log/encoder/delta_encoding.cc
new file mode 100644
index 0000000000..c80424574c
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/encoder/delta_encoding.cc
@@ -0,0 +1,839 @@
+/*
+ * Copyright (c) 2018 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/encoder/delta_encoding.h"
+
+#include <algorithm>
+#include <limits>
+#include <memory>
+#include <utility>
+
+#include "absl/memory/memory.h"
+#include "absl/strings/string_view.h"
+#include "logging/rtc_event_log/encoder/bit_writer.h"
+#include "logging/rtc_event_log/encoder/var_int.h"
+#include "rtc_base/bit_buffer.h"
+#include "rtc_base/bitstream_reader.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/numerics/safe_conversions.h"
+
+namespace webrtc {
+namespace {
+
+// TODO(eladalon): Only build the decoder in tools and unit tests.
+
+bool g_force_unsigned_for_testing = false;
+bool g_force_signed_for_testing = false;
+
+size_t BitsToBytes(size_t bits) {
+ return (bits / 8) + (bits % 8 > 0 ? 1 : 0);
+}
+
+// TODO(eladalon): Replace by something more efficient.
+uint64_t UnsignedBitWidth(uint64_t input, bool zero_val_as_zero_width = false) {
+ if (zero_val_as_zero_width && input == 0) {
+ return 0;
+ }
+
+ uint64_t width = 0;
+ do { // input == 0 -> width == 1
+ width += 1;
+ input >>= 1;
+ } while (input != 0);
+ return width;
+}
+
+uint64_t SignedBitWidth(uint64_t max_pos_magnitude,
+ uint64_t max_neg_magnitude) {
+ const uint64_t bitwidth_pos = UnsignedBitWidth(max_pos_magnitude, true);
+ const uint64_t bitwidth_neg =
+ (max_neg_magnitude > 0) ? UnsignedBitWidth(max_neg_magnitude - 1, true)
+ : 0;
+ return 1 + std::max(bitwidth_pos, bitwidth_neg);
+}
+
+// Return the maximum integer of a given bit width.
+// Examples:
+// MaxUnsignedValueOfBitWidth(1) = 0x01
+// MaxUnsignedValueOfBitWidth(6) = 0x3f
+// MaxUnsignedValueOfBitWidth(8) = 0xff
+// MaxUnsignedValueOfBitWidth(32) = 0xffffffff
+uint64_t MaxUnsignedValueOfBitWidth(uint64_t bit_width) {
+ RTC_DCHECK_GE(bit_width, 1);
+ RTC_DCHECK_LE(bit_width, 64);
+ return (bit_width == 64) ? std::numeric_limits<uint64_t>::max()
+ : ((static_cast<uint64_t>(1) << bit_width) - 1);
+}
+
+// Computes the delta between `previous` and `current`, under the assumption
+// that wrap-around occurs after `width` is exceeded.
+uint64_t UnsignedDelta(uint64_t previous, uint64_t current, uint64_t bit_mask) {
+ return (current - previous) & bit_mask;
+}
+
+// Determines the encoding type (e.g. fixed-size encoding).
+// Given an encoding type, may also distinguish between some variants of it
+// (e.g. which fields of the fixed-size encoding are explicitly mentioned by
+// the header, and which are implicitly assumed to hold certain default values).
+enum class EncodingType {
+ kFixedSizeUnsignedDeltasNoEarlyWrapNoOpt = 0,
+ kFixedSizeSignedDeltasEarlyWrapAndOptSupported = 1,
+ kReserved1 = 2,
+ kReserved2 = 3,
+ kNumberOfEncodingTypes // Keep last
+};
+
+// The width of each field in the encoding header. Note that this is the
+// width in case the field exists; not all fields occur in all encoding types.
+constexpr size_t kBitsInHeaderForEncodingType = 2;
+constexpr size_t kBitsInHeaderForDeltaWidthBits = 6;
+constexpr size_t kBitsInHeaderForSignedDeltas = 1;
+constexpr size_t kBitsInHeaderForValuesOptional = 1;
+constexpr size_t kBitsInHeaderForValueWidthBits = 6;
+
+static_assert(static_cast<size_t>(EncodingType::kNumberOfEncodingTypes) <=
+ 1 << kBitsInHeaderForEncodingType,
+ "Not all encoding types fit.");
+
+// Default values for when the encoding header does not specify explicitly.
+constexpr bool kDefaultSignedDeltas = false;
+constexpr bool kDefaultValuesOptional = false;
+constexpr uint64_t kDefaultValueWidthBits = 64;
+
+// Parameters for fixed-size delta-encoding/decoding.
+// These are tailored for the sequence which will be encoded (e.g. widths).
+class FixedLengthEncodingParameters final {
+ public:
+ static bool ValidParameters(uint64_t delta_width_bits,
+ bool signed_deltas,
+ bool values_optional,
+ uint64_t value_width_bits) {
+ return (1 <= delta_width_bits && delta_width_bits <= 64 &&
+ 1 <= value_width_bits && value_width_bits <= 64 &&
+ delta_width_bits <= value_width_bits);
+ }
+
+ FixedLengthEncodingParameters(uint64_t delta_width_bits,
+ bool signed_deltas,
+ bool values_optional,
+ uint64_t value_width_bits)
+ : delta_width_bits_(delta_width_bits),
+ signed_deltas_(signed_deltas),
+ values_optional_(values_optional),
+ value_width_bits_(value_width_bits),
+ delta_mask_(MaxUnsignedValueOfBitWidth(delta_width_bits_)),
+ value_mask_(MaxUnsignedValueOfBitWidth(value_width_bits_)) {
+ RTC_DCHECK(ValidParameters(delta_width_bits, signed_deltas, values_optional,
+ value_width_bits));
+ }
+
+ // Number of bits necessary to hold the widest(*) of the deltas between the
+ // values in the sequence.
+ // (*) - Widest might not be the largest, if signed deltas are used.
+ uint64_t delta_width_bits() const { return delta_width_bits_; }
+
+ // Whether deltas are signed.
+ bool signed_deltas() const { return signed_deltas_; }
+
+ // Whether the values of the sequence are optional. That is, it may be
+ // that some of them do not have a value (not even a sentinel value indicating
+ // invalidity).
+ bool values_optional() const { return values_optional_; }
+
+ // Number of bits necessary to hold the largest value in the sequence.
+ uint64_t value_width_bits() const { return value_width_bits_; }
+
+ // Masks where only the bits relevant to the deltas/values are turned on.
+ uint64_t delta_mask() const { return delta_mask_; }
+ uint64_t value_mask() const { return value_mask_; }
+
+ void SetSignedDeltas(bool signed_deltas) { signed_deltas_ = signed_deltas; }
+ void SetDeltaWidthBits(uint64_t delta_width_bits) {
+ delta_width_bits_ = delta_width_bits;
+ delta_mask_ = MaxUnsignedValueOfBitWidth(delta_width_bits);
+ }
+
+ private:
+ uint64_t delta_width_bits_; // Normally const, but mutable in tests.
+ bool signed_deltas_; // Normally const, but mutable in tests.
+ const bool values_optional_;
+ const uint64_t value_width_bits_;
+
+ uint64_t delta_mask_; // Normally const, but mutable in tests.
+ const uint64_t value_mask_;
+};
+
+// Performs delta-encoding of a single (non-empty) sequence of values, using
+// an encoding where all deltas are encoded using the same number of bits.
+// (With the exception of optional elements; those are encoded as a bit vector
+// with one bit per element, plus a fixed number of bits for every element that
+// has a value.)
+class FixedLengthDeltaEncoder final {
+ public:
+ // See webrtc::EncodeDeltas() for general details.
+ // This function return a bit pattern that would allow the decoder to
+ // determine whether it was produced by FixedLengthDeltaEncoder, and can
+ // therefore be decoded by FixedLengthDeltaDecoder, or whether it was produced
+ // by a different encoder.
+ static std::string EncodeDeltas(
+ absl::optional<uint64_t> base,
+ const std::vector<absl::optional<uint64_t>>& values);
+
+ FixedLengthDeltaEncoder(const FixedLengthDeltaEncoder&) = delete;
+ FixedLengthDeltaEncoder& operator=(const FixedLengthDeltaEncoder&) = delete;
+
+ private:
+ // Calculate min/max values of unsigned/signed deltas, given the bit width
+ // of all the values in the series.
+ static void CalculateMinAndMaxDeltas(
+ absl::optional<uint64_t> base,
+ const std::vector<absl::optional<uint64_t>>& values,
+ uint64_t bit_width,
+ uint64_t* max_unsigned_delta,
+ uint64_t* max_pos_signed_delta,
+ uint64_t* min_neg_signed_delta);
+
+ // No effect outside of unit tests.
+ // In unit tests, may lead to forcing signed/unsigned deltas, etc.
+ static void ConsiderTestOverrides(FixedLengthEncodingParameters* params,
+ uint64_t delta_width_bits_signed,
+ uint64_t delta_width_bits_unsigned);
+
+ // FixedLengthDeltaEncoder objects are to be created by EncodeDeltas() and
+ // released by it before it returns. They're mostly a convenient way to
+ // avoid having to pass a lot of state between different functions.
+ // Therefore, it was deemed acceptable to let them have a reference to
+ // `values`, whose lifetime must exceed the lifetime of `this`.
+ FixedLengthDeltaEncoder(const FixedLengthEncodingParameters& params,
+ absl::optional<uint64_t> base,
+ const std::vector<absl::optional<uint64_t>>& values,
+ size_t existent_values_count);
+
+ // Perform delta-encoding using the parameters given to the ctor on the
+ // sequence of values given to the ctor.
+ std::string Encode();
+
+ // Exact lengths.
+ size_t OutputLengthBytes(size_t existent_values_count) const;
+ size_t HeaderLengthBits() const;
+ size_t EncodedDeltasLengthBits(size_t existent_values_count) const;
+
+ // Encode the compression parameters into the stream.
+ void EncodeHeader();
+
+ // Encode a given delta into the stream.
+ void EncodeDelta(uint64_t previous, uint64_t current);
+ void EncodeUnsignedDelta(uint64_t previous, uint64_t current);
+ void EncodeSignedDelta(uint64_t previous, uint64_t current);
+
+ // The parameters according to which encoding will be done (width of
+ // fields, whether signed deltas should be used, etc.)
+ const FixedLengthEncodingParameters params_;
+
+ // The encoding scheme assumes that at least one value is transmitted OOB,
+ // so that the first value can be encoded as a delta from that OOB value,
+ // which is `base_`.
+ const absl::optional<uint64_t> base_;
+
+ // The values to be encoded.
+ // Note: This is a non-owning reference. See comment above ctor for details.
+ const std::vector<absl::optional<uint64_t>>& values_;
+
+ // Buffer into which encoded values will be written.
+ // This is created dynmically as a way to enforce that the rest of the
+ // ctor has finished running when this is constructed, so that the lower
+ // bound on the buffer size would be guaranteed correct.
+ std::unique_ptr<BitWriter> writer_;
+};
+
+// TODO(eladalon): Reduce the number of passes.
+std::string FixedLengthDeltaEncoder::EncodeDeltas(
+ absl::optional<uint64_t> base,
+ const std::vector<absl::optional<uint64_t>>& values) {
+ RTC_DCHECK(!values.empty());
+
+ // As a special case, if all of the elements are identical to the base,
+ // (including, for optional fields, about their existence/non-existence),
+ // the empty string is used to signal that.
+ if (std::all_of(
+ values.cbegin(), values.cend(),
+ [base](absl::optional<uint64_t> val) { return val == base; })) {
+ return std::string();
+ }
+
+ bool non_decreasing = true;
+ uint64_t max_value_including_base = base.value_or(0u);
+ size_t existent_values_count = 0;
+ {
+ uint64_t previous = base.value_or(0u);
+ for (size_t i = 0; i < values.size(); ++i) {
+ if (!values[i].has_value()) {
+ continue;
+ }
+ ++existent_values_count;
+ non_decreasing &= (previous <= values[i].value());
+ max_value_including_base =
+ std::max(max_value_including_base, values[i].value());
+ previous = values[i].value();
+ }
+ }
+
+ // If the sequence is non-decreasing, it may be assumed to have width = 64;
+ // there's no reason to encode the actual max width in the encoding header.
+ const uint64_t value_width_bits =
+ non_decreasing ? 64 : UnsignedBitWidth(max_value_including_base);
+
+ uint64_t max_unsigned_delta;
+ uint64_t max_pos_signed_delta;
+ uint64_t min_neg_signed_delta;
+ CalculateMinAndMaxDeltas(base, values, value_width_bits, &max_unsigned_delta,
+ &max_pos_signed_delta, &min_neg_signed_delta);
+
+ const uint64_t delta_width_bits_unsigned =
+ UnsignedBitWidth(max_unsigned_delta);
+ const uint64_t delta_width_bits_signed =
+ SignedBitWidth(max_pos_signed_delta, min_neg_signed_delta);
+
+ // Note: Preference for unsigned if the two have the same width (efficiency).
+ const bool signed_deltas =
+ delta_width_bits_signed < delta_width_bits_unsigned;
+ const uint64_t delta_width_bits =
+ signed_deltas ? delta_width_bits_signed : delta_width_bits_unsigned;
+
+ const bool values_optional =
+ !base.has_value() || (existent_values_count < values.size());
+
+ FixedLengthEncodingParameters params(delta_width_bits, signed_deltas,
+ values_optional, value_width_bits);
+
+ // No effect in production.
+ ConsiderTestOverrides(&params, delta_width_bits_signed,
+ delta_width_bits_unsigned);
+
+ FixedLengthDeltaEncoder encoder(params, base, values, existent_values_count);
+ return encoder.Encode();
+}
+
+void FixedLengthDeltaEncoder::CalculateMinAndMaxDeltas(
+ absl::optional<uint64_t> base,
+ const std::vector<absl::optional<uint64_t>>& values,
+ uint64_t bit_width,
+ uint64_t* max_unsigned_delta_out,
+ uint64_t* max_pos_signed_delta_out,
+ uint64_t* min_neg_signed_delta_out) {
+ RTC_DCHECK(!values.empty());
+ RTC_DCHECK(max_unsigned_delta_out);
+ RTC_DCHECK(max_pos_signed_delta_out);
+ RTC_DCHECK(min_neg_signed_delta_out);
+
+ const uint64_t bit_mask = MaxUnsignedValueOfBitWidth(bit_width);
+
+ uint64_t max_unsigned_delta = 0;
+ uint64_t max_pos_signed_delta = 0;
+ uint64_t min_neg_signed_delta = 0;
+
+ absl::optional<uint64_t> prev = base;
+ for (size_t i = 0; i < values.size(); ++i) {
+ if (!values[i].has_value()) {
+ continue;
+ }
+
+ if (!prev.has_value()) {
+ // If the base is non-existent, the first existent value is encoded as
+ // a varint, rather than as a delta.
+ RTC_DCHECK(!base.has_value());
+ prev = values[i];
+ continue;
+ }
+
+ const uint64_t current = values[i].value();
+
+ const uint64_t forward_delta = UnsignedDelta(*prev, current, bit_mask);
+ const uint64_t backward_delta = UnsignedDelta(current, *prev, bit_mask);
+
+ max_unsigned_delta = std::max(max_unsigned_delta, forward_delta);
+
+ if (forward_delta < backward_delta) {
+ max_pos_signed_delta = std::max(max_pos_signed_delta, forward_delta);
+ } else {
+ min_neg_signed_delta = std::max(min_neg_signed_delta, backward_delta);
+ }
+
+ prev = current;
+ }
+
+ *max_unsigned_delta_out = max_unsigned_delta;
+ *max_pos_signed_delta_out = max_pos_signed_delta;
+ *min_neg_signed_delta_out = min_neg_signed_delta;
+}
+
+void FixedLengthDeltaEncoder::ConsiderTestOverrides(
+ FixedLengthEncodingParameters* params,
+ uint64_t delta_width_bits_signed,
+ uint64_t delta_width_bits_unsigned) {
+ if (g_force_unsigned_for_testing) {
+ params->SetDeltaWidthBits(delta_width_bits_unsigned);
+ params->SetSignedDeltas(false);
+ } else if (g_force_signed_for_testing) {
+ params->SetDeltaWidthBits(delta_width_bits_signed);
+ params->SetSignedDeltas(true);
+ } else {
+ // Unchanged.
+ }
+}
+
+FixedLengthDeltaEncoder::FixedLengthDeltaEncoder(
+ const FixedLengthEncodingParameters& params,
+ absl::optional<uint64_t> base,
+ const std::vector<absl::optional<uint64_t>>& values,
+ size_t existent_values_count)
+ : params_(params), base_(base), values_(values) {
+ RTC_DCHECK(!values_.empty());
+ writer_ =
+ std::make_unique<BitWriter>(OutputLengthBytes(existent_values_count));
+}
+
+std::string FixedLengthDeltaEncoder::Encode() {
+ EncodeHeader();
+
+ if (params_.values_optional()) {
+ // Encode which values exist and which don't.
+ for (absl::optional<uint64_t> value : values_) {
+ writer_->WriteBits(value.has_value() ? 1u : 0u, 1);
+ }
+ }
+
+ absl::optional<uint64_t> previous = base_;
+ for (absl::optional<uint64_t> value : values_) {
+ if (!value.has_value()) {
+ RTC_DCHECK(params_.values_optional());
+ continue;
+ }
+
+ if (!previous.has_value()) {
+ // If the base is non-existent, the first existent value is encoded as
+ // a varint, rather than as a delta.
+ RTC_DCHECK(!base_.has_value());
+ writer_->WriteBits(EncodeVarInt(value.value()));
+ } else {
+ EncodeDelta(previous.value(), value.value());
+ }
+
+ previous = value;
+ }
+
+ return writer_->GetString();
+}
+
+size_t FixedLengthDeltaEncoder::OutputLengthBytes(
+ size_t existent_values_count) const {
+ return BitsToBytes(HeaderLengthBits() +
+ EncodedDeltasLengthBits(existent_values_count));
+}
+
+size_t FixedLengthDeltaEncoder::HeaderLengthBits() const {
+ if (params_.signed_deltas() == kDefaultSignedDeltas &&
+ params_.values_optional() == kDefaultValuesOptional &&
+ params_.value_width_bits() == kDefaultValueWidthBits) {
+ return kBitsInHeaderForEncodingType + kBitsInHeaderForDeltaWidthBits;
+ } else {
+ return kBitsInHeaderForEncodingType + kBitsInHeaderForDeltaWidthBits +
+ kBitsInHeaderForSignedDeltas + kBitsInHeaderForValuesOptional +
+ kBitsInHeaderForValueWidthBits;
+ }
+}
+
+size_t FixedLengthDeltaEncoder::EncodedDeltasLengthBits(
+ size_t existent_values_count) const {
+ if (!params_.values_optional()) {
+ return values_.size() * params_.delta_width_bits();
+ } else {
+ RTC_DCHECK_EQ(std::count_if(values_.begin(), values_.end(),
+ [](absl::optional<uint64_t> val) {
+ return val.has_value();
+ }),
+ existent_values_count);
+ // One bit for each delta, to indicate if the value exists, and delta_width
+ // for each existent value, to indicate the delta itself.
+ // If base_ is non-existent, the first value (if any) is encoded as a varint
+ // rather than as a delta.
+ const size_t existence_bitmap_size_bits = 1 * values_.size();
+ const bool first_value_is_varint =
+ !base_.has_value() && existent_values_count >= 1;
+ const size_t first_value_varint_size_bits = 8 * kMaxVarIntLengthBytes;
+ const size_t deltas_count = existent_values_count - first_value_is_varint;
+ const size_t deltas_size_bits = deltas_count * params_.delta_width_bits();
+ return existence_bitmap_size_bits + first_value_varint_size_bits +
+ deltas_size_bits;
+ }
+}
+
+void FixedLengthDeltaEncoder::EncodeHeader() {
+ RTC_DCHECK(writer_);
+
+ const EncodingType encoding_type =
+ (params_.value_width_bits() == kDefaultValueWidthBits &&
+ params_.signed_deltas() == kDefaultSignedDeltas &&
+ params_.values_optional() == kDefaultValuesOptional)
+ ? EncodingType::kFixedSizeUnsignedDeltasNoEarlyWrapNoOpt
+ : EncodingType::kFixedSizeSignedDeltasEarlyWrapAndOptSupported;
+
+ writer_->WriteBits(static_cast<uint64_t>(encoding_type),
+ kBitsInHeaderForEncodingType);
+
+ // Note: Since it's meaningless for a field to be of width 0, when it comes
+ // to fields that relate widths, we encode width 1 as 0, width 2 as 1,
+
+ writer_->WriteBits(params_.delta_width_bits() - 1,
+ kBitsInHeaderForDeltaWidthBits);
+
+ if (encoding_type == EncodingType::kFixedSizeUnsignedDeltasNoEarlyWrapNoOpt) {
+ return;
+ }
+
+ writer_->WriteBits(static_cast<uint64_t>(params_.signed_deltas()),
+ kBitsInHeaderForSignedDeltas);
+ writer_->WriteBits(static_cast<uint64_t>(params_.values_optional()),
+ kBitsInHeaderForValuesOptional);
+ writer_->WriteBits(params_.value_width_bits() - 1,
+ kBitsInHeaderForValueWidthBits);
+}
+
+void FixedLengthDeltaEncoder::EncodeDelta(uint64_t previous, uint64_t current) {
+ if (params_.signed_deltas()) {
+ EncodeSignedDelta(previous, current);
+ } else {
+ EncodeUnsignedDelta(previous, current);
+ }
+}
+
+void FixedLengthDeltaEncoder::EncodeUnsignedDelta(uint64_t previous,
+ uint64_t current) {
+ RTC_DCHECK(writer_);
+ const uint64_t delta = UnsignedDelta(previous, current, params_.value_mask());
+ writer_->WriteBits(delta, params_.delta_width_bits());
+}
+
+void FixedLengthDeltaEncoder::EncodeSignedDelta(uint64_t previous,
+ uint64_t current) {
+ RTC_DCHECK(writer_);
+
+ const uint64_t forward_delta =
+ UnsignedDelta(previous, current, params_.value_mask());
+ const uint64_t backward_delta =
+ UnsignedDelta(current, previous, params_.value_mask());
+
+ uint64_t delta;
+ if (forward_delta <= backward_delta) {
+ delta = forward_delta;
+ } else {
+ // Compute the unsigned representation of a negative delta.
+ // This is the two's complement representation of this negative value,
+ // when deltas are of width params_.delta_mask().
+ RTC_DCHECK_GE(params_.delta_mask(), backward_delta);
+ RTC_DCHECK_LT(params_.delta_mask() - backward_delta, params_.delta_mask());
+ delta = params_.delta_mask() - backward_delta + 1;
+ RTC_DCHECK_LE(delta, params_.delta_mask());
+ }
+
+ writer_->WriteBits(delta, params_.delta_width_bits());
+}
+
+// Perform decoding of a a delta-encoded stream, extracting the original
+// sequence of values.
+class FixedLengthDeltaDecoder final {
+ public:
+ // Checks whether FixedLengthDeltaDecoder is a suitable decoder for this
+ // bitstream. Note that this does NOT imply that stream is valid, and will
+ // be decoded successfully. It DOES imply that all other decoder classes
+ // will fail to decode this input, though.
+ static bool IsSuitableDecoderFor(absl::string_view input);
+
+ // Assuming that `input` is the result of fixed-size delta-encoding
+ // that took place with the same value to `base` and over `num_of_deltas`
+ // original values, this will return the sequence of original values.
+ // If an error occurs (can happen if `input` is corrupt), an empty
+ // vector will be returned.
+ static std::vector<absl::optional<uint64_t>> DecodeDeltas(
+ absl::string_view input,
+ absl::optional<uint64_t> base,
+ size_t num_of_deltas);
+
+ FixedLengthDeltaDecoder(const FixedLengthDeltaDecoder&) = delete;
+ FixedLengthDeltaDecoder& operator=(const FixedLengthDeltaDecoder&) = delete;
+
+ private:
+ // Reads the encoding header in `input` and returns a FixedLengthDeltaDecoder
+ // with the corresponding configuration, that can be used to decode the
+ // values in `input`.
+ // If the encoding header is corrupt (contains an illegal configuration),
+ // nullptr will be returned.
+ // When a valid FixedLengthDeltaDecoder is returned, this does not mean that
+ // the entire stream is free of error. Rather, only the encoding header is
+ // examined and guaranteed.
+ static std::unique_ptr<FixedLengthDeltaDecoder> Create(
+ absl::string_view input,
+ absl::optional<uint64_t> base,
+ size_t num_of_deltas);
+
+ // FixedLengthDeltaDecoder objects are to be created by DecodeDeltas() and
+ // released by it before it returns. They're mostly a convenient way to
+ // avoid having to pass a lot of state between different functions.
+ // Therefore, it was deemed acceptable that `reader` does not own the buffer
+ // it reads, meaning the lifetime of `this` must not exceed the lifetime
+ // of `reader`'s underlying buffer.
+ FixedLengthDeltaDecoder(BitstreamReader reader,
+ const FixedLengthEncodingParameters& params,
+ absl::optional<uint64_t> base,
+ size_t num_of_deltas);
+
+ // Perform the decoding using the parameters given to the ctor.
+ std::vector<absl::optional<uint64_t>> Decode();
+
+ // Add `delta` to `base` to produce the next value in a sequence.
+ // The delta is applied as signed/unsigned depending on the parameters
+ // given to the ctor. Wrap-around is taken into account according to the
+ // values' width, as specified by the aforementioned encoding parameters.
+ uint64_t ApplyDelta(uint64_t base, uint64_t delta) const;
+
+ // Helpers for ApplyDelta().
+ uint64_t ApplyUnsignedDelta(uint64_t base, uint64_t delta) const;
+ uint64_t ApplySignedDelta(uint64_t base, uint64_t delta) const;
+
+ // Reader of the input stream to be decoded. Does not own that buffer.
+ // See comment above ctor for details.
+ BitstreamReader reader_;
+
+ // The parameters according to which encoding will be done (width of
+ // fields, whether signed deltas should be used, etc.)
+ const FixedLengthEncodingParameters params_;
+
+ // The encoding scheme assumes that at least one value is transmitted OOB,
+ // so that the first value can be encoded as a delta from that OOB value,
+ // which is `base_`.
+ const absl::optional<uint64_t> base_;
+
+ // The number of values to be known to be decoded.
+ const size_t num_of_deltas_;
+};
+
+bool FixedLengthDeltaDecoder::IsSuitableDecoderFor(absl::string_view input) {
+ BitstreamReader reader(input);
+ uint64_t encoding_type_bits = reader.ReadBits(kBitsInHeaderForEncodingType);
+ if (!reader.Ok()) {
+ return false;
+ }
+
+ const auto encoding_type = static_cast<EncodingType>(encoding_type_bits);
+ return encoding_type ==
+ EncodingType::kFixedSizeUnsignedDeltasNoEarlyWrapNoOpt ||
+ encoding_type ==
+ EncodingType::kFixedSizeSignedDeltasEarlyWrapAndOptSupported;
+}
+
+std::vector<absl::optional<uint64_t>> FixedLengthDeltaDecoder::DecodeDeltas(
+ absl::string_view input,
+ absl::optional<uint64_t> base,
+ size_t num_of_deltas) {
+ auto decoder = FixedLengthDeltaDecoder::Create(input, base, num_of_deltas);
+ if (!decoder) {
+ return std::vector<absl::optional<uint64_t>>();
+ }
+
+ return decoder->Decode();
+}
+
+std::unique_ptr<FixedLengthDeltaDecoder> FixedLengthDeltaDecoder::Create(
+ absl::string_view input,
+ absl::optional<uint64_t> base,
+ size_t num_of_deltas) {
+ BitstreamReader reader(input);
+ // Encoding type
+ uint32_t encoding_type_bits = reader.ReadBits(kBitsInHeaderForEncodingType);
+ if (!reader.Ok()) {
+ return nullptr;
+ }
+
+ const EncodingType encoding = static_cast<EncodingType>(encoding_type_bits);
+ if (encoding != EncodingType::kFixedSizeUnsignedDeltasNoEarlyWrapNoOpt &&
+ encoding !=
+ EncodingType::kFixedSizeSignedDeltasEarlyWrapAndOptSupported) {
+ RTC_LOG(LS_WARNING) << "Unrecognized encoding type.";
+ return nullptr;
+ }
+
+ // See encoding for +1's rationale.
+ const uint64_t delta_width_bits =
+ reader.ReadBits(kBitsInHeaderForDeltaWidthBits) + 1;
+ RTC_DCHECK_LE(delta_width_bits, 64);
+
+ // signed_deltas, values_optional, value_width_bits
+ bool signed_deltas;
+ bool values_optional;
+ uint64_t value_width_bits;
+ if (encoding == EncodingType::kFixedSizeUnsignedDeltasNoEarlyWrapNoOpt) {
+ signed_deltas = kDefaultSignedDeltas;
+ values_optional = kDefaultValuesOptional;
+ value_width_bits = kDefaultValueWidthBits;
+ } else {
+ signed_deltas = reader.Read<bool>();
+ values_optional = reader.Read<bool>();
+ // See encoding for +1's rationale.
+ value_width_bits = reader.ReadBits(kBitsInHeaderForValueWidthBits) + 1;
+ RTC_DCHECK_LE(value_width_bits, 64);
+ }
+
+ if (!reader.Ok()) {
+ return nullptr;
+ }
+
+ // Note: Because of the way the parameters are read, it is not possible
+ // for illegal values to be read. We check nevertheless, in case the code
+ // changes in the future in a way that breaks this promise.
+ if (!FixedLengthEncodingParameters::ValidParameters(
+ delta_width_bits, signed_deltas, values_optional, value_width_bits)) {
+ RTC_LOG(LS_WARNING) << "Corrupt log; illegal encoding parameters.";
+ return nullptr;
+ }
+
+ FixedLengthEncodingParameters params(delta_width_bits, signed_deltas,
+ values_optional, value_width_bits);
+ return absl::WrapUnique(
+ new FixedLengthDeltaDecoder(reader, params, base, num_of_deltas));
+}
+
+FixedLengthDeltaDecoder::FixedLengthDeltaDecoder(
+ BitstreamReader reader,
+ const FixedLengthEncodingParameters& params,
+ absl::optional<uint64_t> base,
+ size_t num_of_deltas)
+ : reader_(reader),
+ params_(params),
+ base_(base),
+ num_of_deltas_(num_of_deltas) {
+ RTC_DCHECK(reader_.Ok());
+}
+
+std::vector<absl::optional<uint64_t>> FixedLengthDeltaDecoder::Decode() {
+ RTC_DCHECK(reader_.Ok());
+ std::vector<bool> existing_values(num_of_deltas_);
+ if (params_.values_optional()) {
+ for (size_t i = 0; i < num_of_deltas_; ++i) {
+ existing_values[i] = reader_.Read<bool>();
+ }
+ } else {
+ std::fill(existing_values.begin(), existing_values.end(), true);
+ }
+
+ absl::optional<uint64_t> previous = base_;
+ std::vector<absl::optional<uint64_t>> values(num_of_deltas_);
+
+ for (size_t i = 0; i < num_of_deltas_; ++i) {
+ if (!existing_values[i]) {
+ RTC_DCHECK(params_.values_optional());
+ continue;
+ }
+
+ if (!previous) {
+ // If the base is non-existent, the first existent value is encoded as
+ // a varint, rather than as a delta.
+ RTC_DCHECK(!base_.has_value());
+ values[i] = DecodeVarInt(reader_);
+ } else {
+ uint64_t delta = reader_.ReadBits(params_.delta_width_bits());
+ values[i] = ApplyDelta(*previous, delta);
+ }
+
+ previous = values[i];
+ }
+
+ if (!reader_.Ok()) {
+ values = {};
+ }
+
+ return values;
+}
+
+uint64_t FixedLengthDeltaDecoder::ApplyDelta(uint64_t base,
+ uint64_t delta) const {
+ RTC_DCHECK_LE(base, MaxUnsignedValueOfBitWidth(params_.value_width_bits()));
+ RTC_DCHECK_LE(delta, MaxUnsignedValueOfBitWidth(params_.delta_width_bits()));
+ return params_.signed_deltas() ? ApplySignedDelta(base, delta)
+ : ApplyUnsignedDelta(base, delta);
+}
+
+uint64_t FixedLengthDeltaDecoder::ApplyUnsignedDelta(uint64_t base,
+ uint64_t delta) const {
+ // Note: May still be used if signed deltas used.
+ RTC_DCHECK_LE(base, MaxUnsignedValueOfBitWidth(params_.value_width_bits()));
+ RTC_DCHECK_LE(delta, MaxUnsignedValueOfBitWidth(params_.delta_width_bits()));
+ return (base + delta) & params_.value_mask();
+}
+
+uint64_t FixedLengthDeltaDecoder::ApplySignedDelta(uint64_t base,
+ uint64_t delta) const {
+ RTC_DCHECK(params_.signed_deltas());
+ RTC_DCHECK_LE(base, MaxUnsignedValueOfBitWidth(params_.value_width_bits()));
+ RTC_DCHECK_LE(delta, MaxUnsignedValueOfBitWidth(params_.delta_width_bits()));
+
+ const uint64_t top_bit = static_cast<uint64_t>(1)
+ << (params_.delta_width_bits() - 1);
+
+ const bool positive_delta = ((delta & top_bit) == 0);
+ if (positive_delta) {
+ return ApplyUnsignedDelta(base, delta);
+ }
+
+ const uint64_t delta_abs = (~delta & params_.delta_mask()) + 1;
+ return (base - delta_abs) & params_.value_mask();
+}
+
+} // namespace
+
+std::string EncodeDeltas(absl::optional<uint64_t> base,
+ const std::vector<absl::optional<uint64_t>>& values) {
+ // TODO(eladalon): Support additional encodings.
+ return FixedLengthDeltaEncoder::EncodeDeltas(base, values);
+}
+
+std::vector<absl::optional<uint64_t>> DecodeDeltas(
+ absl::string_view input,
+ absl::optional<uint64_t> base,
+ size_t num_of_deltas) {
+ RTC_DCHECK_GT(num_of_deltas, 0); // Allows empty vector to indicate error.
+
+ // The empty string is a special case indicating that all values were equal
+ // to the base.
+ if (input.empty()) {
+ std::vector<absl::optional<uint64_t>> result(num_of_deltas);
+ std::fill(result.begin(), result.end(), base);
+ return result;
+ }
+
+ if (FixedLengthDeltaDecoder::IsSuitableDecoderFor(input)) {
+ return FixedLengthDeltaDecoder::DecodeDeltas(input, base, num_of_deltas);
+ }
+
+ RTC_LOG(LS_WARNING) << "Could not decode delta-encoded stream.";
+ return std::vector<absl::optional<uint64_t>>();
+}
+
+void SetFixedLengthEncoderDeltaSignednessForTesting(bool signedness) {
+ g_force_unsigned_for_testing = !signedness;
+ g_force_signed_for_testing = signedness;
+}
+
+void UnsetFixedLengthEncoderDeltaSignednessForTesting() {
+ g_force_unsigned_for_testing = false;
+ g_force_signed_for_testing = false;
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/logging/rtc_event_log/encoder/delta_encoding.h b/third_party/libwebrtc/logging/rtc_event_log/encoder/delta_encoding.h
new file mode 100644
index 0000000000..779cdc6b2f
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/encoder/delta_encoding.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2018 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_ENCODER_DELTA_ENCODING_H_
+#define LOGGING_RTC_EVENT_LOG_ENCODER_DELTA_ENCODING_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "absl/types/optional.h"
+
+namespace webrtc {
+
+// Encode `values` as a sequence of deltas following on `base` and return it.
+// If all of the values were equal to the base, an empty string will be
+// returned; this is a valid encoding of that edge case.
+// `base` is not guaranteed to be written into `output`, and must therefore
+// be provided separately to the decoder.
+// This function never fails.
+// TODO(eladalon): Split into optional and non-optional variants (efficiency).
+std::string EncodeDeltas(absl::optional<uint64_t> base,
+ const std::vector<absl::optional<uint64_t>>& values);
+
+// EncodeDeltas() and DecodeDeltas() are inverse operations;
+// invoking DecodeDeltas() over the output of EncodeDeltas(), will return
+// the input originally given to EncodeDeltas().
+// `num_of_deltas` must be greater than zero. If input is not a valid encoding
+// of `num_of_deltas` elements based on `base`, the function returns an empty
+// vector, which signals an error.
+// TODO(eladalon): Split into optional and non-optional variants (efficiency).
+std::vector<absl::optional<uint64_t>> DecodeDeltas(
+ absl::string_view input,
+ absl::optional<uint64_t> base,
+ size_t num_of_deltas);
+
+} // namespace webrtc
+
+#endif // LOGGING_RTC_EVENT_LOG_ENCODER_DELTA_ENCODING_H_
diff --git a/third_party/libwebrtc/logging/rtc_event_log/encoder/delta_encoding_unittest.cc b/third_party/libwebrtc/logging/rtc_event_log/encoder/delta_encoding_unittest.cc
new file mode 100644
index 0000000000..d0f7fb93db
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/encoder/delta_encoding_unittest.cc
@@ -0,0 +1,693 @@
+/*
+ * Copyright (c) 2018 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/encoder/delta_encoding.h"
+
+#include <algorithm>
+#include <limits>
+#include <numeric>
+#include <string>
+#include <tuple>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "rtc_base/arraysize.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/random.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+
+void SetFixedLengthEncoderDeltaSignednessForTesting(bool signedness);
+void UnsetFixedLengthEncoderDeltaSignednessForTesting();
+
+namespace {
+
+enum class DeltaSignedness { kNoOverride, kForceUnsigned, kForceSigned };
+
+void MaybeSetSignedness(DeltaSignedness signedness) {
+ switch (signedness) {
+ case DeltaSignedness::kNoOverride:
+ UnsetFixedLengthEncoderDeltaSignednessForTesting();
+ return;
+ case DeltaSignedness::kForceUnsigned:
+ SetFixedLengthEncoderDeltaSignednessForTesting(false);
+ return;
+ case DeltaSignedness::kForceSigned:
+ SetFixedLengthEncoderDeltaSignednessForTesting(true);
+ return;
+ }
+ RTC_DCHECK_NOTREACHED();
+}
+
+uint64_t RandomWithMaxBitWidth(Random* prng, uint64_t max_width) {
+ RTC_DCHECK_GE(max_width, 1u);
+ RTC_DCHECK_LE(max_width, 64u);
+
+ const uint64_t low = prng->Rand(std::numeric_limits<uint32_t>::max());
+ const uint64_t high =
+ max_width > 32u ? prng->Rand(std::numeric_limits<uint32_t>::max()) : 0u;
+
+ const uint64_t random_before_mask = (high << 32) | low;
+
+ if (max_width < 64) {
+ return random_before_mask & ((static_cast<uint64_t>(1) << max_width) - 1);
+ } else {
+ return random_before_mask;
+ }
+}
+
+// Encodes `values` based on `base`, then decodes the result and makes sure
+// that it is equal to the original input.
+// If `encoded_string` is non-null, the encoded result will also be written
+// into it.
+void TestEncodingAndDecoding(
+ absl::optional<uint64_t> base,
+ const std::vector<absl::optional<uint64_t>>& values,
+ std::string* encoded_string = nullptr) {
+ const std::string encoded = EncodeDeltas(base, values);
+ if (encoded_string) {
+ *encoded_string = encoded;
+ }
+
+ const std::vector<absl::optional<uint64_t>> decoded =
+ DecodeDeltas(encoded, base, values.size());
+
+ EXPECT_EQ(decoded, values);
+}
+
+std::vector<absl::optional<uint64_t>> CreateSequenceByFirstValue(
+ uint64_t first,
+ size_t sequence_length) {
+ std::vector<absl::optional<uint64_t>> sequence(sequence_length);
+ std::iota(sequence.begin(), sequence.end(), first);
+ return sequence;
+}
+
+std::vector<absl::optional<uint64_t>> CreateSequenceByLastValue(
+ uint64_t last,
+ size_t num_values) {
+ const uint64_t first = last - num_values + 1;
+ std::vector<absl::optional<uint64_t>> result(num_values);
+ std::iota(result.begin(), result.end(), first);
+ return result;
+}
+
+// If `sequence_length` is greater than the number of deltas, the sequence of
+// deltas will wrap around.
+std::vector<absl::optional<uint64_t>> CreateSequenceByOptionalDeltas(
+ uint64_t first,
+ const std::vector<absl::optional<uint64_t>>& deltas,
+ size_t sequence_length) {
+ RTC_DCHECK_GE(sequence_length, 1);
+
+ std::vector<absl::optional<uint64_t>> sequence(sequence_length);
+
+ uint64_t previous = first;
+ for (size_t i = 0, next_delta_index = 0; i < sequence.size(); ++i) {
+ if (deltas[next_delta_index].has_value()) {
+ sequence[i] =
+ absl::optional<uint64_t>(previous + deltas[next_delta_index].value());
+ previous = sequence[i].value();
+ }
+ next_delta_index = (next_delta_index + 1) % deltas.size();
+ }
+
+ return sequence;
+}
+
+size_t EncodingLengthUpperBound(size_t delta_max_bit_width,
+ size_t num_of_deltas,
+ DeltaSignedness signedness_override) {
+ absl::optional<size_t> smallest_header_size_bytes;
+ switch (signedness_override) {
+ case DeltaSignedness::kNoOverride:
+ case DeltaSignedness::kForceUnsigned:
+ smallest_header_size_bytes = 1;
+ break;
+ case DeltaSignedness::kForceSigned:
+ smallest_header_size_bytes = 2;
+ break;
+ }
+ RTC_DCHECK(smallest_header_size_bytes);
+
+ return delta_max_bit_width * num_of_deltas + *smallest_header_size_bytes;
+}
+
+// If `sequence_length` is greater than the number of deltas, the sequence of
+// deltas will wrap around.
+std::vector<absl::optional<uint64_t>> CreateSequenceByDeltas(
+ uint64_t first,
+ const std::vector<uint64_t>& deltas,
+ size_t sequence_length) {
+ RTC_DCHECK(!deltas.empty());
+ std::vector<absl::optional<uint64_t>> optional_deltas(deltas.size());
+ for (size_t i = 0; i < deltas.size(); ++i) {
+ optional_deltas[i] = absl::optional<uint64_t>(deltas[i]);
+ }
+ return CreateSequenceByOptionalDeltas(first, optional_deltas,
+ sequence_length);
+}
+
+// Tests of the delta encoding, parameterized by the number of values
+// in the sequence created by the test.
+class DeltaEncodingTest
+ : public ::testing::TestWithParam<
+ std::tuple<DeltaSignedness, size_t, bool, uint64_t>> {
+ public:
+ DeltaEncodingTest()
+ : signedness_(std::get<0>(GetParam())),
+ num_of_values_(std::get<1>(GetParam())),
+ optional_values_(std::get<2>(GetParam())),
+ partial_random_seed_(std::get<3>(GetParam())) {
+ MaybeSetSignedness(signedness_);
+ }
+
+ ~DeltaEncodingTest() override = default;
+
+ // Running with the same seed for all variants would make all tests start
+ // with the same sequence; avoid this by making the seed different.
+ uint64_t Seed() const {
+ // Multiply everything but by different primes to produce unique results.
+ return 2 * static_cast<uint64_t>(signedness_) + 3 * num_of_values_ +
+ 5 * optional_values_ + 7 * partial_random_seed_;
+ }
+
+ const DeltaSignedness signedness_;
+ const uint64_t num_of_values_;
+ const bool optional_values_;
+ const uint64_t partial_random_seed_; // Explained where it's used.
+};
+
+TEST_P(DeltaEncodingTest, AllValuesEqualToExistentBaseValue) {
+ const absl::optional<uint64_t> base(3432);
+ std::vector<absl::optional<uint64_t>> values(num_of_values_);
+ std::fill(values.begin(), values.end(), base);
+ std::string encoded;
+ TestEncodingAndDecoding(base, values, &encoded);
+
+ // Additional requirement - the encoding should be efficient in this
+ // case - the empty string will be used.
+ EXPECT_TRUE(encoded.empty());
+}
+
+TEST_P(DeltaEncodingTest, AllValuesEqualToNonExistentBaseValue) {
+ if (!optional_values_) {
+ return; // Test irrelevant for this case.
+ }
+
+ const absl::optional<uint64_t> base;
+ std::vector<absl::optional<uint64_t>> values(num_of_values_);
+ std::fill(values.begin(), values.end(), base);
+ std::string encoded;
+ TestEncodingAndDecoding(base, values, &encoded);
+
+ // Additional requirement - the encoding should be efficient in this
+ // case - the empty string will be used.
+ EXPECT_TRUE(encoded.empty());
+}
+
+TEST_P(DeltaEncodingTest, BaseNonExistentButSomeOtherValuesExist) {
+ if (!optional_values_) {
+ return; // Test irrelevant for this case.
+ }
+
+ const absl::optional<uint64_t> base;
+ std::vector<absl::optional<uint64_t>> values(num_of_values_);
+
+ Random prng(Seed());
+
+ const uint64_t max_bit_width = 1 + prng.Rand(63); // [1, 64]
+
+ for (size_t i = 0; i < values.size();) {
+ // Leave a random number of values as non-existent.
+ const size_t non_existent_count = prng.Rand(values.size() - i - 1);
+ i += non_existent_count;
+
+ // Assign random values to a random number of values. (At least one, to
+ // prevent this iteration of the outer loop from being a no-op.)
+ const size_t existent_count =
+ std::max<size_t>(prng.Rand(values.size() - i - 1), 1);
+ for (size_t j = 0; j < existent_count; ++j) {
+ values[i + j] = RandomWithMaxBitWidth(&prng, max_bit_width);
+ }
+ i += existent_count;
+ }
+
+ TestEncodingAndDecoding(base, values);
+}
+
+TEST_P(DeltaEncodingTest, MinDeltaNoWrapAround) {
+ const absl::optional<uint64_t> base(3432);
+
+ auto values = CreateSequenceByFirstValue(base.value() + 1, num_of_values_);
+ ASSERT_GT(values[values.size() - 1], base) << "Sanity; must not wrap around";
+
+ if (optional_values_) {
+ // Arbitrarily make one of the values non-existent, to force
+ // optional-supporting encoding.
+ values[0] = absl::optional<uint64_t>();
+ }
+
+ TestEncodingAndDecoding(base, values);
+}
+
+TEST_P(DeltaEncodingTest, BigDeltaNoWrapAround) {
+ const uint64_t kBigDelta = 132828;
+ const absl::optional<uint64_t> base(3432);
+
+ auto values =
+ CreateSequenceByFirstValue(base.value() + kBigDelta, num_of_values_);
+ ASSERT_GT(values[values.size() - 1], base) << "Sanity; must not wrap around";
+
+ if (optional_values_) {
+ // Arbitrarily make one of the values non-existent, to force
+ // optional-supporting encoding.
+ values[0] = absl::optional<uint64_t>();
+ }
+
+ TestEncodingAndDecoding(base, values);
+}
+
+TEST_P(DeltaEncodingTest, MaxDeltaNoWrapAround) {
+ const absl::optional<uint64_t> base(3432);
+
+ auto values = CreateSequenceByLastValue(std::numeric_limits<uint64_t>::max(),
+ num_of_values_);
+ ASSERT_GT(values[values.size() - 1], base) << "Sanity; must not wrap around";
+
+ if (optional_values_) {
+ // Arbitrarily make one of the values non-existent, to force
+ // optional-supporting encoding.
+ values[0] = absl::optional<uint64_t>();
+ }
+
+ TestEncodingAndDecoding(base, values);
+}
+
+TEST_P(DeltaEncodingTest, SmallDeltaWithWrapAroundComparedToBase) {
+ if (optional_values_ && num_of_values_ == 1) {
+ return; // Inapplicable
+ }
+
+ const absl::optional<uint64_t> base(std::numeric_limits<uint64_t>::max());
+
+ auto values = CreateSequenceByDeltas(*base, {1, 10, 3}, num_of_values_);
+ ASSERT_LT(values[0], base) << "Sanity; must wrap around";
+
+ if (optional_values_) {
+ // Arbitrarily make one of the values non-existent, to force
+ // optional-supporting encoding.
+ values[1] = absl::optional<uint64_t>();
+ }
+
+ TestEncodingAndDecoding(base, values);
+}
+
+TEST_P(DeltaEncodingTest, SmallDeltaWithWrapAroundInValueSequence) {
+ if (num_of_values_ == 1 || (optional_values_ && num_of_values_ < 3)) {
+ return; // Inapplicable.
+ }
+
+ const absl::optional<uint64_t> base(std::numeric_limits<uint64_t>::max() - 2);
+
+ auto values = CreateSequenceByDeltas(*base, {1, 10, 3}, num_of_values_);
+ ASSERT_LT(values[values.size() - 1], values[0]) << "Sanity; must wrap around";
+
+ if (optional_values_) {
+ // Arbitrarily make one of the values non-existent, to force
+ // optional-supporting encoding.
+ RTC_DCHECK_GT(values.size() - 1, 1u); // Wrap around not cancelled.
+ values[1] = absl::optional<uint64_t>();
+ }
+
+ TestEncodingAndDecoding(base, values);
+}
+
+// Suppress "integral constant overflow" warning; this is the test's focus.
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4307)
+#endif
+TEST_P(DeltaEncodingTest, BigDeltaWithWrapAroundComparedToBase) {
+ if (optional_values_ && num_of_values_ == 1) {
+ return; // Inapplicable
+ }
+
+ const uint64_t kBigDelta = 132828;
+ const absl::optional<uint64_t> base(std::numeric_limits<uint64_t>::max() -
+ kBigDelta + 3);
+
+ auto values =
+ CreateSequenceByFirstValue(base.value() + kBigDelta, num_of_values_);
+ ASSERT_LT(values[0], base.value()) << "Sanity; must wrap around";
+
+ if (optional_values_) {
+ // Arbitrarily make one of the values non-existent, to force
+ // optional-supporting encoding.
+ values[1] = absl::optional<uint64_t>();
+ }
+
+ TestEncodingAndDecoding(base, values);
+}
+
+TEST_P(DeltaEncodingTest, BigDeltaWithWrapAroundInValueSequence) {
+ if (num_of_values_ == 1 || (optional_values_ && num_of_values_ < 3)) {
+ return; // Inapplicable.
+ }
+
+ const uint64_t kBigDelta = 132828;
+ const absl::optional<uint64_t> base(std::numeric_limits<uint64_t>::max() -
+ kBigDelta + 3);
+
+ auto values = CreateSequenceByFirstValue(std::numeric_limits<uint64_t>::max(),
+ num_of_values_);
+ ASSERT_LT(values[values.size() - 1], values[0]) << "Sanity; must wrap around";
+
+ if (optional_values_) {
+ // Arbitrarily make one of the values non-existent, to force
+ // optional-supporting encoding.
+ RTC_DCHECK_GT(values.size() - 1, 1u); // Wrap around not cancelled.
+ values[1] = absl::optional<uint64_t>();
+ }
+
+ TestEncodingAndDecoding(base, values);
+}
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+TEST_P(DeltaEncodingTest, MaxDeltaWithWrapAroundComparedToBase) {
+ if (optional_values_ && num_of_values_ == 1) {
+ return; // Inapplicable
+ }
+
+ const absl::optional<uint64_t> base(3432);
+ auto values = CreateSequenceByFirstValue(*base - 1, num_of_values_);
+
+ if (optional_values_) {
+ // Arbitrarily make one of the values non-existent, to force
+ // optional-supporting encoding.
+ values[1] = absl::optional<uint64_t>();
+ }
+
+ TestEncodingAndDecoding(base, values);
+}
+
+TEST_P(DeltaEncodingTest, MaxDeltaWithWrapAroundInValueSequence) {
+ if (num_of_values_ == 1 || (optional_values_ && num_of_values_ < 3)) {
+ return; // Inapplicable.
+ }
+
+ const absl::optional<uint64_t> base(3432);
+
+ auto values = CreateSequenceByDeltas(
+ *base, {0, std::numeric_limits<uint64_t>::max(), 3}, num_of_values_);
+ // Wraps around continuously by virtue of being max(); will not ASSERT.
+
+ if (optional_values_) {
+ // Arbitrarily make one of the values non-existent, to force
+ // optional-supporting encoding.
+ RTC_DCHECK_GT(values.size() - 1, 1u); // Wrap around not cancelled.
+ values[1] = absl::optional<uint64_t>();
+ }
+
+ TestEncodingAndDecoding(base, values);
+}
+
+// If num_of_values_ == 1, a zero delta will yield an empty string; that's
+// already covered by AllValuesEqualToExistentBaseValue, but it doesn't hurt to
+// test again. For all other cases, we have a new test.
+TEST_P(DeltaEncodingTest, ZeroDelta) {
+ const absl::optional<uint64_t> base(3432);
+
+ // Arbitrary sequence of deltas with intentional zero deltas, as well as
+ // consecutive zeros.
+ const std::vector<uint64_t> deltas = {0, 312, 11, 1, 1, 0, 0, 12,
+ 400321, 3, 3, 12, 5, 0, 6};
+ auto values = CreateSequenceByDeltas(base.value(), deltas, num_of_values_);
+
+ if (optional_values_) {
+ // Arbitrarily make one of the values non-existent, to force
+ // optional-supporting encoding.
+ values[0] = absl::optional<uint64_t>();
+ }
+
+ TestEncodingAndDecoding(base, values);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ SignednessOverrideAndNumberOfValuesInSequence,
+ DeltaEncodingTest,
+ ::testing::Combine(::testing::Values(DeltaSignedness::kNoOverride,
+ DeltaSignedness::kForceUnsigned,
+ DeltaSignedness::kForceSigned),
+ ::testing::Values(1, 2, 100, 10000),
+ ::testing::Bool(),
+ ::testing::Values(10, 20, 30)));
+
+// Tests over the quality of the compression (as opposed to its correctness).
+// Not to be confused with tests of runtime efficiency.
+class DeltaEncodingCompressionQualityTest
+ : public ::testing::TestWithParam<
+ std::tuple<DeltaSignedness, uint64_t, uint64_t, uint64_t>> {
+ public:
+ DeltaEncodingCompressionQualityTest()
+ : signedness_(std::get<0>(GetParam())),
+ delta_max_bit_width_(std::get<1>(GetParam())),
+ num_of_values_(std::get<2>(GetParam())),
+ partial_random_seed_(std::get<3>(GetParam())) {
+ MaybeSetSignedness(signedness_);
+ }
+
+ ~DeltaEncodingCompressionQualityTest() override = default;
+
+ // Running with the same seed for all variants would make all tests start
+ // with the same sequence; avoid this by making the seed different.
+ uint64_t Seed() const {
+ // Multiply everything but by different primes to produce unique results.
+ return 2 * static_cast<uint64_t>(signedness_) + 3 * delta_max_bit_width_ +
+ 5 * delta_max_bit_width_ + 7 * num_of_values_ +
+ 11 * partial_random_seed_;
+ }
+
+ const DeltaSignedness signedness_;
+ const uint64_t delta_max_bit_width_;
+ const uint64_t num_of_values_;
+ const uint64_t partial_random_seed_; // Explained where it's used.
+};
+
+// If no wrap-around occurs in the stream, the width of the values does not
+// matter to compression performance; only the deltas matter.
+TEST_P(DeltaEncodingCompressionQualityTest,
+ BaseDoesNotAffectEfficiencyIfNoWrapAround) {
+ // 1. Bases which will not produce a wrap-around.
+ // 2. The last base - 0xffffffffffffffff - does cause a wrap-around, but
+ // that still works, because the width is 64 anyway, and does not
+ // need to be conveyed explicitly in the encoding header.
+ const uint64_t bases[] = {0, 0x55, 0xffffffff,
+ std::numeric_limits<uint64_t>::max()};
+ const size_t kIntendedWrapAroundBaseIndex = arraysize(bases);
+
+ std::vector<uint64_t> deltas(num_of_values_);
+
+ // Allows us to make sure that the deltas do not produce a wrap-around.
+ uint64_t last_element[arraysize(bases)];
+ memcpy(last_element, bases, sizeof(bases));
+
+ // Avoid empty `deltas` due to first element causing wrap-around.
+ deltas[0] = 1;
+ for (size_t i = 0; i < arraysize(last_element); ++i) {
+ last_element[i] += 1;
+ }
+
+ Random prng(Seed());
+
+ for (size_t i = 1; i < deltas.size(); ++i) {
+ const uint64_t delta = RandomWithMaxBitWidth(&prng, delta_max_bit_width_);
+
+ bool wrap_around = false;
+ for (size_t j = 0; j < arraysize(last_element); ++j) {
+ if (j == kIntendedWrapAroundBaseIndex) {
+ continue;
+ }
+
+ last_element[j] += delta;
+ if (last_element[j] < bases[j]) {
+ wrap_around = true;
+ break;
+ }
+ }
+
+ if (wrap_around) {
+ deltas.resize(i);
+ break;
+ }
+
+ deltas[i] = delta;
+ }
+
+ std::string encodings[arraysize(bases)];
+
+ for (size_t i = 0; i < arraysize(bases); ++i) {
+ const auto values =
+ CreateSequenceByDeltas(bases[i], deltas, num_of_values_);
+ // Produce the encoding and write it to encodings[i].
+ // By using TestEncodingAndDecoding() to do this, we also sanity-test
+ // the encoding/decoding, though that is not the test's focus.
+ TestEncodingAndDecoding(bases[i], values, &encodings[i]);
+ EXPECT_LE(encodings[i].length(),
+ EncodingLengthUpperBound(delta_max_bit_width_, num_of_values_,
+ signedness_));
+ }
+
+ // Test focus - all of the encodings should be the same, as they are based
+ // on the same delta sequence, and do not contain a wrap-around.
+ for (size_t i = 1; i < arraysize(encodings); ++i) {
+ EXPECT_EQ(encodings[i], encodings[0]);
+ }
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ SignednessOverrideAndDeltaMaxBitWidthAndNumberOfValuesInSequence,
+ DeltaEncodingCompressionQualityTest,
+ ::testing::Combine(
+ ::testing::Values(DeltaSignedness::kNoOverride,
+ DeltaSignedness::kForceUnsigned,
+ DeltaSignedness::kForceSigned),
+ ::testing::Values(1, 4, 8, 15, 16, 17, 31, 32, 33, 63, 64),
+ ::testing::Values(1, 2, 100, 10000),
+ ::testing::Values(11, 12, 13)));
+
+// Similar to DeltaEncodingTest, but instead of semi-surgically producing
+// specific cases, produce large amount of semi-realistic inputs.
+class DeltaEncodingFuzzerLikeTest
+ : public ::testing::TestWithParam<
+ std::tuple<DeltaSignedness, uint64_t, uint64_t, bool, uint64_t>> {
+ public:
+ DeltaEncodingFuzzerLikeTest()
+ : signedness_(std::get<0>(GetParam())),
+ delta_max_bit_width_(std::get<1>(GetParam())),
+ num_of_values_(std::get<2>(GetParam())),
+ optional_values_(std::get<3>(GetParam())),
+ partial_random_seed_(std::get<4>(GetParam())) {
+ MaybeSetSignedness(signedness_);
+ }
+
+ ~DeltaEncodingFuzzerLikeTest() override = default;
+
+ // Running with the same seed for all variants would make all tests start
+ // with the same sequence; avoid this by making the seed different.
+ uint64_t Seed() const {
+ // Multiply everything but by different primes to produce unique results.
+ return 2 * static_cast<uint64_t>(signedness_) + 3 * delta_max_bit_width_ +
+ 5 * delta_max_bit_width_ + 7 * num_of_values_ +
+ 11 * static_cast<uint64_t>(optional_values_) +
+ 13 * partial_random_seed_;
+ }
+
+ const DeltaSignedness signedness_;
+ const uint64_t delta_max_bit_width_;
+ const uint64_t num_of_values_;
+ const bool optional_values_;
+ const uint64_t partial_random_seed_; // Explained where it's used.
+};
+
+TEST_P(DeltaEncodingFuzzerLikeTest, Test) {
+ const absl::optional<uint64_t> base(3432);
+
+ Random prng(Seed());
+ std::vector<absl::optional<uint64_t>> deltas(num_of_values_);
+ for (size_t i = 0; i < deltas.size(); ++i) {
+ if (!optional_values_ || prng.Rand<bool>()) {
+ deltas[i] = RandomWithMaxBitWidth(&prng, delta_max_bit_width_);
+ }
+ }
+ const auto values =
+ CreateSequenceByOptionalDeltas(base.value(), deltas, num_of_values_);
+
+ TestEncodingAndDecoding(base, values);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ SignednessOverrideAndDeltaMaxBitWidthAndNumberOfValuesInSequence,
+ DeltaEncodingFuzzerLikeTest,
+ ::testing::Combine(
+ ::testing::Values(DeltaSignedness::kNoOverride,
+ DeltaSignedness::kForceUnsigned,
+ DeltaSignedness::kForceSigned),
+ ::testing::Values(1, 4, 8, 15, 16, 17, 31, 32, 33, 63, 64),
+ ::testing::Values(1, 2, 100, 10000),
+ ::testing::Bool(),
+ ::testing::Values(21, 22, 23)));
+
+class DeltaEncodingSpecificEdgeCasesTest
+ : public ::testing::TestWithParam<
+ std::tuple<DeltaSignedness, uint64_t, bool>> {
+ public:
+ DeltaEncodingSpecificEdgeCasesTest() {
+ UnsetFixedLengthEncoderDeltaSignednessForTesting();
+ }
+
+ ~DeltaEncodingSpecificEdgeCasesTest() override = default;
+};
+
+// This case is special because it produces identical forward/backward deltas.
+TEST_F(DeltaEncodingSpecificEdgeCasesTest, SignedDeltaWithOnlyTopBitOn) {
+ MaybeSetSignedness(DeltaSignedness::kForceSigned);
+
+ const absl::optional<uint64_t> base(3432);
+
+ const uint64_t delta = static_cast<uint64_t>(1) << 63;
+ const std::vector<absl::optional<uint64_t>> values = {base.value() + delta};
+
+ TestEncodingAndDecoding(base, values);
+}
+
+TEST_F(DeltaEncodingSpecificEdgeCasesTest, MaximumUnsignedDelta) {
+ MaybeSetSignedness(DeltaSignedness::kForceUnsigned);
+
+ const absl::optional<uint64_t> base((static_cast<uint64_t>(1) << 63) + 0x123);
+
+ const std::vector<absl::optional<uint64_t>> values = {base.value() - 1};
+
+ TestEncodingAndDecoding(base, values);
+}
+
+// Check that, if all deltas are set to -1, things still work.
+TEST_P(DeltaEncodingSpecificEdgeCasesTest, ReverseSequence) {
+ MaybeSetSignedness(std::get<0>(GetParam()));
+ const uint64_t width = std::get<1>(GetParam());
+ const bool wrap_around = std::get<2>(GetParam());
+
+ const uint64_t value_mask = (width == 64)
+ ? std::numeric_limits<uint64_t>::max()
+ : ((static_cast<uint64_t>(1) << width) - 1);
+
+ const uint64_t base = wrap_around ? 1u : (0xf82d3 & value_mask);
+ const std::vector<absl::optional<uint64_t>> values = {
+ (base - 1u) & value_mask, (base - 2u) & value_mask,
+ (base - 3u) & value_mask};
+
+ TestEncodingAndDecoding(base, values);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ _,
+ DeltaEncodingSpecificEdgeCasesTest,
+ ::testing::Combine(
+ ::testing::Values(DeltaSignedness::kNoOverride,
+ DeltaSignedness::kForceUnsigned,
+ DeltaSignedness::kForceSigned),
+ ::testing::Values(1, 4, 8, 15, 16, 17, 31, 32, 33, 63, 64),
+ ::testing::Bool()));
+
+} // namespace
+} // namespace webrtc
diff --git a/third_party/libwebrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder.h b/third_party/libwebrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder.h
new file mode 100644
index 0000000000..3c3dc78990
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2017 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_ENCODER_RTC_EVENT_LOG_ENCODER_H_
+#define LOGGING_RTC_EVENT_LOG_ENCODER_RTC_EVENT_LOG_ENCODER_H_
+
+#include <deque>
+#include <memory>
+#include <string>
+
+#include "api/rtc_event_log/rtc_event.h"
+
+namespace webrtc {
+class RtcEventLogEncoder {
+ public:
+ virtual ~RtcEventLogEncoder() = default;
+
+ virtual std::string EncodeLogStart(int64_t timestamp_us,
+ int64_t utc_time_us) = 0;
+ virtual std::string EncodeLogEnd(int64_t timestamp_us) = 0;
+
+ virtual std::string EncodeBatch(
+ std::deque<std::unique_ptr<RtcEvent>>::const_iterator begin,
+ std::deque<std::unique_ptr<RtcEvent>>::const_iterator end) = 0;
+};
+
+} // namespace webrtc
+
+#endif // LOGGING_RTC_EVENT_LOG_ENCODER_RTC_EVENT_LOG_ENCODER_H_
diff --git a/third_party/libwebrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder_common.cc b/third_party/libwebrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder_common.cc
new file mode 100644
index 0000000000..7aea47611d
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder_common.cc
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2018 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/encoder/rtc_event_log_encoder_common.h"
+
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+namespace {
+// We use 0x3fff because that gives decent precision (compared to the underlying
+// measurement producing the packet loss fraction) on the one hand, while
+// allowing us to use no more than 2 bytes in varint form on the other hand.
+// (We might also fixed-size encode using at most 14 bits.)
+constexpr uint32_t kPacketLossFractionRange = (1 << 14) - 1; // 0x3fff
+constexpr float kPacketLossFractionRangeFloat =
+ static_cast<float>(kPacketLossFractionRange);
+} // namespace
+
+uint32_t ConvertPacketLossFractionToProtoFormat(float packet_loss_fraction) {
+ RTC_DCHECK_GE(packet_loss_fraction, 0);
+ RTC_DCHECK_LE(packet_loss_fraction, 1);
+ return static_cast<uint32_t>(packet_loss_fraction * kPacketLossFractionRange);
+}
+
+bool ParsePacketLossFractionFromProtoFormat(uint32_t proto_packet_loss_fraction,
+ float* output) {
+ if (proto_packet_loss_fraction >= kPacketLossFractionRange) {
+ return false;
+ }
+ *output = proto_packet_loss_fraction / kPacketLossFractionRangeFloat;
+ return true;
+}
+} // namespace webrtc
diff --git a/third_party/libwebrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder_common.h b/third_party/libwebrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder_common.h
new file mode 100644
index 0000000000..c167a8eb8f
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder_common.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2018 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_ENCODER_RTC_EVENT_LOG_ENCODER_COMMON_H_
+#define LOGGING_RTC_EVENT_LOG_ENCODER_RTC_EVENT_LOG_ENCODER_COMMON_H_
+
+#include <stdint.h>
+
+#include <limits>
+#include <type_traits>
+
+namespace webrtc {
+
+// Convert between the packet fraction loss (a floating point number in
+// the range [0.0, 1.0]), and a uint32_t with up to a fixed number of bits.
+// The latter can be more efficiently stored in a protobuf and/or delta-encoded.
+uint32_t ConvertPacketLossFractionToProtoFormat(float packet_loss_fraction);
+bool ParsePacketLossFractionFromProtoFormat(uint32_t proto_packet_loss_fraction,
+ float* output);
+
+} // namespace webrtc
+
+namespace webrtc_event_logging {
+
+// Produce an unsigned representation of a signed integer. On two's complement
+// machines, this is equivalent to:
+// static_cast<uint64_t>(static_cast<std::make_unsigned<T>>(y))
+template <typename T>
+uint64_t ToUnsigned(T y) {
+ static_assert(std::is_integral<T>::value, "");
+ static_assert(std::is_signed<T>::value, "");
+
+ // Note that a signed integer whose width is N bits, has N-1 digits.
+ static_assert(std::numeric_limits<T>::digits < 64, "");
+
+ constexpr T MIN_T = std::numeric_limits<T>::min();
+ constexpr T MAX_T = std::numeric_limits<T>::max();
+
+ static_assert(MAX_T + MIN_T + 1 >= 0, "MAX_T >= abs(MIN_T) - 1");
+
+ if (y >= 0) {
+ return static_cast<uint64_t>(y);
+ } else {
+ // y is in the range [MIN_T, -1], so (y - MIN_T) is in the
+ // range [0, abs(MIN_T) - 1]. This is representable in a T
+ // because MAX_T >= abs(MIN_T) - 1, as per the static_assert above.
+ return static_cast<uint64_t>(MAX_T) + 1 + static_cast<uint64_t>(y - MIN_T);
+ }
+}
+
+// Assuming x = ToUnsigned(y), return `y`.
+// Note: static_cast<T>(x) would work on most platforms and compilers, but
+// involves undefined behavior. This function is well-defined, and can be
+// optimized to a noop for 64 bit types, or a few arithmetic
+// instructions and a single conditional jump for narrower types.
+template <typename T>
+bool ToSigned(uint64_t x, T* y) {
+ static_assert(std::is_integral<T>::value, "");
+ static_assert(std::is_signed<T>::value, "");
+
+ // Note that a signed integer whose width is N bits, has N-1 digits.
+ static_assert(std::numeric_limits<T>::digits < 64, "");
+
+ constexpr T MIN_T = std::numeric_limits<T>::min();
+ constexpr T MAX_T = std::numeric_limits<T>::max();
+
+ using UNSIGNED_T = typename std::make_unsigned<T>::type;
+ constexpr auto MAX_UNSIGNED_T = std::numeric_limits<UNSIGNED_T>::max();
+ if (x > static_cast<uint64_t>(MAX_UNSIGNED_T)) {
+ return false; // `x` cannot be represented using a T.
+ }
+
+ if (x <= static_cast<uint64_t>(MAX_T)) {
+ // The original value was positive, so it is safe to just static_cast.
+ *y = static_cast<T>(x);
+ } else { // x > static_cast<uint64_t>(MAX_T)
+ const uint64_t neg_x = x - static_cast<uint64_t>(MAX_T) - 1;
+ *y = static_cast<T>(neg_x) + MIN_T;
+ }
+
+ return true;
+}
+
+} // namespace webrtc_event_logging
+
+#endif // LOGGING_RTC_EVENT_LOG_ENCODER_RTC_EVENT_LOG_ENCODER_COMMON_H_
diff --git a/third_party/libwebrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder_common_unittest.cc b/third_party/libwebrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder_common_unittest.cc
new file mode 100644
index 0000000000..0afa5368d1
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder_common_unittest.cc
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2018 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/encoder/rtc_event_log_encoder_common.h"
+
+#include <cstdint>
+#include <limits>
+#include <type_traits>
+#include <vector>
+
+#include "test/gtest.h"
+
+namespace webrtc_event_logging {
+namespace {
+
+template <typename T>
+class SignednessConversionTest : public ::testing::Test {
+ public:
+ static_assert(std::is_integral<T>::value, "");
+ static_assert(std::is_signed<T>::value, "");
+};
+
+TYPED_TEST_SUITE_P(SignednessConversionTest);
+
+TYPED_TEST_P(SignednessConversionTest, CorrectlyConvertsLegalValues) {
+ using T = TypeParam;
+ std::vector<T> legal_values = {std::numeric_limits<T>::min(),
+ std::numeric_limits<T>::min() + 1,
+ -1,
+ 0,
+ 1,
+ std::numeric_limits<T>::max() - 1,
+ std::numeric_limits<T>::max()};
+ for (T val : legal_values) {
+ const auto unsigned_val = ToUnsigned(val);
+ T signed_val;
+ ASSERT_TRUE(ToSigned<T>(unsigned_val, &signed_val))
+ << "Failed on " << static_cast<uint64_t>(unsigned_val) << ".";
+ EXPECT_EQ(val, signed_val)
+ << "Failed on " << static_cast<uint64_t>(unsigned_val) << ".";
+ }
+}
+
+TYPED_TEST_P(SignednessConversionTest, FailsOnConvertingIllegalValues) {
+ using T = TypeParam;
+
+ // Note that a signed integer whose width is N bits, has N-1 digits.
+ constexpr bool width_is_64 = std::numeric_limits<T>::digits == 63;
+
+ if (width_is_64) {
+ return; // Test irrelevant; illegal values do not exist.
+ }
+
+ const uint64_t max_legal_value = ToUnsigned(static_cast<T>(-1));
+
+ const std::vector<uint64_t> illegal_values = {
+ max_legal_value + 1u, max_legal_value + 2u,
+ std::numeric_limits<uint64_t>::max() - 1u,
+ std::numeric_limits<uint64_t>::max()};
+
+ for (uint64_t unsigned_val : illegal_values) {
+ T signed_val;
+ EXPECT_FALSE(ToSigned<T>(unsigned_val, &signed_val))
+ << "Failed on " << static_cast<uint64_t>(unsigned_val) << ".";
+ }
+}
+
+REGISTER_TYPED_TEST_SUITE_P(SignednessConversionTest,
+ CorrectlyConvertsLegalValues,
+ FailsOnConvertingIllegalValues);
+
+using Types = ::testing::Types<int8_t, int16_t, int32_t, int64_t>;
+
+INSTANTIATE_TYPED_TEST_SUITE_P(_, SignednessConversionTest, Types);
+
+} // namespace
+} // namespace webrtc_event_logging
diff --git a/third_party/libwebrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder_legacy.cc b/third_party/libwebrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder_legacy.cc
new file mode 100644
index 0000000000..5619827246
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder_legacy.cc
@@ -0,0 +1,814 @@
+/*
+ * Copyright (c) 2017 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/encoder/rtc_event_log_encoder_legacy.h"
+
+#include <string.h>
+
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "api/network_state_predictor.h"
+#include "api/rtp_headers.h"
+#include "api/rtp_parameters.h"
+#include "api/transport/network_types.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"
+#include "logging/rtc_event_log/events/rtc_event_audio_receive_stream_config.h"
+#include "logging/rtc_event_log/events/rtc_event_audio_send_stream_config.h"
+#include "logging/rtc_event_log/events/rtc_event_bwe_update_delay_based.h"
+#include "logging/rtc_event_log/events/rtc_event_bwe_update_loss_based.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"
+#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_remote_estimate.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"
+#include "logging/rtc_event_log/events/rtc_event_rtp_packet_outgoing.h"
+#include "logging/rtc_event_log/events/rtc_event_video_receive_stream_config.h"
+#include "logging/rtc_event_log/events/rtc_event_video_send_stream_config.h"
+#include "logging/rtc_event_log/rtc_stream_config.h"
+#include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor_config.h"
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/app.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/bye.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/extended_reports.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/psfb.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/receiver_report.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/rtpfb.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/sdes.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/sender_report.h"
+#include "modules/rtp_rtcp/source/rtp_packet.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/ignore_wundef.h"
+#include "rtc_base/logging.h"
+
+// *.pb.h files are generated at build-time by the protobuf compiler.
+RTC_PUSH_IGNORING_WUNDEF()
+#ifdef WEBRTC_ANDROID_PLATFORM_BUILD
+#include "external/webrtc/webrtc/logging/rtc_event_log/rtc_event_log.pb.h"
+#else
+#include "logging/rtc_event_log/rtc_event_log.pb.h"
+#endif
+RTC_POP_IGNORING_WUNDEF()
+
+namespace webrtc {
+
+namespace {
+rtclog::DelayBasedBweUpdate::DetectorState ConvertDetectorState(
+ BandwidthUsage state) {
+ switch (state) {
+ case BandwidthUsage::kBwNormal:
+ return rtclog::DelayBasedBweUpdate::BWE_NORMAL;
+ case BandwidthUsage::kBwUnderusing:
+ return rtclog::DelayBasedBweUpdate::BWE_UNDERUSING;
+ case BandwidthUsage::kBwOverusing:
+ return rtclog::DelayBasedBweUpdate::BWE_OVERUSING;
+ case BandwidthUsage::kLast:
+ RTC_DCHECK_NOTREACHED();
+ }
+ RTC_DCHECK_NOTREACHED();
+ return rtclog::DelayBasedBweUpdate::BWE_NORMAL;
+}
+
+rtclog::BweProbeResult::ResultType ConvertProbeResultType(
+ ProbeFailureReason failure_reason) {
+ switch (failure_reason) {
+ case ProbeFailureReason::kInvalidSendReceiveInterval:
+ return rtclog::BweProbeResult::INVALID_SEND_RECEIVE_INTERVAL;
+ case ProbeFailureReason::kInvalidSendReceiveRatio:
+ return rtclog::BweProbeResult::INVALID_SEND_RECEIVE_RATIO;
+ case ProbeFailureReason::kTimeout:
+ return rtclog::BweProbeResult::TIMEOUT;
+ case ProbeFailureReason::kLast:
+ RTC_DCHECK_NOTREACHED();
+ }
+ RTC_DCHECK_NOTREACHED();
+ return rtclog::BweProbeResult::SUCCESS;
+}
+
+rtclog::VideoReceiveConfig_RtcpMode ConvertRtcpMode(RtcpMode rtcp_mode) {
+ switch (rtcp_mode) {
+ case RtcpMode::kCompound:
+ return rtclog::VideoReceiveConfig::RTCP_COMPOUND;
+ case RtcpMode::kReducedSize:
+ return rtclog::VideoReceiveConfig::RTCP_REDUCEDSIZE;
+ case RtcpMode::kOff:
+ RTC_DCHECK_NOTREACHED();
+ }
+ RTC_DCHECK_NOTREACHED();
+ return rtclog::VideoReceiveConfig::RTCP_COMPOUND;
+}
+
+rtclog::IceCandidatePairConfig::IceCandidatePairConfigType
+ConvertIceCandidatePairConfigType(IceCandidatePairConfigType type) {
+ switch (type) {
+ case IceCandidatePairConfigType::kAdded:
+ return rtclog::IceCandidatePairConfig::ADDED;
+ case IceCandidatePairConfigType::kUpdated:
+ return rtclog::IceCandidatePairConfig::UPDATED;
+ case IceCandidatePairConfigType::kDestroyed:
+ return rtclog::IceCandidatePairConfig::DESTROYED;
+ case IceCandidatePairConfigType::kSelected:
+ return rtclog::IceCandidatePairConfig::SELECTED;
+ case IceCandidatePairConfigType::kNumValues:
+ RTC_DCHECK_NOTREACHED();
+ }
+ RTC_DCHECK_NOTREACHED();
+ return rtclog::IceCandidatePairConfig::ADDED;
+}
+
+rtclog::IceCandidatePairConfig::IceCandidateType ConvertIceCandidateType(
+ IceCandidateType type) {
+ switch (type) {
+ case IceCandidateType::kUnknown:
+ return rtclog::IceCandidatePairConfig::UNKNOWN_CANDIDATE_TYPE;
+ case IceCandidateType::kLocal:
+ return rtclog::IceCandidatePairConfig::LOCAL;
+ case IceCandidateType::kStun:
+ return rtclog::IceCandidatePairConfig::STUN;
+ case IceCandidateType::kPrflx:
+ return rtclog::IceCandidatePairConfig::PRFLX;
+ case IceCandidateType::kRelay:
+ return rtclog::IceCandidatePairConfig::RELAY;
+ case IceCandidateType::kNumValues:
+ RTC_DCHECK_NOTREACHED();
+ }
+ RTC_DCHECK_NOTREACHED();
+ return rtclog::IceCandidatePairConfig::UNKNOWN_CANDIDATE_TYPE;
+}
+
+rtclog::IceCandidatePairConfig::Protocol ConvertIceCandidatePairProtocol(
+ IceCandidatePairProtocol protocol) {
+ switch (protocol) {
+ case IceCandidatePairProtocol::kUnknown:
+ return rtclog::IceCandidatePairConfig::UNKNOWN_PROTOCOL;
+ case IceCandidatePairProtocol::kUdp:
+ return rtclog::IceCandidatePairConfig::UDP;
+ case IceCandidatePairProtocol::kTcp:
+ return rtclog::IceCandidatePairConfig::TCP;
+ case IceCandidatePairProtocol::kSsltcp:
+ return rtclog::IceCandidatePairConfig::SSLTCP;
+ case IceCandidatePairProtocol::kTls:
+ return rtclog::IceCandidatePairConfig::TLS;
+ case IceCandidatePairProtocol::kNumValues:
+ RTC_DCHECK_NOTREACHED();
+ }
+ RTC_DCHECK_NOTREACHED();
+ return rtclog::IceCandidatePairConfig::UNKNOWN_PROTOCOL;
+}
+
+rtclog::IceCandidatePairConfig::AddressFamily
+ConvertIceCandidatePairAddressFamily(
+ IceCandidatePairAddressFamily address_family) {
+ switch (address_family) {
+ case IceCandidatePairAddressFamily::kUnknown:
+ return rtclog::IceCandidatePairConfig::UNKNOWN_ADDRESS_FAMILY;
+ case IceCandidatePairAddressFamily::kIpv4:
+ return rtclog::IceCandidatePairConfig::IPV4;
+ case IceCandidatePairAddressFamily::kIpv6:
+ return rtclog::IceCandidatePairConfig::IPV6;
+ case IceCandidatePairAddressFamily::kNumValues:
+ RTC_DCHECK_NOTREACHED();
+ }
+ RTC_DCHECK_NOTREACHED();
+ return rtclog::IceCandidatePairConfig::UNKNOWN_ADDRESS_FAMILY;
+}
+
+rtclog::IceCandidatePairConfig::NetworkType ConvertIceCandidateNetworkType(
+ IceCandidateNetworkType network_type) {
+ switch (network_type) {
+ case IceCandidateNetworkType::kUnknown:
+ return rtclog::IceCandidatePairConfig::UNKNOWN_NETWORK_TYPE;
+ case IceCandidateNetworkType::kEthernet:
+ return rtclog::IceCandidatePairConfig::ETHERNET;
+ case IceCandidateNetworkType::kLoopback:
+ return rtclog::IceCandidatePairConfig::LOOPBACK;
+ case IceCandidateNetworkType::kWifi:
+ return rtclog::IceCandidatePairConfig::WIFI;
+ case IceCandidateNetworkType::kVpn:
+ return rtclog::IceCandidatePairConfig::VPN;
+ case IceCandidateNetworkType::kCellular:
+ return rtclog::IceCandidatePairConfig::CELLULAR;
+ case IceCandidateNetworkType::kNumValues:
+ RTC_DCHECK_NOTREACHED();
+ }
+ RTC_DCHECK_NOTREACHED();
+ return rtclog::IceCandidatePairConfig::UNKNOWN_NETWORK_TYPE;
+}
+
+rtclog::IceCandidatePairEvent::IceCandidatePairEventType
+ConvertIceCandidatePairEventType(IceCandidatePairEventType type) {
+ switch (type) {
+ case IceCandidatePairEventType::kCheckSent:
+ return rtclog::IceCandidatePairEvent::CHECK_SENT;
+ case IceCandidatePairEventType::kCheckReceived:
+ return rtclog::IceCandidatePairEvent::CHECK_RECEIVED;
+ case IceCandidatePairEventType::kCheckResponseSent:
+ return rtclog::IceCandidatePairEvent::CHECK_RESPONSE_SENT;
+ case IceCandidatePairEventType::kCheckResponseReceived:
+ return rtclog::IceCandidatePairEvent::CHECK_RESPONSE_RECEIVED;
+ case IceCandidatePairEventType::kNumValues:
+ RTC_DCHECK_NOTREACHED();
+ }
+ RTC_DCHECK_NOTREACHED();
+ return rtclog::IceCandidatePairEvent::CHECK_SENT;
+}
+
+} // namespace
+
+std::string RtcEventLogEncoderLegacy::EncodeLogStart(int64_t timestamp_us,
+ int64_t utc_time_us) {
+ rtclog::Event rtclog_event;
+ rtclog_event.set_timestamp_us(timestamp_us);
+ rtclog_event.set_type(rtclog::Event::LOG_START);
+ return Serialize(&rtclog_event);
+}
+
+std::string RtcEventLogEncoderLegacy::EncodeLogEnd(int64_t timestamp_us) {
+ rtclog::Event rtclog_event;
+ rtclog_event.set_timestamp_us(timestamp_us);
+ rtclog_event.set_type(rtclog::Event::LOG_END);
+ return Serialize(&rtclog_event);
+}
+
+std::string RtcEventLogEncoderLegacy::EncodeBatch(
+ std::deque<std::unique_ptr<RtcEvent>>::const_iterator begin,
+ std::deque<std::unique_ptr<RtcEvent>>::const_iterator end) {
+ std::string encoded_output;
+ for (auto it = begin; it != end; ++it) {
+ // TODO(terelius): Can we avoid the slight inefficiency of reallocating the
+ // string?
+ RTC_CHECK(it->get() != nullptr);
+ encoded_output += Encode(**it);
+ }
+ return encoded_output;
+}
+
+std::string RtcEventLogEncoderLegacy::Encode(const RtcEvent& event) {
+ switch (event.GetType()) {
+ case RtcEvent::Type::AudioNetworkAdaptation: {
+ auto& rtc_event =
+ static_cast<const RtcEventAudioNetworkAdaptation&>(event);
+ return EncodeAudioNetworkAdaptation(rtc_event);
+ }
+
+ case RtcEvent::Type::AlrStateEvent: {
+ auto& rtc_event = static_cast<const RtcEventAlrState&>(event);
+ return EncodeAlrState(rtc_event);
+ }
+
+ case RtcEvent::Type::AudioPlayout: {
+ auto& rtc_event = static_cast<const RtcEventAudioPlayout&>(event);
+ return EncodeAudioPlayout(rtc_event);
+ }
+
+ case RtcEvent::Type::AudioReceiveStreamConfig: {
+ auto& rtc_event =
+ static_cast<const RtcEventAudioReceiveStreamConfig&>(event);
+ return EncodeAudioReceiveStreamConfig(rtc_event);
+ }
+
+ case RtcEvent::Type::AudioSendStreamConfig: {
+ auto& rtc_event =
+ static_cast<const RtcEventAudioSendStreamConfig&>(event);
+ return EncodeAudioSendStreamConfig(rtc_event);
+ }
+
+ case RtcEvent::Type::BweUpdateDelayBased: {
+ auto& rtc_event = static_cast<const RtcEventBweUpdateDelayBased&>(event);
+ return EncodeBweUpdateDelayBased(rtc_event);
+ }
+
+ case RtcEvent::Type::BweUpdateLossBased: {
+ auto& rtc_event = static_cast<const RtcEventBweUpdateLossBased&>(event);
+ return EncodeBweUpdateLossBased(rtc_event);
+ }
+
+ case RtcEvent::Type::DtlsTransportState: {
+ return "";
+ }
+
+ case RtcEvent::Type::DtlsWritableState: {
+ return "";
+ }
+
+ case RtcEvent::Type::IceCandidatePairConfig: {
+ auto& rtc_event =
+ static_cast<const RtcEventIceCandidatePairConfig&>(event);
+ return EncodeIceCandidatePairConfig(rtc_event);
+ }
+
+ case RtcEvent::Type::IceCandidatePairEvent: {
+ auto& rtc_event = static_cast<const RtcEventIceCandidatePair&>(event);
+ return EncodeIceCandidatePairEvent(rtc_event);
+ }
+
+ case RtcEvent::Type::ProbeClusterCreated: {
+ auto& rtc_event = static_cast<const RtcEventProbeClusterCreated&>(event);
+ return EncodeProbeClusterCreated(rtc_event);
+ }
+
+ case RtcEvent::Type::ProbeResultFailure: {
+ auto& rtc_event = static_cast<const RtcEventProbeResultFailure&>(event);
+ return EncodeProbeResultFailure(rtc_event);
+ }
+
+ case RtcEvent::Type::ProbeResultSuccess: {
+ auto& rtc_event = static_cast<const RtcEventProbeResultSuccess&>(event);
+ return EncodeProbeResultSuccess(rtc_event);
+ }
+
+ case RtcEvent::Type::RemoteEstimateEvent: {
+ auto& rtc_event = static_cast<const RtcEventRemoteEstimate&>(event);
+ return EncodeRemoteEstimate(rtc_event);
+ }
+
+ case RtcEvent::Type::RtcpPacketIncoming: {
+ auto& rtc_event = static_cast<const RtcEventRtcpPacketIncoming&>(event);
+ return EncodeRtcpPacketIncoming(rtc_event);
+ }
+
+ case RtcEvent::Type::RtcpPacketOutgoing: {
+ auto& rtc_event = static_cast<const RtcEventRtcpPacketOutgoing&>(event);
+ return EncodeRtcpPacketOutgoing(rtc_event);
+ }
+
+ case RtcEvent::Type::RtpPacketIncoming: {
+ auto& rtc_event = static_cast<const RtcEventRtpPacketIncoming&>(event);
+ return EncodeRtpPacketIncoming(rtc_event);
+ }
+
+ case RtcEvent::Type::RtpPacketOutgoing: {
+ auto& rtc_event = static_cast<const RtcEventRtpPacketOutgoing&>(event);
+ return EncodeRtpPacketOutgoing(rtc_event);
+ }
+
+ case RtcEvent::Type::VideoReceiveStreamConfig: {
+ auto& rtc_event =
+ static_cast<const RtcEventVideoReceiveStreamConfig&>(event);
+ return EncodeVideoReceiveStreamConfig(rtc_event);
+ }
+
+ case RtcEvent::Type::VideoSendStreamConfig: {
+ auto& rtc_event =
+ static_cast<const RtcEventVideoSendStreamConfig&>(event);
+ return EncodeVideoSendStreamConfig(rtc_event);
+ }
+ case RtcEvent::Type::BeginV3Log:
+ case RtcEvent::Type::EndV3Log:
+ // These special events are written as part of starting
+ // and stopping the log, and only as part of version 3 of the format.
+ RTC_DCHECK_NOTREACHED();
+ break;
+ case RtcEvent::Type::FakeEvent:
+ // Fake event used for unit test.
+ RTC_DCHECK_NOTREACHED();
+ break;
+ case RtcEvent::Type::RouteChangeEvent:
+ case RtcEvent::Type::GenericPacketReceived:
+ case RtcEvent::Type::GenericPacketSent:
+ case RtcEvent::Type::GenericAckReceived:
+ case RtcEvent::Type::FrameDecoded:
+ case RtcEvent::Type::NetEqSetMinimumDelay:
+ // These are unsupported in the old format, but shouldn't crash.
+ return "";
+ }
+
+ int event_type = static_cast<int>(event.GetType());
+ RTC_DCHECK_NOTREACHED() << "Unknown event type (" << event_type << ")";
+ return "";
+}
+
+std::string RtcEventLogEncoderLegacy::EncodeAlrState(
+ const RtcEventAlrState& event) {
+ rtclog::Event rtclog_event;
+ rtclog_event.set_timestamp_us(event.timestamp_us());
+ rtclog_event.set_type(rtclog::Event::ALR_STATE_EVENT);
+
+ auto* alr_state = rtclog_event.mutable_alr_state();
+ alr_state->set_in_alr(event.in_alr());
+ return Serialize(&rtclog_event);
+}
+
+std::string RtcEventLogEncoderLegacy::EncodeAudioNetworkAdaptation(
+ const RtcEventAudioNetworkAdaptation& event) {
+ rtclog::Event rtclog_event;
+ rtclog_event.set_timestamp_us(event.timestamp_us());
+ rtclog_event.set_type(rtclog::Event::AUDIO_NETWORK_ADAPTATION_EVENT);
+
+ auto* audio_network_adaptation =
+ rtclog_event.mutable_audio_network_adaptation();
+ if (event.config().bitrate_bps)
+ audio_network_adaptation->set_bitrate_bps(*event.config().bitrate_bps);
+ if (event.config().frame_length_ms)
+ audio_network_adaptation->set_frame_length_ms(
+ *event.config().frame_length_ms);
+ if (event.config().uplink_packet_loss_fraction) {
+ audio_network_adaptation->set_uplink_packet_loss_fraction(
+ *event.config().uplink_packet_loss_fraction);
+ }
+ if (event.config().enable_fec)
+ audio_network_adaptation->set_enable_fec(*event.config().enable_fec);
+ if (event.config().enable_dtx)
+ audio_network_adaptation->set_enable_dtx(*event.config().enable_dtx);
+ if (event.config().num_channels)
+ audio_network_adaptation->set_num_channels(*event.config().num_channels);
+
+ return Serialize(&rtclog_event);
+}
+
+std::string RtcEventLogEncoderLegacy::EncodeAudioPlayout(
+ const RtcEventAudioPlayout& event) {
+ rtclog::Event rtclog_event;
+ rtclog_event.set_timestamp_us(event.timestamp_us());
+ rtclog_event.set_type(rtclog::Event::AUDIO_PLAYOUT_EVENT);
+
+ auto* playout_event = rtclog_event.mutable_audio_playout_event();
+ playout_event->set_local_ssrc(event.ssrc());
+
+ return Serialize(&rtclog_event);
+}
+
+std::string RtcEventLogEncoderLegacy::EncodeAudioReceiveStreamConfig(
+ const RtcEventAudioReceiveStreamConfig& event) {
+ rtclog::Event rtclog_event;
+ rtclog_event.set_timestamp_us(event.timestamp_us());
+ rtclog_event.set_type(rtclog::Event::AUDIO_RECEIVER_CONFIG_EVENT);
+
+ rtclog::AudioReceiveConfig* receiver_config =
+ rtclog_event.mutable_audio_receiver_config();
+ receiver_config->set_remote_ssrc(event.config().remote_ssrc);
+ receiver_config->set_local_ssrc(event.config().local_ssrc);
+
+ for (const auto& e : event.config().rtp_extensions) {
+ rtclog::RtpHeaderExtension* extension =
+ receiver_config->add_header_extensions();
+ extension->set_name(e.uri);
+ extension->set_id(e.id);
+ }
+
+ return Serialize(&rtclog_event);
+}
+
+std::string RtcEventLogEncoderLegacy::EncodeAudioSendStreamConfig(
+ const RtcEventAudioSendStreamConfig& event) {
+ rtclog::Event rtclog_event;
+ rtclog_event.set_timestamp_us(event.timestamp_us());
+ rtclog_event.set_type(rtclog::Event::AUDIO_SENDER_CONFIG_EVENT);
+
+ rtclog::AudioSendConfig* sender_config =
+ rtclog_event.mutable_audio_sender_config();
+
+ sender_config->set_ssrc(event.config().local_ssrc);
+
+ for (const auto& e : event.config().rtp_extensions) {
+ rtclog::RtpHeaderExtension* extension =
+ sender_config->add_header_extensions();
+ extension->set_name(e.uri);
+ extension->set_id(e.id);
+ }
+
+ return Serialize(&rtclog_event);
+}
+
+std::string RtcEventLogEncoderLegacy::EncodeBweUpdateDelayBased(
+ const RtcEventBweUpdateDelayBased& event) {
+ rtclog::Event rtclog_event;
+ rtclog_event.set_timestamp_us(event.timestamp_us());
+ rtclog_event.set_type(rtclog::Event::DELAY_BASED_BWE_UPDATE);
+
+ auto* bwe_event = rtclog_event.mutable_delay_based_bwe_update();
+ bwe_event->set_bitrate_bps(event.bitrate_bps());
+ bwe_event->set_detector_state(ConvertDetectorState(event.detector_state()));
+
+ return Serialize(&rtclog_event);
+}
+
+std::string RtcEventLogEncoderLegacy::EncodeBweUpdateLossBased(
+ const RtcEventBweUpdateLossBased& event) {
+ rtclog::Event rtclog_event;
+ rtclog_event.set_timestamp_us(event.timestamp_us());
+ rtclog_event.set_type(rtclog::Event::LOSS_BASED_BWE_UPDATE);
+
+ auto* bwe_event = rtclog_event.mutable_loss_based_bwe_update();
+ bwe_event->set_bitrate_bps(event.bitrate_bps());
+ bwe_event->set_fraction_loss(event.fraction_loss());
+ bwe_event->set_total_packets(event.total_packets());
+
+ return Serialize(&rtclog_event);
+}
+
+std::string RtcEventLogEncoderLegacy::EncodeIceCandidatePairConfig(
+ const RtcEventIceCandidatePairConfig& event) {
+ rtclog::Event encoded_rtc_event;
+ encoded_rtc_event.set_timestamp_us(event.timestamp_us());
+ encoded_rtc_event.set_type(rtclog::Event::ICE_CANDIDATE_PAIR_CONFIG);
+
+ auto* encoded_ice_event =
+ encoded_rtc_event.mutable_ice_candidate_pair_config();
+ encoded_ice_event->set_config_type(
+ ConvertIceCandidatePairConfigType(event.type()));
+ encoded_ice_event->set_candidate_pair_id(event.candidate_pair_id());
+ const auto& desc = event.candidate_pair_desc();
+ encoded_ice_event->set_local_candidate_type(
+ ConvertIceCandidateType(desc.local_candidate_type));
+ encoded_ice_event->set_local_relay_protocol(
+ ConvertIceCandidatePairProtocol(desc.local_relay_protocol));
+ encoded_ice_event->set_local_network_type(
+ ConvertIceCandidateNetworkType(desc.local_network_type));
+ encoded_ice_event->set_local_address_family(
+ ConvertIceCandidatePairAddressFamily(desc.local_address_family));
+ encoded_ice_event->set_remote_candidate_type(
+ ConvertIceCandidateType(desc.remote_candidate_type));
+ encoded_ice_event->set_remote_address_family(
+ ConvertIceCandidatePairAddressFamily(desc.remote_address_family));
+ encoded_ice_event->set_candidate_pair_protocol(
+ ConvertIceCandidatePairProtocol(desc.candidate_pair_protocol));
+ return Serialize(&encoded_rtc_event);
+}
+
+std::string RtcEventLogEncoderLegacy::EncodeIceCandidatePairEvent(
+ const RtcEventIceCandidatePair& event) {
+ rtclog::Event encoded_rtc_event;
+ encoded_rtc_event.set_timestamp_us(event.timestamp_us());
+ encoded_rtc_event.set_type(rtclog::Event::ICE_CANDIDATE_PAIR_EVENT);
+
+ auto* encoded_ice_event =
+ encoded_rtc_event.mutable_ice_candidate_pair_event();
+ encoded_ice_event->set_event_type(
+ ConvertIceCandidatePairEventType(event.type()));
+ encoded_ice_event->set_candidate_pair_id(event.candidate_pair_id());
+ return Serialize(&encoded_rtc_event);
+}
+
+std::string RtcEventLogEncoderLegacy::EncodeProbeClusterCreated(
+ const RtcEventProbeClusterCreated& event) {
+ rtclog::Event rtclog_event;
+ rtclog_event.set_timestamp_us(event.timestamp_us());
+ rtclog_event.set_type(rtclog::Event::BWE_PROBE_CLUSTER_CREATED_EVENT);
+
+ auto* probe_cluster = rtclog_event.mutable_probe_cluster();
+ probe_cluster->set_id(event.id());
+ probe_cluster->set_bitrate_bps(event.bitrate_bps());
+ probe_cluster->set_min_packets(event.min_probes());
+ probe_cluster->set_min_bytes(event.min_bytes());
+
+ return Serialize(&rtclog_event);
+}
+
+std::string RtcEventLogEncoderLegacy::EncodeProbeResultFailure(
+ const RtcEventProbeResultFailure& event) {
+ rtclog::Event rtclog_event;
+ rtclog_event.set_timestamp_us(event.timestamp_us());
+ rtclog_event.set_type(rtclog::Event::BWE_PROBE_RESULT_EVENT);
+
+ auto* probe_result = rtclog_event.mutable_probe_result();
+ probe_result->set_id(event.id());
+ probe_result->set_result(ConvertProbeResultType(event.failure_reason()));
+
+ return Serialize(&rtclog_event);
+}
+
+std::string RtcEventLogEncoderLegacy::EncodeProbeResultSuccess(
+ const RtcEventProbeResultSuccess& event) {
+ rtclog::Event rtclog_event;
+ rtclog_event.set_timestamp_us(event.timestamp_us());
+ rtclog_event.set_type(rtclog::Event::BWE_PROBE_RESULT_EVENT);
+
+ auto* probe_result = rtclog_event.mutable_probe_result();
+ probe_result->set_id(event.id());
+ probe_result->set_result(rtclog::BweProbeResult::SUCCESS);
+ probe_result->set_bitrate_bps(event.bitrate_bps());
+
+ return Serialize(&rtclog_event);
+}
+
+std::string RtcEventLogEncoderLegacy::EncodeRemoteEstimate(
+ const RtcEventRemoteEstimate& event) {
+ rtclog::Event rtclog_event;
+ rtclog_event.set_timestamp_us(event.timestamp_us());
+ rtclog_event.set_type(rtclog::Event::REMOTE_ESTIMATE);
+
+ auto* remote_estimate = rtclog_event.mutable_remote_estimate();
+ if (event.link_capacity_lower_.IsFinite())
+ remote_estimate->set_link_capacity_lower_kbps(
+ event.link_capacity_lower_.kbps<uint32_t>());
+ if (event.link_capacity_upper_.IsFinite())
+ remote_estimate->set_link_capacity_upper_kbps(
+ event.link_capacity_upper_.kbps<uint32_t>());
+
+ return Serialize(&rtclog_event);
+}
+
+std::string RtcEventLogEncoderLegacy::EncodeRtcpPacketIncoming(
+ const RtcEventRtcpPacketIncoming& event) {
+ return EncodeRtcpPacket(event.timestamp_us(), event.packet(), true);
+}
+
+std::string RtcEventLogEncoderLegacy::EncodeRtcpPacketOutgoing(
+ const RtcEventRtcpPacketOutgoing& event) {
+ return EncodeRtcpPacket(event.timestamp_us(), event.packet(), false);
+}
+
+std::string RtcEventLogEncoderLegacy::EncodeRtpPacketIncoming(
+ const RtcEventRtpPacketIncoming& event) {
+ return EncodeRtpPacket(event.timestamp_us(), event.RawHeader(),
+ event.packet_length(), PacedPacketInfo::kNotAProbe,
+ true);
+}
+
+std::string RtcEventLogEncoderLegacy::EncodeRtpPacketOutgoing(
+ const RtcEventRtpPacketOutgoing& event) {
+ return EncodeRtpPacket(event.timestamp_us(), event.RawHeader(),
+ event.packet_length(), event.probe_cluster_id(),
+ false);
+}
+
+std::string RtcEventLogEncoderLegacy::EncodeVideoReceiveStreamConfig(
+ const RtcEventVideoReceiveStreamConfig& event) {
+ rtclog::Event rtclog_event;
+ rtclog_event.set_timestamp_us(event.timestamp_us());
+ rtclog_event.set_type(rtclog::Event::VIDEO_RECEIVER_CONFIG_EVENT);
+
+ rtclog::VideoReceiveConfig* receiver_config =
+ rtclog_event.mutable_video_receiver_config();
+ receiver_config->set_remote_ssrc(event.config().remote_ssrc);
+ receiver_config->set_local_ssrc(event.config().local_ssrc);
+
+ // TODO(perkj): Add field for rsid.
+ receiver_config->set_rtcp_mode(ConvertRtcpMode(event.config().rtcp_mode));
+ receiver_config->set_remb(event.config().remb);
+
+ for (const auto& e : event.config().rtp_extensions) {
+ rtclog::RtpHeaderExtension* extension =
+ receiver_config->add_header_extensions();
+ extension->set_name(e.uri);
+ extension->set_id(e.id);
+ }
+
+ for (const auto& d : event.config().codecs) {
+ rtclog::DecoderConfig* decoder = receiver_config->add_decoders();
+ decoder->set_name(d.payload_name);
+ decoder->set_payload_type(d.payload_type);
+ if (d.rtx_payload_type != 0) {
+ rtclog::RtxMap* rtx = receiver_config->add_rtx_map();
+ rtx->set_payload_type(d.payload_type);
+ rtx->mutable_config()->set_rtx_ssrc(event.config().rtx_ssrc);
+ rtx->mutable_config()->set_rtx_payload_type(d.rtx_payload_type);
+ }
+ }
+
+ return Serialize(&rtclog_event);
+}
+
+std::string RtcEventLogEncoderLegacy::EncodeVideoSendStreamConfig(
+ const RtcEventVideoSendStreamConfig& event) {
+ rtclog::Event rtclog_event;
+ rtclog_event.set_timestamp_us(event.timestamp_us());
+ rtclog_event.set_type(rtclog::Event::VIDEO_SENDER_CONFIG_EVENT);
+
+ rtclog::VideoSendConfig* sender_config =
+ rtclog_event.mutable_video_sender_config();
+
+ // TODO(perkj): rtclog::VideoSendConfig should only contain one SSRC.
+ sender_config->add_ssrcs(event.config().local_ssrc);
+ if (event.config().rtx_ssrc != 0) {
+ sender_config->add_rtx_ssrcs(event.config().rtx_ssrc);
+ }
+
+ for (const auto& e : event.config().rtp_extensions) {
+ rtclog::RtpHeaderExtension* extension =
+ sender_config->add_header_extensions();
+ extension->set_name(e.uri);
+ extension->set_id(e.id);
+ }
+
+ // TODO(perkj): rtclog::VideoSendConfig should contain many possible codec
+ // configurations.
+ for (const auto& codec : event.config().codecs) {
+ sender_config->set_rtx_payload_type(codec.rtx_payload_type);
+ rtclog::EncoderConfig* encoder = sender_config->mutable_encoder();
+ encoder->set_name(codec.payload_name);
+ encoder->set_payload_type(codec.payload_type);
+
+ if (event.config().codecs.size() > 1) {
+ RTC_LOG(LS_WARNING)
+ << "LogVideoSendStreamConfig currently only supports one "
+ "codec. Logging codec :"
+ << codec.payload_name;
+ break;
+ }
+ }
+
+ return Serialize(&rtclog_event);
+}
+
+std::string RtcEventLogEncoderLegacy::EncodeRtcpPacket(
+ int64_t timestamp_us,
+ const rtc::Buffer& packet,
+ bool is_incoming) {
+ rtclog::Event rtclog_event;
+ rtclog_event.set_timestamp_us(timestamp_us);
+ rtclog_event.set_type(rtclog::Event::RTCP_EVENT);
+ rtclog_event.mutable_rtcp_packet()->set_incoming(is_incoming);
+
+ rtcp::CommonHeader header;
+ const uint8_t* block_begin = packet.data();
+ const uint8_t* packet_end = packet.data() + packet.size();
+ std::vector<uint8_t> buffer(packet.size());
+ uint32_t buffer_length = 0;
+ while (block_begin < packet_end) {
+ if (!header.Parse(block_begin, packet_end - block_begin)) {
+ break; // Incorrect message header.
+ }
+ const uint8_t* next_block = header.NextPacket();
+ uint32_t block_size = next_block - block_begin;
+ switch (header.type()) {
+ case rtcp::Bye::kPacketType:
+ case rtcp::ExtendedReports::kPacketType:
+ case rtcp::Psfb::kPacketType:
+ case rtcp::ReceiverReport::kPacketType:
+ case rtcp::Rtpfb::kPacketType:
+ case rtcp::SenderReport::kPacketType:
+ // We log sender reports, receiver reports, bye messages, third-party
+ // loss reports, payload-specific feedback and extended reports.
+ memcpy(buffer.data() + buffer_length, block_begin, block_size);
+ buffer_length += block_size;
+ break;
+ case rtcp::App::kPacketType:
+ case rtcp::Sdes::kPacketType:
+ default:
+ // We don't log sender descriptions, application defined messages
+ // or message blocks of unknown type.
+ break;
+ }
+
+ block_begin += block_size;
+ }
+ rtclog_event.mutable_rtcp_packet()->set_packet_data(buffer.data(),
+ buffer_length);
+
+ return Serialize(&rtclog_event);
+}
+
+std::string RtcEventLogEncoderLegacy::EncodeRtpPacket(
+ int64_t timestamp_us,
+ rtc::ArrayView<const uint8_t> header,
+ size_t packet_length,
+ int probe_cluster_id,
+ bool is_incoming) {
+ rtclog::Event rtclog_event;
+ rtclog_event.set_timestamp_us(timestamp_us);
+ rtclog_event.set_type(rtclog::Event::RTP_EVENT);
+
+ rtclog_event.mutable_rtp_packet()->set_incoming(is_incoming);
+ rtclog_event.mutable_rtp_packet()->set_packet_length(packet_length);
+ rtclog_event.mutable_rtp_packet()->set_header(header.data(), header.size());
+ if (probe_cluster_id != PacedPacketInfo::kNotAProbe) {
+ RTC_DCHECK(!is_incoming);
+ rtclog_event.mutable_rtp_packet()->set_probe_cluster_id(probe_cluster_id);
+ }
+
+ return Serialize(&rtclog_event);
+}
+
+std::string RtcEventLogEncoderLegacy::Serialize(rtclog::Event* event) {
+ // Even though we're only serializing a single event during this call, what
+ // we intend to get is a list of events, with a tag and length preceding
+ // each actual event. To produce that, we serialize a list of a single event.
+ // If we later concatenate several results from this function, the result will
+ // be a proper concatenation of all those events.
+
+ rtclog::EventStream event_stream;
+ event_stream.add_stream();
+
+ // As a tweak, we swap the new event into the event-stream, write that to
+ // file, then swap back. This saves on some copying, while making sure that
+ // the caller wouldn't be surprised by Serialize() modifying the object.
+ rtclog::Event* output_event = event_stream.mutable_stream(0);
+ output_event->Swap(event);
+
+ std::string output_string = event_stream.SerializeAsString();
+ RTC_DCHECK(!output_string.empty());
+
+ // When the function returns, the original Event will be unchanged.
+ output_event->Swap(event);
+
+ return output_string;
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder_legacy.h b/third_party/libwebrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder_legacy.h
new file mode 100644
index 0000000000..33c530789b
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder_legacy.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2017 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_ENCODER_RTC_EVENT_LOG_ENCODER_LEGACY_H_
+#define LOGGING_RTC_EVENT_LOG_ENCODER_RTC_EVENT_LOG_ENCODER_LEGACY_H_
+
+#include <deque>
+#include <memory>
+#include <string>
+
+#include "api/array_view.h"
+#include "logging/rtc_event_log/encoder/rtc_event_log_encoder.h"
+#include "rtc_base/buffer.h"
+
+namespace webrtc {
+
+namespace rtclog {
+class Event; // Auto-generated from protobuf.
+} // namespace rtclog
+
+class RtcEventAlrState;
+class RtcEventAudioNetworkAdaptation;
+class RtcEventAudioPlayout;
+class RtcEventAudioReceiveStreamConfig;
+class RtcEventAudioSendStreamConfig;
+class RtcEventBweUpdateDelayBased;
+class RtcEventBweUpdateLossBased;
+class RtcEventIceCandidatePairConfig;
+class RtcEventIceCandidatePair;
+class RtcEventLoggingStarted;
+class RtcEventLoggingStopped;
+class RtcEventProbeClusterCreated;
+class RtcEventProbeResultFailure;
+class RtcEventProbeResultSuccess;
+class RtcEventRemoteEstimate;
+class RtcEventRtcpPacketIncoming;
+class RtcEventRtcpPacketOutgoing;
+class RtcEventRtpPacketIncoming;
+class RtcEventRtpPacketOutgoing;
+class RtcEventVideoReceiveStreamConfig;
+class RtcEventVideoSendStreamConfig;
+class RtpPacket;
+
+class RtcEventLogEncoderLegacy final : public RtcEventLogEncoder {
+ public:
+ ~RtcEventLogEncoderLegacy() override = default;
+
+ std::string EncodeLogStart(int64_t timestamp_us,
+ int64_t utc_time_us) override;
+ std::string EncodeLogEnd(int64_t timestamp_us) override;
+
+ std::string EncodeBatch(
+ std::deque<std::unique_ptr<RtcEvent>>::const_iterator begin,
+ std::deque<std::unique_ptr<RtcEvent>>::const_iterator end) override;
+
+ private:
+ std::string Encode(const RtcEvent& event);
+ // Encoding entry-point for the various RtcEvent subclasses.
+ std::string EncodeAlrState(const RtcEventAlrState& event);
+ std::string EncodeAudioNetworkAdaptation(
+ const RtcEventAudioNetworkAdaptation& event);
+ std::string EncodeAudioPlayout(const RtcEventAudioPlayout& event);
+ std::string EncodeAudioReceiveStreamConfig(
+ const RtcEventAudioReceiveStreamConfig& event);
+ std::string EncodeAudioSendStreamConfig(
+ const RtcEventAudioSendStreamConfig& event);
+ std::string EncodeBweUpdateDelayBased(
+ const RtcEventBweUpdateDelayBased& event);
+ std::string EncodeBweUpdateLossBased(const RtcEventBweUpdateLossBased& event);
+ std::string EncodeIceCandidatePairConfig(
+ const RtcEventIceCandidatePairConfig& event);
+ std::string EncodeIceCandidatePairEvent(
+ const RtcEventIceCandidatePair& event);
+ std::string EncodeProbeClusterCreated(
+ const RtcEventProbeClusterCreated& event);
+ std::string EncodeProbeResultFailure(const RtcEventProbeResultFailure& event);
+ std::string EncodeProbeResultSuccess(const RtcEventProbeResultSuccess&);
+ std::string EncodeRemoteEstimate(const RtcEventRemoteEstimate& event);
+ std::string EncodeRtcpPacketIncoming(const RtcEventRtcpPacketIncoming& event);
+ std::string EncodeRtcpPacketOutgoing(const RtcEventRtcpPacketOutgoing& event);
+ std::string EncodeRtpPacketIncoming(const RtcEventRtpPacketIncoming& event);
+ std::string EncodeRtpPacketOutgoing(const RtcEventRtpPacketOutgoing& event);
+ std::string EncodeVideoReceiveStreamConfig(
+ const RtcEventVideoReceiveStreamConfig& event);
+ std::string EncodeVideoSendStreamConfig(
+ const RtcEventVideoSendStreamConfig& event);
+
+ // RTCP/RTP are handled similarly for incoming/outgoing.
+ std::string EncodeRtcpPacket(int64_t timestamp_us,
+ const rtc::Buffer& packet,
+ bool is_incoming);
+ std::string EncodeRtpPacket(int64_t timestamp_us,
+ rtc::ArrayView<const uint8_t> header,
+ size_t packet_length,
+ int probe_cluster_id,
+ bool is_incoming);
+
+ std::string Serialize(rtclog::Event* event);
+};
+
+} // namespace webrtc
+
+#endif // LOGGING_RTC_EVENT_LOG_ENCODER_RTC_EVENT_LOG_ENCODER_LEGACY_H_
diff --git a/third_party/libwebrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder_new_format.cc b/third_party/libwebrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder_new_format.cc
new file mode 100644
index 0000000000..2e02f68213
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder_new_format.cc
@@ -0,0 +1,1941 @@
+/*
+ * Copyright (c) 2017 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/encoder/rtc_event_log_encoder_new_format.h"
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "api/network_state_predictor.h"
+#include "logging/rtc_event_log/encoder/blob_encoding.h"
+#include "logging/rtc_event_log/encoder/delta_encoding.h"
+#include "logging/rtc_event_log/encoder/rtc_event_log_encoder_common.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"
+#include "logging/rtc_event_log/events/rtc_event_audio_receive_stream_config.h"
+#include "logging/rtc_event_log/events/rtc_event_audio_send_stream_config.h"
+#include "logging/rtc_event_log/events/rtc_event_bwe_update_delay_based.h"
+#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_frame_decoded.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_neteq_set_minimum_delay.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"
+#include "logging/rtc_event_log/events/rtc_event_remote_estimate.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"
+#include "logging/rtc_event_log/events/rtc_event_rtp_packet_outgoing.h"
+#include "logging/rtc_event_log/events/rtc_event_video_receive_stream_config.h"
+#include "logging/rtc_event_log/events/rtc_event_video_send_stream_config.h"
+#include "logging/rtc_event_log/rtc_stream_config.h"
+#include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor_config.h"
+#include "modules/rtp_rtcp/include/rtp_cvo.h"
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/app.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/bye.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/extended_reports.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/psfb.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/receiver_report.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/rtpfb.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/sdes.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/sender_report.h"
+#include "modules/rtp_rtcp/source/rtp_header_extensions.h"
+#include "modules/rtp_rtcp/source/rtp_packet.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/ignore_wundef.h"
+#include "rtc_base/logging.h"
+#include "system_wrappers/include/field_trial.h"
+
+// *.pb.h files are generated at build-time by the protobuf compiler.
+RTC_PUSH_IGNORING_WUNDEF()
+#ifdef WEBRTC_ANDROID_PLATFORM_BUILD
+#include "external/webrtc/webrtc/logging/rtc_event_log/rtc_event_log2.pb.h"
+#else
+#include "logging/rtc_event_log/rtc_event_log2.pb.h"
+#endif
+RTC_POP_IGNORING_WUNDEF()
+
+using webrtc_event_logging::ToUnsigned;
+
+namespace webrtc {
+
+namespace {
+rtclog2::DelayBasedBweUpdates::DetectorState ConvertToProtoFormat(
+ BandwidthUsage state) {
+ switch (state) {
+ case BandwidthUsage::kBwNormal:
+ return rtclog2::DelayBasedBweUpdates::BWE_NORMAL;
+ case BandwidthUsage::kBwUnderusing:
+ return rtclog2::DelayBasedBweUpdates::BWE_UNDERUSING;
+ case BandwidthUsage::kBwOverusing:
+ return rtclog2::DelayBasedBweUpdates::BWE_OVERUSING;
+ case BandwidthUsage::kLast:
+ RTC_DCHECK_NOTREACHED();
+ }
+ RTC_DCHECK_NOTREACHED();
+ return rtclog2::DelayBasedBweUpdates::BWE_UNKNOWN_STATE;
+}
+
+rtclog2::FrameDecodedEvents::Codec ConvertToProtoFormat(VideoCodecType codec) {
+ switch (codec) {
+ case VideoCodecType::kVideoCodecGeneric:
+ return rtclog2::FrameDecodedEvents::CODEC_GENERIC;
+ case VideoCodecType::kVideoCodecVP8:
+ return rtclog2::FrameDecodedEvents::CODEC_VP8;
+ case VideoCodecType::kVideoCodecVP9:
+ return rtclog2::FrameDecodedEvents::CODEC_VP9;
+ case VideoCodecType::kVideoCodecAV1:
+ return rtclog2::FrameDecodedEvents::CODEC_AV1;
+ case VideoCodecType::kVideoCodecH264:
+ return rtclog2::FrameDecodedEvents::CODEC_H264;
+ case VideoCodecType::kVideoCodecMultiplex:
+ // This codec type is afaik not used.
+ return rtclog2::FrameDecodedEvents::CODEC_UNKNOWN;
+ }
+ RTC_DCHECK_NOTREACHED();
+ return rtclog2::FrameDecodedEvents::CODEC_UNKNOWN;
+}
+
+rtclog2::BweProbeResultFailure::FailureReason ConvertToProtoFormat(
+ ProbeFailureReason failure_reason) {
+ switch (failure_reason) {
+ case ProbeFailureReason::kInvalidSendReceiveInterval:
+ return rtclog2::BweProbeResultFailure::INVALID_SEND_RECEIVE_INTERVAL;
+ case ProbeFailureReason::kInvalidSendReceiveRatio:
+ return rtclog2::BweProbeResultFailure::INVALID_SEND_RECEIVE_RATIO;
+ case ProbeFailureReason::kTimeout:
+ return rtclog2::BweProbeResultFailure::TIMEOUT;
+ case ProbeFailureReason::kLast:
+ RTC_DCHECK_NOTREACHED();
+ }
+ RTC_DCHECK_NOTREACHED();
+ return rtclog2::BweProbeResultFailure::UNKNOWN;
+}
+
+// Returns true if there are recognized extensions that we should log
+// and false if there are no extensions or all extensions are types we don't
+// log. The protobuf representation of the header configs is written to
+// `proto_config`.
+bool ConvertToProtoFormat(const std::vector<RtpExtension>& extensions,
+ rtclog2::RtpHeaderExtensionConfig* proto_config) {
+ size_t unknown_extensions = 0;
+ for (auto& extension : extensions) {
+ if (extension.uri == RtpExtension::kAudioLevelUri) {
+ proto_config->set_audio_level_id(extension.id);
+ } else if (extension.uri == RtpExtension::kTimestampOffsetUri) {
+ proto_config->set_transmission_time_offset_id(extension.id);
+ } else if (extension.uri == RtpExtension::kAbsSendTimeUri) {
+ proto_config->set_absolute_send_time_id(extension.id);
+ } else if (extension.uri == RtpExtension::kTransportSequenceNumberUri) {
+ proto_config->set_transport_sequence_number_id(extension.id);
+ } else if (extension.uri == RtpExtension::kVideoRotationUri) {
+ proto_config->set_video_rotation_id(extension.id);
+ } else {
+ ++unknown_extensions;
+ }
+ }
+ return unknown_extensions < extensions.size();
+}
+
+rtclog2::DtlsTransportStateEvent::DtlsTransportState ConvertToProtoFormat(
+ webrtc::DtlsTransportState state) {
+ switch (state) {
+ case webrtc::DtlsTransportState::kNew:
+ return rtclog2::DtlsTransportStateEvent::DTLS_TRANSPORT_NEW;
+ case webrtc::DtlsTransportState::kConnecting:
+ return rtclog2::DtlsTransportStateEvent::DTLS_TRANSPORT_CONNECTING;
+ case webrtc::DtlsTransportState::kConnected:
+ return rtclog2::DtlsTransportStateEvent::DTLS_TRANSPORT_CONNECTED;
+ case webrtc::DtlsTransportState::kClosed:
+ return rtclog2::DtlsTransportStateEvent::DTLS_TRANSPORT_CLOSED;
+ case webrtc::DtlsTransportState::kFailed:
+ return rtclog2::DtlsTransportStateEvent::DTLS_TRANSPORT_FAILED;
+ case webrtc::DtlsTransportState::kNumValues:
+ RTC_DCHECK_NOTREACHED();
+ }
+ RTC_DCHECK_NOTREACHED();
+ return rtclog2::DtlsTransportStateEvent::UNKNOWN_DTLS_TRANSPORT_STATE;
+}
+
+rtclog2::IceCandidatePairConfig::IceCandidatePairConfigType
+ConvertToProtoFormat(IceCandidatePairConfigType type) {
+ switch (type) {
+ case IceCandidatePairConfigType::kAdded:
+ return rtclog2::IceCandidatePairConfig::ADDED;
+ case IceCandidatePairConfigType::kUpdated:
+ return rtclog2::IceCandidatePairConfig::UPDATED;
+ case IceCandidatePairConfigType::kDestroyed:
+ return rtclog2::IceCandidatePairConfig::DESTROYED;
+ case IceCandidatePairConfigType::kSelected:
+ return rtclog2::IceCandidatePairConfig::SELECTED;
+ case IceCandidatePairConfigType::kNumValues:
+ RTC_DCHECK_NOTREACHED();
+ }
+ RTC_DCHECK_NOTREACHED();
+ return rtclog2::IceCandidatePairConfig::UNKNOWN_CONFIG_TYPE;
+}
+
+rtclog2::IceCandidatePairConfig::IceCandidateType ConvertToProtoFormat(
+ IceCandidateType type) {
+ switch (type) {
+ case IceCandidateType::kUnknown:
+ return rtclog2::IceCandidatePairConfig::UNKNOWN_CANDIDATE_TYPE;
+ case IceCandidateType::kLocal:
+ return rtclog2::IceCandidatePairConfig::LOCAL;
+ case IceCandidateType::kStun:
+ return rtclog2::IceCandidatePairConfig::STUN;
+ case IceCandidateType::kPrflx:
+ return rtclog2::IceCandidatePairConfig::PRFLX;
+ case IceCandidateType::kRelay:
+ return rtclog2::IceCandidatePairConfig::RELAY;
+ case IceCandidateType::kNumValues:
+ RTC_DCHECK_NOTREACHED();
+ }
+ RTC_DCHECK_NOTREACHED();
+ return rtclog2::IceCandidatePairConfig::UNKNOWN_CANDIDATE_TYPE;
+}
+
+rtclog2::IceCandidatePairConfig::Protocol ConvertToProtoFormat(
+ IceCandidatePairProtocol protocol) {
+ switch (protocol) {
+ case IceCandidatePairProtocol::kUnknown:
+ return rtclog2::IceCandidatePairConfig::UNKNOWN_PROTOCOL;
+ case IceCandidatePairProtocol::kUdp:
+ return rtclog2::IceCandidatePairConfig::UDP;
+ case IceCandidatePairProtocol::kTcp:
+ return rtclog2::IceCandidatePairConfig::TCP;
+ case IceCandidatePairProtocol::kSsltcp:
+ return rtclog2::IceCandidatePairConfig::SSLTCP;
+ case IceCandidatePairProtocol::kTls:
+ return rtclog2::IceCandidatePairConfig::TLS;
+ case IceCandidatePairProtocol::kNumValues:
+ RTC_DCHECK_NOTREACHED();
+ }
+ RTC_DCHECK_NOTREACHED();
+ return rtclog2::IceCandidatePairConfig::UNKNOWN_PROTOCOL;
+}
+
+rtclog2::IceCandidatePairConfig::AddressFamily ConvertToProtoFormat(
+ IceCandidatePairAddressFamily address_family) {
+ switch (address_family) {
+ case IceCandidatePairAddressFamily::kUnknown:
+ return rtclog2::IceCandidatePairConfig::UNKNOWN_ADDRESS_FAMILY;
+ case IceCandidatePairAddressFamily::kIpv4:
+ return rtclog2::IceCandidatePairConfig::IPV4;
+ case IceCandidatePairAddressFamily::kIpv6:
+ return rtclog2::IceCandidatePairConfig::IPV6;
+ case IceCandidatePairAddressFamily::kNumValues:
+ RTC_DCHECK_NOTREACHED();
+ }
+ RTC_DCHECK_NOTREACHED();
+ return rtclog2::IceCandidatePairConfig::UNKNOWN_ADDRESS_FAMILY;
+}
+
+rtclog2::IceCandidatePairConfig::NetworkType ConvertToProtoFormat(
+ IceCandidateNetworkType network_type) {
+ switch (network_type) {
+ case IceCandidateNetworkType::kUnknown:
+ return rtclog2::IceCandidatePairConfig::UNKNOWN_NETWORK_TYPE;
+ case IceCandidateNetworkType::kEthernet:
+ return rtclog2::IceCandidatePairConfig::ETHERNET;
+ case IceCandidateNetworkType::kLoopback:
+ return rtclog2::IceCandidatePairConfig::LOOPBACK;
+ case IceCandidateNetworkType::kWifi:
+ return rtclog2::IceCandidatePairConfig::WIFI;
+ case IceCandidateNetworkType::kVpn:
+ return rtclog2::IceCandidatePairConfig::VPN;
+ case IceCandidateNetworkType::kCellular:
+ return rtclog2::IceCandidatePairConfig::CELLULAR;
+ case IceCandidateNetworkType::kNumValues:
+ RTC_DCHECK_NOTREACHED();
+ }
+ RTC_DCHECK_NOTREACHED();
+ return rtclog2::IceCandidatePairConfig::UNKNOWN_NETWORK_TYPE;
+}
+
+rtclog2::IceCandidatePairEvent::IceCandidatePairEventType ConvertToProtoFormat(
+ IceCandidatePairEventType type) {
+ switch (type) {
+ case IceCandidatePairEventType::kCheckSent:
+ return rtclog2::IceCandidatePairEvent::CHECK_SENT;
+ case IceCandidatePairEventType::kCheckReceived:
+ return rtclog2::IceCandidatePairEvent::CHECK_RECEIVED;
+ case IceCandidatePairEventType::kCheckResponseSent:
+ return rtclog2::IceCandidatePairEvent::CHECK_RESPONSE_SENT;
+ case IceCandidatePairEventType::kCheckResponseReceived:
+ return rtclog2::IceCandidatePairEvent::CHECK_RESPONSE_RECEIVED;
+ case IceCandidatePairEventType::kNumValues:
+ RTC_DCHECK_NOTREACHED();
+ }
+ RTC_DCHECK_NOTREACHED();
+ return rtclog2::IceCandidatePairEvent::UNKNOWN_CHECK_TYPE;
+}
+
+// Copies all RTCP blocks except APP, SDES and unknown from `packet` to
+// `buffer`. `buffer` must have space for at least `packet.size()` bytes.
+size_t RemoveNonAllowlistedRtcpBlocks(const rtc::Buffer& packet,
+ uint8_t* buffer) {
+ RTC_DCHECK(buffer != nullptr);
+ rtcp::CommonHeader header;
+ const uint8_t* block_begin = packet.data();
+ const uint8_t* packet_end = packet.data() + packet.size();
+ size_t buffer_length = 0;
+ while (block_begin < packet_end) {
+ if (!header.Parse(block_begin, packet_end - block_begin)) {
+ break; // Incorrect message header.
+ }
+ const uint8_t* next_block = header.NextPacket();
+ RTC_DCHECK_GT(next_block, block_begin);
+ RTC_DCHECK_LE(next_block, packet_end);
+ size_t block_size = next_block - block_begin;
+ switch (header.type()) {
+ case rtcp::Bye::kPacketType:
+ case rtcp::ExtendedReports::kPacketType:
+ case rtcp::Psfb::kPacketType:
+ case rtcp::ReceiverReport::kPacketType:
+ case rtcp::Rtpfb::kPacketType:
+ case rtcp::SenderReport::kPacketType:
+ // We log sender reports, receiver reports, bye messages, third-party
+ // loss reports, payload-specific feedback and extended reports.
+ // TODO(terelius): As an optimization, don't copy anything if all blocks
+ // in the packet are allowlisted types.
+ memcpy(buffer + buffer_length, block_begin, block_size);
+ buffer_length += block_size;
+ break;
+ case rtcp::App::kPacketType:
+ case rtcp::Sdes::kPacketType:
+ default:
+ // We don't log sender descriptions, application defined messages
+ // or message blocks of unknown type.
+ break;
+ }
+
+ block_begin += block_size;
+ }
+ return buffer_length;
+}
+
+template <typename EventType, typename ProtoType>
+void EncodeRtcpPacket(rtc::ArrayView<const EventType*> batch,
+ ProtoType* proto_batch) {
+ if (batch.empty()) {
+ return;
+ }
+
+ // Base event
+ const EventType* const base_event = batch[0];
+ proto_batch->set_timestamp_ms(base_event->timestamp_ms());
+ {
+ std::vector<uint8_t> buffer(base_event->packet().size());
+ size_t buffer_length =
+ RemoveNonAllowlistedRtcpBlocks(base_event->packet(), buffer.data());
+ proto_batch->set_raw_packet(buffer.data(), buffer_length);
+ }
+
+ if (batch.size() == 1) {
+ return;
+ }
+
+ // 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;
+
+ // timestamp_ms
+ for (size_t i = 0; i < values.size(); ++i) {
+ const EventType* 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);
+ }
+
+ // raw_packet
+ std::vector<std::string> scrubed_packets(batch.size() - 1);
+ for (size_t i = 0; i < scrubed_packets.size(); ++i) {
+ const EventType* event = batch[i + 1];
+ scrubed_packets[i].resize(event->packet().size());
+ static_assert(sizeof(std::string::value_type) == sizeof(uint8_t), "");
+ const size_t buffer_length = RemoveNonAllowlistedRtcpBlocks(
+ event->packet(), reinterpret_cast<uint8_t*>(&scrubed_packets[i][0]));
+ if (buffer_length < event->packet().size()) {
+ scrubed_packets[i].resize(buffer_length);
+ }
+ }
+ proto_batch->set_raw_packet_blobs(EncodeBlobs(scrubed_packets));
+}
+
+template <typename EventType, typename ProtoType>
+void EncodeRtpPacket(const std::vector<const EventType*>& batch,
+ ProtoType* proto_batch) {
+ if (batch.empty()) {
+ return;
+ }
+
+ // Base event
+ const EventType* const base_event = batch[0];
+ proto_batch->set_timestamp_ms(base_event->timestamp_ms());
+ proto_batch->set_marker(base_event->Marker());
+ // TODO(terelius): Is payload type needed?
+ proto_batch->set_payload_type(base_event->PayloadType());
+ proto_batch->set_sequence_number(base_event->SequenceNumber());
+ proto_batch->set_rtp_timestamp(base_event->Timestamp());
+ proto_batch->set_ssrc(base_event->Ssrc());
+ proto_batch->set_payload_size(base_event->payload_length());
+ proto_batch->set_header_size(base_event->header_length());
+ proto_batch->set_padding_size(base_event->padding_length());
+
+ // Add header extensions (base event).
+ absl::optional<uint64_t> base_transport_sequence_number;
+ {
+ uint16_t seqnum;
+ if (base_event->template GetExtension<TransportSequenceNumber>(&seqnum)) {
+ proto_batch->set_transport_sequence_number(seqnum);
+ base_transport_sequence_number = seqnum;
+ }
+ }
+
+ absl::optional<uint64_t> unsigned_base_transmission_time_offset;
+ {
+ int32_t offset;
+ if (base_event->template GetExtension<TransmissionOffset>(&offset)) {
+ proto_batch->set_transmission_time_offset(offset);
+ unsigned_base_transmission_time_offset = ToUnsigned(offset);
+ }
+ }
+
+ absl::optional<uint64_t> base_absolute_send_time;
+ {
+ uint32_t sendtime;
+ if (base_event->template GetExtension<AbsoluteSendTime>(&sendtime)) {
+ proto_batch->set_absolute_send_time(sendtime);
+ base_absolute_send_time = sendtime;
+ }
+ }
+
+ absl::optional<uint64_t> base_video_rotation;
+ {
+ VideoRotation video_rotation;
+ if (base_event->template GetExtension<VideoOrientation>(&video_rotation)) {
+ proto_batch->set_video_rotation(
+ ConvertVideoRotationToCVOByte(video_rotation));
+ base_video_rotation = ConvertVideoRotationToCVOByte(video_rotation);
+ }
+ }
+
+ absl::optional<uint64_t> base_audio_level;
+ absl::optional<uint64_t> base_voice_activity;
+ {
+ bool voice_activity;
+ uint8_t audio_level;
+ if (base_event->template GetExtension<AudioLevel>(&voice_activity,
+ &audio_level)) {
+ RTC_DCHECK_LE(audio_level, 0x7Fu);
+ base_audio_level = audio_level;
+ proto_batch->set_audio_level(audio_level);
+
+ base_voice_activity = voice_activity;
+ proto_batch->set_voice_activity(voice_activity);
+ }
+ }
+
+ if (batch.size() == 1) {
+ return;
+ }
+
+ // 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;
+
+ // timestamp_ms (event)
+ for (size_t i = 0; i < values.size(); ++i) {
+ const EventType* 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);
+ }
+
+ // marker (RTP base)
+ for (size_t i = 0; i < values.size(); ++i) {
+ const EventType* event = batch[i + 1];
+ values[i] = event->Marker();
+ }
+ encoded_deltas = EncodeDeltas(base_event->Marker(), values);
+ if (!encoded_deltas.empty()) {
+ proto_batch->set_marker_deltas(encoded_deltas);
+ }
+
+ // payload_type (RTP base)
+ for (size_t i = 0; i < values.size(); ++i) {
+ const EventType* event = batch[i + 1];
+ values[i] = event->PayloadType();
+ }
+ encoded_deltas = EncodeDeltas(base_event->PayloadType(), values);
+ if (!encoded_deltas.empty()) {
+ proto_batch->set_payload_type_deltas(encoded_deltas);
+ }
+
+ // sequence_number (RTP base)
+ for (size_t i = 0; i < values.size(); ++i) {
+ const EventType* event = batch[i + 1];
+ values[i] = event->SequenceNumber();
+ }
+ encoded_deltas = EncodeDeltas(base_event->SequenceNumber(), values);
+ if (!encoded_deltas.empty()) {
+ proto_batch->set_sequence_number_deltas(encoded_deltas);
+ }
+
+ // rtp_timestamp (RTP base)
+ for (size_t i = 0; i < values.size(); ++i) {
+ const EventType* event = batch[i + 1];
+ values[i] = event->Timestamp();
+ }
+ encoded_deltas = EncodeDeltas(base_event->Timestamp(), values);
+ if (!encoded_deltas.empty()) {
+ proto_batch->set_rtp_timestamp_deltas(encoded_deltas);
+ }
+
+ // ssrc (RTP base)
+ for (size_t i = 0; i < values.size(); ++i) {
+ const EventType* event = batch[i + 1];
+ values[i] = event->Ssrc();
+ }
+ encoded_deltas = EncodeDeltas(base_event->Ssrc(), values);
+ if (!encoded_deltas.empty()) {
+ proto_batch->set_ssrc_deltas(encoded_deltas);
+ }
+
+ // payload_size (RTP base)
+ for (size_t i = 0; i < values.size(); ++i) {
+ const EventType* 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_size_deltas(encoded_deltas);
+ }
+
+ // header_size (RTP base)
+ for (size_t i = 0; i < values.size(); ++i) {
+ const EventType* event = batch[i + 1];
+ values[i] = event->header_length();
+ }
+ encoded_deltas = EncodeDeltas(base_event->header_length(), values);
+ if (!encoded_deltas.empty()) {
+ proto_batch->set_header_size_deltas(encoded_deltas);
+ }
+
+ // padding_size (RTP base)
+ for (size_t i = 0; i < values.size(); ++i) {
+ const EventType* 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_size_deltas(encoded_deltas);
+ }
+
+ // transport_sequence_number (RTP extension)
+ for (size_t i = 0; i < values.size(); ++i) {
+ const EventType* event = batch[i + 1];
+ uint16_t seqnum;
+ if (event->template GetExtension<TransportSequenceNumber>(&seqnum)) {
+ values[i] = seqnum;
+ } else {
+ values[i].reset();
+ }
+ }
+ encoded_deltas = EncodeDeltas(base_transport_sequence_number, values);
+ if (!encoded_deltas.empty()) {
+ proto_batch->set_transport_sequence_number_deltas(encoded_deltas);
+ }
+
+ // transmission_time_offset (RTP extension)
+ for (size_t i = 0; i < values.size(); ++i) {
+ const EventType* event = batch[i + 1];
+ int32_t offset;
+ if (event->template GetExtension<TransmissionOffset>(&offset)) {
+ values[i] = ToUnsigned(offset);
+ } else {
+ values[i].reset();
+ }
+ }
+ encoded_deltas = EncodeDeltas(unsigned_base_transmission_time_offset, values);
+ if (!encoded_deltas.empty()) {
+ proto_batch->set_transmission_time_offset_deltas(encoded_deltas);
+ }
+
+ // absolute_send_time (RTP extension)
+ for (size_t i = 0; i < values.size(); ++i) {
+ const EventType* event = batch[i + 1];
+ uint32_t sendtime;
+ if (event->template GetExtension<AbsoluteSendTime>(&sendtime)) {
+ values[i] = sendtime;
+ } else {
+ values[i].reset();
+ }
+ }
+ encoded_deltas = EncodeDeltas(base_absolute_send_time, values);
+ if (!encoded_deltas.empty()) {
+ proto_batch->set_absolute_send_time_deltas(encoded_deltas);
+ }
+
+ // video_rotation (RTP extension)
+ for (size_t i = 0; i < values.size(); ++i) {
+ const EventType* event = batch[i + 1];
+ VideoRotation video_rotation;
+ if (event->template GetExtension<VideoOrientation>(&video_rotation)) {
+ values[i] = ConvertVideoRotationToCVOByte(video_rotation);
+ } else {
+ values[i].reset();
+ }
+ }
+ encoded_deltas = EncodeDeltas(base_video_rotation, values);
+ if (!encoded_deltas.empty()) {
+ proto_batch->set_video_rotation_deltas(encoded_deltas);
+ }
+
+ // audio_level (RTP extension)
+ for (size_t i = 0; i < values.size(); ++i) {
+ const EventType* event = batch[i + 1];
+ bool voice_activity;
+ uint8_t audio_level;
+ if (event->template GetExtension<AudioLevel>(&voice_activity,
+ &audio_level)) {
+ RTC_DCHECK_LE(audio_level, 0x7Fu);
+ values[i] = audio_level;
+ } else {
+ values[i].reset();
+ }
+ }
+ encoded_deltas = EncodeDeltas(base_audio_level, values);
+ if (!encoded_deltas.empty()) {
+ proto_batch->set_audio_level_deltas(encoded_deltas);
+ }
+
+ // voice_activity (RTP extension)
+ for (size_t i = 0; i < values.size(); ++i) {
+ const EventType* event = batch[i + 1];
+ bool voice_activity;
+ uint8_t audio_level;
+ if (event->template GetExtension<AudioLevel>(&voice_activity,
+ &audio_level)) {
+ RTC_DCHECK_LE(audio_level, 0x7Fu);
+ values[i] = voice_activity;
+ } else {
+ values[i].reset();
+ }
+ }
+ encoded_deltas = EncodeDeltas(base_voice_activity, values);
+ if (!encoded_deltas.empty()) {
+ proto_batch->set_voice_activity_deltas(encoded_deltas);
+ }
+}
+} // namespace
+
+RtcEventLogEncoderNewFormat::RtcEventLogEncoderNewFormat() {
+ encode_neteq_set_minimum_delay_kill_switch_ = false;
+ if (webrtc::field_trial::IsEnabled(
+ "WebRTC-RtcEventLogEncodeNetEqSetMinimumDelayKillSwitch")) {
+ encode_neteq_set_minimum_delay_kill_switch_ = true;
+ }
+}
+
+std::string RtcEventLogEncoderNewFormat::EncodeLogStart(int64_t timestamp_us,
+ int64_t utc_time_us) {
+ rtclog2::EventStream event_stream;
+ rtclog2::BeginLogEvent* proto_batch = event_stream.add_begin_log_events();
+ proto_batch->set_timestamp_ms(timestamp_us / 1000);
+ proto_batch->set_version(2);
+ proto_batch->set_utc_time_ms(utc_time_us / 1000);
+ return event_stream.SerializeAsString();
+}
+
+std::string RtcEventLogEncoderNewFormat::EncodeLogEnd(int64_t timestamp_us) {
+ rtclog2::EventStream event_stream;
+ rtclog2::EndLogEvent* proto_batch = event_stream.add_end_log_events();
+ proto_batch->set_timestamp_ms(timestamp_us / 1000);
+ return event_stream.SerializeAsString();
+}
+
+std::string RtcEventLogEncoderNewFormat::EncodeBatch(
+ std::deque<std::unique_ptr<RtcEvent>>::const_iterator begin,
+ std::deque<std::unique_ptr<RtcEvent>>::const_iterator end) {
+ rtclog2::EventStream event_stream;
+ std::string encoded_output;
+
+ {
+ std::vector<const RtcEventAlrState*> alr_state_events;
+ std::vector<const RtcEventAudioNetworkAdaptation*>
+ audio_network_adaptation_events;
+ std::vector<const RtcEventAudioPlayout*> audio_playout_events;
+ std::vector<const RtcEventNetEqSetMinimumDelay*>
+ neteq_set_minimum_delay_events;
+ std::vector<const RtcEventAudioReceiveStreamConfig*>
+ audio_recv_stream_configs;
+ std::vector<const RtcEventAudioSendStreamConfig*> audio_send_stream_configs;
+ std::vector<const RtcEventBweUpdateDelayBased*> bwe_delay_based_updates;
+ std::vector<const RtcEventBweUpdateLossBased*> bwe_loss_based_updates;
+ std::vector<const RtcEventDtlsTransportState*> dtls_transport_states;
+ std::vector<const RtcEventDtlsWritableState*> dtls_writable_states;
+ std::map<uint32_t /* SSRC */, std::vector<const RtcEventFrameDecoded*>>
+ frames_decoded;
+ 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 RtcEventRemoteEstimate*> remote_estimate_events;
+ std::vector<const RtcEventRtcpPacketIncoming*> incoming_rtcp_packets;
+ std::vector<const RtcEventRtcpPacketOutgoing*> outgoing_rtcp_packets;
+ std::map<uint32_t /* SSRC */, std::vector<const RtcEventRtpPacketIncoming*>>
+ incoming_rtp_packets;
+ std::map<uint32_t /* SSRC */, std::vector<const RtcEventRtpPacketOutgoing*>>
+ outgoing_rtp_packets;
+ std::vector<const RtcEventVideoReceiveStreamConfig*>
+ video_recv_stream_configs;
+ std::vector<const RtcEventVideoSendStreamConfig*> video_send_stream_configs;
+
+ for (auto it = begin; it != end; ++it) {
+ switch ((*it)->GetType()) {
+ case RtcEvent::Type::AlrStateEvent: {
+ auto* rtc_event =
+ static_cast<const RtcEventAlrState* const>(it->get());
+ alr_state_events.push_back(rtc_event);
+ break;
+ }
+ case RtcEvent::Type::AudioNetworkAdaptation: {
+ auto* rtc_event =
+ static_cast<const RtcEventAudioNetworkAdaptation* const>(
+ it->get());
+ audio_network_adaptation_events.push_back(rtc_event);
+ break;
+ }
+ case RtcEvent::Type::AudioPlayout: {
+ auto* rtc_event =
+ static_cast<const RtcEventAudioPlayout* const>(it->get());
+ audio_playout_events.push_back(rtc_event);
+ break;
+ }
+ case RtcEvent::Type::AudioReceiveStreamConfig: {
+ auto* rtc_event =
+ static_cast<const RtcEventAudioReceiveStreamConfig* const>(
+ it->get());
+ audio_recv_stream_configs.push_back(rtc_event);
+ break;
+ }
+ case RtcEvent::Type::AudioSendStreamConfig: {
+ auto* rtc_event =
+ static_cast<const RtcEventAudioSendStreamConfig* const>(
+ it->get());
+ audio_send_stream_configs.push_back(rtc_event);
+ break;
+ }
+ case RtcEvent::Type::BweUpdateDelayBased: {
+ auto* rtc_event =
+ static_cast<const RtcEventBweUpdateDelayBased* const>(it->get());
+ bwe_delay_based_updates.push_back(rtc_event);
+ break;
+ }
+ case RtcEvent::Type::BweUpdateLossBased: {
+ auto* rtc_event =
+ static_cast<const RtcEventBweUpdateLossBased* const>(it->get());
+ bwe_loss_based_updates.push_back(rtc_event);
+ break;
+ }
+ case RtcEvent::Type::DtlsTransportState: {
+ auto* rtc_event =
+ static_cast<const RtcEventDtlsTransportState* const>(it->get());
+ dtls_transport_states.push_back(rtc_event);
+ break;
+ }
+ case RtcEvent::Type::DtlsWritableState: {
+ auto* rtc_event =
+ static_cast<const RtcEventDtlsWritableState* const>(it->get());
+ dtls_writable_states.push_back(rtc_event);
+ break;
+ }
+ case RtcEvent::Type::ProbeClusterCreated: {
+ auto* rtc_event =
+ static_cast<const RtcEventProbeClusterCreated* const>(it->get());
+ probe_cluster_created_events.push_back(rtc_event);
+ break;
+ }
+ case RtcEvent::Type::ProbeResultFailure: {
+ auto* rtc_event =
+ static_cast<const RtcEventProbeResultFailure* const>(it->get());
+ probe_result_failure_events.push_back(rtc_event);
+ break;
+ }
+ case RtcEvent::Type::ProbeResultSuccess: {
+ auto* rtc_event =
+ static_cast<const RtcEventProbeResultSuccess* const>(it->get());
+ 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::RemoteEstimateEvent: {
+ auto* rtc_event =
+ static_cast<const RtcEventRemoteEstimate* const>(it->get());
+ remote_estimate_events.push_back(rtc_event);
+ break;
+ }
+ case RtcEvent::Type::RtcpPacketIncoming: {
+ auto* rtc_event =
+ static_cast<const RtcEventRtcpPacketIncoming* const>(it->get());
+ incoming_rtcp_packets.push_back(rtc_event);
+ break;
+ }
+ case RtcEvent::Type::RtcpPacketOutgoing: {
+ auto* rtc_event =
+ static_cast<const RtcEventRtcpPacketOutgoing* const>(it->get());
+ outgoing_rtcp_packets.push_back(rtc_event);
+ break;
+ }
+ case RtcEvent::Type::RtpPacketIncoming: {
+ auto* rtc_event =
+ static_cast<const RtcEventRtpPacketIncoming* const>(it->get());
+ auto& v = incoming_rtp_packets[rtc_event->Ssrc()];
+ v.emplace_back(rtc_event);
+ break;
+ }
+ case RtcEvent::Type::RtpPacketOutgoing: {
+ auto* rtc_event =
+ static_cast<const RtcEventRtpPacketOutgoing* const>(it->get());
+ auto& v = outgoing_rtp_packets[rtc_event->Ssrc()];
+ v.emplace_back(rtc_event);
+ break;
+ }
+ case RtcEvent::Type::VideoReceiveStreamConfig: {
+ auto* rtc_event =
+ static_cast<const RtcEventVideoReceiveStreamConfig* const>(
+ it->get());
+ video_recv_stream_configs.push_back(rtc_event);
+ break;
+ }
+ case RtcEvent::Type::VideoSendStreamConfig: {
+ auto* rtc_event =
+ static_cast<const RtcEventVideoSendStreamConfig* const>(
+ it->get());
+ video_send_stream_configs.push_back(rtc_event);
+ break;
+ }
+ case RtcEvent::Type::IceCandidatePairConfig: {
+ auto* rtc_event =
+ static_cast<const RtcEventIceCandidatePairConfig* const>(
+ it->get());
+ ice_candidate_configs.push_back(rtc_event);
+ break;
+ }
+ case RtcEvent::Type::IceCandidatePairEvent: {
+ auto* rtc_event =
+ static_cast<const RtcEventIceCandidatePair* const>(it->get());
+ ice_candidate_events.push_back(rtc_event);
+ break;
+ }
+ case RtcEvent::Type::GenericPacketReceived: {
+ auto* rtc_event =
+ static_cast<const RtcEventGenericPacketReceived* const>(
+ it->get());
+ generic_packets_received.push_back(rtc_event);
+ break;
+ }
+ case RtcEvent::Type::GenericPacketSent: {
+ auto* rtc_event =
+ static_cast<const RtcEventGenericPacketSent* const>(it->get());
+ generic_packets_sent.push_back(rtc_event);
+ break;
+ }
+ case RtcEvent::Type::GenericAckReceived: {
+ auto* rtc_event =
+ static_cast<const RtcEventGenericAckReceived* const>(it->get());
+ generic_acks_received.push_back(rtc_event);
+ break;
+ }
+ case RtcEvent::Type::FrameDecoded: {
+ auto* rtc_event =
+ static_cast<const RtcEventFrameDecoded* const>(it->get());
+ frames_decoded[rtc_event->ssrc()].emplace_back(rtc_event);
+ break;
+ }
+ case RtcEvent::Type::NetEqSetMinimumDelay: {
+ auto* rtc_event =
+ static_cast<const RtcEventNetEqSetMinimumDelay* const>(it->get());
+ neteq_set_minimum_delay_events.push_back(rtc_event);
+ break;
+ }
+ case RtcEvent::Type::BeginV3Log:
+ case RtcEvent::Type::EndV3Log:
+ // These special events are written as part of starting
+ // and stopping the log, and only as part of version 3 of the format.
+ RTC_DCHECK_NOTREACHED();
+ break;
+ case RtcEvent::Type::FakeEvent:
+ // Fake event used for unit test.
+ RTC_DCHECK_NOTREACHED();
+ break;
+ }
+ }
+
+ EncodeAlrState(alr_state_events, &event_stream);
+ EncodeAudioNetworkAdaptation(audio_network_adaptation_events,
+ &event_stream);
+ EncodeAudioPlayout(audio_playout_events, &event_stream);
+ EncodeAudioRecvStreamConfig(audio_recv_stream_configs, &event_stream);
+ EncodeAudioSendStreamConfig(audio_send_stream_configs, &event_stream);
+ EncodeNetEqSetMinimumDelay(neteq_set_minimum_delay_events, &event_stream);
+ EncodeBweUpdateDelayBased(bwe_delay_based_updates, &event_stream);
+ EncodeBweUpdateLossBased(bwe_loss_based_updates, &event_stream);
+ EncodeDtlsTransportState(dtls_transport_states, &event_stream);
+ EncodeDtlsWritableState(dtls_writable_states, &event_stream);
+ for (const auto& kv : frames_decoded) {
+ EncodeFramesDecoded(kv.second, &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);
+ EncodeRemoteEstimate(remote_estimate_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);
+ } // Deallocate the temporary vectors.
+
+ return event_stream.SerializeAsString();
+}
+
+void RtcEventLogEncoderNewFormat::EncodeAlrState(
+ rtc::ArrayView<const RtcEventAlrState*> batch,
+ rtclog2::EventStream* event_stream) {
+ for (const RtcEventAlrState* base_event : batch) {
+ rtclog2::AlrState* proto_batch = event_stream->add_alr_states();
+ proto_batch->set_timestamp_ms(base_event->timestamp_ms());
+ proto_batch->set_in_alr(base_event->in_alr());
+ }
+ // TODO(terelius): Should we delta-compress this event type?
+}
+
+void RtcEventLogEncoderNewFormat::EncodeAudioNetworkAdaptation(
+ rtc::ArrayView<const RtcEventAudioNetworkAdaptation*> batch,
+ rtclog2::EventStream* event_stream) {
+ if (batch.empty())
+ return;
+
+ // Base event
+ const RtcEventAudioNetworkAdaptation* const base_event = batch[0];
+ rtclog2::AudioNetworkAdaptations* proto_batch =
+ event_stream->add_audio_network_adaptations();
+ proto_batch->set_timestamp_ms(base_event->timestamp_ms());
+ if (base_event->config().bitrate_bps.has_value())
+ proto_batch->set_bitrate_bps(base_event->config().bitrate_bps.value());
+ if (base_event->config().frame_length_ms.has_value()) {
+ proto_batch->set_frame_length_ms(
+ base_event->config().frame_length_ms.value());
+ }
+ absl::optional<uint64_t> base_uplink_packet_loss_fraction;
+ if (base_event->config().uplink_packet_loss_fraction.has_value()) {
+ base_uplink_packet_loss_fraction = ConvertPacketLossFractionToProtoFormat(
+ base_event->config().uplink_packet_loss_fraction.value());
+ proto_batch->set_uplink_packet_loss_fraction(
+ base_uplink_packet_loss_fraction.value());
+ }
+ if (base_event->config().enable_fec.has_value())
+ proto_batch->set_enable_fec(base_event->config().enable_fec.value());
+ if (base_event->config().enable_dtx.has_value())
+ proto_batch->set_enable_dtx(base_event->config().enable_dtx.value());
+ // Note that `num_channels_deltas` encodes N as N-1, to keep deltas smaller,
+ // but there's no reason to do the same for the base event's value, since
+ // no bits will be spared.
+ if (base_event->config().num_channels.has_value())
+ proto_batch->set_num_channels(base_event->config().num_channels.value());
+
+ if (batch.size() == 1)
+ return;
+
+ // 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;
+
+ // timestamp_ms
+ for (size_t i = 0; i < values.size(); ++i) {
+ const RtcEventAudioNetworkAdaptation* 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);
+ }
+
+ // bitrate_bps
+ for (size_t i = 0; i < values.size(); ++i) {
+ const RtcEventAudioNetworkAdaptation* event = batch[i + 1];
+ if (event->config().bitrate_bps.has_value()) {
+ values[i] = ToUnsigned(event->config().bitrate_bps.value());
+ } else {
+ values[i].reset();
+ }
+ }
+ const absl::optional<uint64_t> unsigned_base_bitrate_bps =
+ base_event->config().bitrate_bps.has_value()
+ ? ToUnsigned(base_event->config().bitrate_bps.value())
+ : absl::optional<uint64_t>();
+ encoded_deltas = EncodeDeltas(unsigned_base_bitrate_bps, values);
+ if (!encoded_deltas.empty()) {
+ proto_batch->set_bitrate_bps_deltas(encoded_deltas);
+ }
+
+ // frame_length_ms
+ for (size_t i = 0; i < values.size(); ++i) {
+ const RtcEventAudioNetworkAdaptation* event = batch[i + 1];
+ if (event->config().frame_length_ms.has_value()) {
+ values[i] = ToUnsigned(event->config().frame_length_ms.value());
+ } else {
+ values[i].reset();
+ }
+ }
+ const absl::optional<uint64_t> unsigned_base_frame_length_ms =
+ base_event->config().frame_length_ms.has_value()
+ ? ToUnsigned(base_event->config().frame_length_ms.value())
+ : absl::optional<uint64_t>();
+ encoded_deltas = EncodeDeltas(unsigned_base_frame_length_ms, values);
+ if (!encoded_deltas.empty()) {
+ proto_batch->set_frame_length_ms_deltas(encoded_deltas);
+ }
+
+ // uplink_packet_loss_fraction
+ for (size_t i = 0; i < values.size(); ++i) {
+ const RtcEventAudioNetworkAdaptation* event = batch[i + 1];
+ if (event->config().uplink_packet_loss_fraction.has_value()) {
+ values[i] = ConvertPacketLossFractionToProtoFormat(
+ event->config().uplink_packet_loss_fraction.value());
+ } else {
+ values[i].reset();
+ }
+ }
+ encoded_deltas = EncodeDeltas(base_uplink_packet_loss_fraction, values);
+ if (!encoded_deltas.empty()) {
+ proto_batch->set_uplink_packet_loss_fraction_deltas(encoded_deltas);
+ }
+
+ // enable_fec
+ for (size_t i = 0; i < values.size(); ++i) {
+ const RtcEventAudioNetworkAdaptation* event = batch[i + 1];
+ values[i] = event->config().enable_fec;
+ }
+ encoded_deltas = EncodeDeltas(base_event->config().enable_fec, values);
+ if (!encoded_deltas.empty()) {
+ proto_batch->set_enable_fec_deltas(encoded_deltas);
+ }
+
+ // enable_dtx
+ for (size_t i = 0; i < values.size(); ++i) {
+ const RtcEventAudioNetworkAdaptation* event = batch[i + 1];
+ values[i] = event->config().enable_dtx;
+ }
+ encoded_deltas = EncodeDeltas(base_event->config().enable_dtx, values);
+ if (!encoded_deltas.empty()) {
+ proto_batch->set_enable_dtx_deltas(encoded_deltas);
+ }
+
+ // num_channels
+ for (size_t i = 0; i < values.size(); ++i) {
+ const RtcEventAudioNetworkAdaptation* event = batch[i + 1];
+ const absl::optional<size_t> num_channels = event->config().num_channels;
+ if (num_channels.has_value()) {
+ // Since the number of channels is always greater than 0, we can encode
+ // N channels as N-1, thereby making sure that we get smaller deltas.
+ // That is, a toggle of 1->2->1 can be encoded as deltas vector (1, 1),
+ // rather than as (1, 3) or (1, -1), either of which would require two
+ // bits per delta.
+ RTC_DCHECK_GT(num_channels.value(), 0u);
+ values[i] = num_channels.value() - 1;
+ } else {
+ values[i].reset();
+ }
+ }
+ // In the base event, N channels encoded as N channels, but for delta
+ // compression purposes, also shifted down by 1.
+ absl::optional<size_t> shifted_base_num_channels;
+ if (base_event->config().num_channels.has_value()) {
+ RTC_DCHECK_GT(base_event->config().num_channels.value(), 0u);
+ shifted_base_num_channels = base_event->config().num_channels.value() - 1;
+ }
+ encoded_deltas = EncodeDeltas(shifted_base_num_channels, values);
+ if (!encoded_deltas.empty()) {
+ proto_batch->set_num_channels_deltas(encoded_deltas);
+ }
+}
+
+void RtcEventLogEncoderNewFormat::EncodeAudioPlayout(
+ rtc::ArrayView<const RtcEventAudioPlayout*> batch,
+ rtclog2::EventStream* event_stream) {
+ if (batch.empty())
+ return;
+
+ // Base event
+ const RtcEventAudioPlayout* const base_event = batch[0];
+ rtclog2::AudioPlayoutEvents* proto_batch =
+ event_stream->add_audio_playout_events();
+ proto_batch->set_timestamp_ms(base_event->timestamp_ms());
+ proto_batch->set_local_ssrc(base_event->ssrc());
+
+ if (batch.size() == 1)
+ return;
+
+ // 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;
+
+ // timestamp_ms
+ for (size_t i = 0; i < values.size(); ++i) {
+ const RtcEventAudioPlayout* 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);
+ }
+
+ // local_ssrc
+ for (size_t i = 0; i < values.size(); ++i) {
+ const RtcEventAudioPlayout* event = batch[i + 1];
+ values[i] = event->ssrc();
+ }
+ encoded_deltas = EncodeDeltas(base_event->ssrc(), values);
+ if (!encoded_deltas.empty()) {
+ proto_batch->set_local_ssrc_deltas(encoded_deltas);
+ }
+}
+
+void RtcEventLogEncoderNewFormat::EncodeNetEqSetMinimumDelay(
+ rtc::ArrayView<const RtcEventNetEqSetMinimumDelay*> batch,
+ rtclog2::EventStream* event_stream) {
+ if (encode_neteq_set_minimum_delay_kill_switch_) {
+ return;
+ }
+ if (batch.empty()) {
+ return;
+ }
+
+ const RtcEventNetEqSetMinimumDelay* base_event = batch[0];
+
+ rtclog2::NetEqSetMinimumDelay* proto_batch =
+ event_stream->add_neteq_set_minimum_delay();
+ proto_batch->set_timestamp_ms(base_event->timestamp_ms());
+ proto_batch->set_remote_ssrc(base_event->remote_ssrc());
+ proto_batch->set_minimum_delay_ms(base_event->minimum_delay_ms());
+
+ if (batch.size() == 1)
+ return;
+
+ // 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;
+
+ // timestamp_ms
+ for (size_t i = 0; i < values.size(); ++i) {
+ const RtcEventNetEqSetMinimumDelay* 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);
+ }
+
+ // remote_ssrc
+ for (size_t i = 0; i < values.size(); ++i) {
+ const RtcEventNetEqSetMinimumDelay* event = batch[i + 1];
+ values[i] = event->remote_ssrc();
+ }
+ encoded_deltas = EncodeDeltas(base_event->remote_ssrc(), values);
+ if (!encoded_deltas.empty()) {
+ proto_batch->set_remote_ssrc_deltas(encoded_deltas);
+ }
+
+ // minimum_delay_ms
+ for (size_t i = 0; i < values.size(); ++i) {
+ const RtcEventNetEqSetMinimumDelay* event = batch[i + 1];
+ values[i] = ToUnsigned(event->minimum_delay_ms());
+ }
+ encoded_deltas =
+ EncodeDeltas(ToUnsigned(base_event->minimum_delay_ms()), values);
+ if (!encoded_deltas.empty()) {
+ proto_batch->set_minimum_delay_ms_deltas(encoded_deltas);
+ }
+}
+
+void RtcEventLogEncoderNewFormat::EncodeAudioRecvStreamConfig(
+ rtc::ArrayView<const RtcEventAudioReceiveStreamConfig*> batch,
+ rtclog2::EventStream* event_stream) {
+ for (const RtcEventAudioReceiveStreamConfig* base_event : batch) {
+ rtclog2::AudioRecvStreamConfig* proto_batch =
+ event_stream->add_audio_recv_stream_configs();
+ proto_batch->set_timestamp_ms(base_event->timestamp_ms());
+ proto_batch->set_remote_ssrc(base_event->config().remote_ssrc);
+ proto_batch->set_local_ssrc(base_event->config().local_ssrc);
+
+ rtclog2::RtpHeaderExtensionConfig* proto_config =
+ proto_batch->mutable_header_extensions();
+ bool has_recognized_extensions =
+ ConvertToProtoFormat(base_event->config().rtp_extensions, proto_config);
+ if (!has_recognized_extensions)
+ proto_batch->clear_header_extensions();
+ }
+}
+
+void RtcEventLogEncoderNewFormat::EncodeAudioSendStreamConfig(
+ rtc::ArrayView<const RtcEventAudioSendStreamConfig*> batch,
+ rtclog2::EventStream* event_stream) {
+ for (const RtcEventAudioSendStreamConfig* base_event : batch) {
+ rtclog2::AudioSendStreamConfig* proto_batch =
+ event_stream->add_audio_send_stream_configs();
+ proto_batch->set_timestamp_ms(base_event->timestamp_ms());
+ proto_batch->set_ssrc(base_event->config().local_ssrc);
+
+ rtclog2::RtpHeaderExtensionConfig* proto_config =
+ proto_batch->mutable_header_extensions();
+ bool has_recognized_extensions =
+ ConvertToProtoFormat(base_event->config().rtp_extensions, proto_config);
+ if (!has_recognized_extensions)
+ proto_batch->clear_header_extensions();
+ }
+}
+
+void RtcEventLogEncoderNewFormat::EncodeBweUpdateDelayBased(
+ rtc::ArrayView<const RtcEventBweUpdateDelayBased*> batch,
+ rtclog2::EventStream* event_stream) {
+ if (batch.empty())
+ return;
+
+ // Base event
+ const RtcEventBweUpdateDelayBased* const base_event = batch[0];
+ rtclog2::DelayBasedBweUpdates* proto_batch =
+ event_stream->add_delay_based_bwe_updates();
+ proto_batch->set_timestamp_ms(base_event->timestamp_ms());
+ proto_batch->set_bitrate_bps(base_event->bitrate_bps());
+ proto_batch->set_detector_state(
+ ConvertToProtoFormat(base_event->detector_state()));
+
+ if (batch.size() == 1)
+ return;
+
+ // 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;
+
+ // timestamp_ms
+ for (size_t i = 0; i < values.size(); ++i) {
+ const RtcEventBweUpdateDelayBased* 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);
+ }
+
+ // bitrate_bps
+ for (size_t i = 0; i < values.size(); ++i) {
+ const RtcEventBweUpdateDelayBased* event = batch[i + 1];
+ values[i] = event->bitrate_bps();
+ }
+ encoded_deltas = EncodeDeltas(base_event->bitrate_bps(), values);
+ if (!encoded_deltas.empty()) {
+ proto_batch->set_bitrate_bps_deltas(encoded_deltas);
+ }
+
+ // detector_state
+ for (size_t i = 0; i < values.size(); ++i) {
+ const RtcEventBweUpdateDelayBased* event = batch[i + 1];
+ values[i] =
+ static_cast<uint64_t>(ConvertToProtoFormat(event->detector_state()));
+ }
+ encoded_deltas = EncodeDeltas(
+ static_cast<uint64_t>(ConvertToProtoFormat(base_event->detector_state())),
+ values);
+ if (!encoded_deltas.empty()) {
+ proto_batch->set_detector_state_deltas(encoded_deltas);
+ }
+}
+
+void RtcEventLogEncoderNewFormat::EncodeBweUpdateLossBased(
+ rtc::ArrayView<const RtcEventBweUpdateLossBased*> batch,
+ rtclog2::EventStream* event_stream) {
+ if (batch.empty())
+ return;
+
+ // Base event
+ const RtcEventBweUpdateLossBased* const base_event = batch[0];
+ rtclog2::LossBasedBweUpdates* proto_batch =
+ event_stream->add_loss_based_bwe_updates();
+ proto_batch->set_timestamp_ms(base_event->timestamp_ms());
+ proto_batch->set_bitrate_bps(base_event->bitrate_bps());
+ proto_batch->set_fraction_loss(base_event->fraction_loss());
+ proto_batch->set_total_packets(base_event->total_packets());
+
+ if (batch.size() == 1)
+ return;
+
+ // 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;
+
+ // timestamp_ms
+ for (size_t i = 0; i < values.size(); ++i) {
+ const RtcEventBweUpdateLossBased* 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);
+ }
+
+ // bitrate_bps
+ for (size_t i = 0; i < values.size(); ++i) {
+ const RtcEventBweUpdateLossBased* event = batch[i + 1];
+ values[i] = event->bitrate_bps();
+ }
+ encoded_deltas = EncodeDeltas(base_event->bitrate_bps(), values);
+ if (!encoded_deltas.empty()) {
+ proto_batch->set_bitrate_bps_deltas(encoded_deltas);
+ }
+
+ // fraction_loss
+ for (size_t i = 0; i < values.size(); ++i) {
+ const RtcEventBweUpdateLossBased* event = batch[i + 1];
+ values[i] = event->fraction_loss();
+ }
+ encoded_deltas = EncodeDeltas(base_event->fraction_loss(), values);
+ if (!encoded_deltas.empty()) {
+ proto_batch->set_fraction_loss_deltas(encoded_deltas);
+ }
+
+ // total_packets
+ for (size_t i = 0; i < values.size(); ++i) {
+ const RtcEventBweUpdateLossBased* event = batch[i + 1];
+ values[i] = event->total_packets();
+ }
+ encoded_deltas = EncodeDeltas(base_event->total_packets(), values);
+ if (!encoded_deltas.empty()) {
+ proto_batch->set_total_packets_deltas(encoded_deltas);
+ }
+}
+
+void RtcEventLogEncoderNewFormat::EncodeDtlsTransportState(
+ rtc::ArrayView<const RtcEventDtlsTransportState*> batch,
+ rtclog2::EventStream* event_stream) {
+ for (const RtcEventDtlsTransportState* base_event : batch) {
+ rtclog2::DtlsTransportStateEvent* proto_batch =
+ event_stream->add_dtls_transport_state_events();
+ proto_batch->set_timestamp_ms(base_event->timestamp_ms());
+ proto_batch->set_dtls_transport_state(
+ ConvertToProtoFormat(base_event->dtls_transport_state()));
+ }
+}
+
+void RtcEventLogEncoderNewFormat::EncodeDtlsWritableState(
+ rtc::ArrayView<const RtcEventDtlsWritableState*> batch,
+ rtclog2::EventStream* event_stream) {
+ for (const RtcEventDtlsWritableState* base_event : batch) {
+ rtclog2::DtlsWritableState* proto_batch =
+ event_stream->add_dtls_writable_states();
+ proto_batch->set_timestamp_ms(base_event->timestamp_ms());
+ proto_batch->set_writable(base_event->writable());
+ }
+}
+
+void RtcEventLogEncoderNewFormat::EncodeProbeClusterCreated(
+ rtc::ArrayView<const RtcEventProbeClusterCreated*> batch,
+ rtclog2::EventStream* event_stream) {
+ for (const RtcEventProbeClusterCreated* base_event : batch) {
+ rtclog2::BweProbeCluster* proto_batch = event_stream->add_probe_clusters();
+ proto_batch->set_timestamp_ms(base_event->timestamp_ms());
+ proto_batch->set_id(base_event->id());
+ proto_batch->set_bitrate_bps(base_event->bitrate_bps());
+ proto_batch->set_min_packets(base_event->min_probes());
+ proto_batch->set_min_bytes(base_event->min_bytes());
+ }
+}
+
+void RtcEventLogEncoderNewFormat::EncodeProbeResultFailure(
+ rtc::ArrayView<const RtcEventProbeResultFailure*> batch,
+ rtclog2::EventStream* event_stream) {
+ for (const RtcEventProbeResultFailure* base_event : batch) {
+ rtclog2::BweProbeResultFailure* proto_batch =
+ event_stream->add_probe_failure();
+ proto_batch->set_timestamp_ms(base_event->timestamp_ms());
+ proto_batch->set_id(base_event->id());
+ proto_batch->set_failure(
+ ConvertToProtoFormat(base_event->failure_reason()));
+ }
+ // TODO(terelius): Should we delta-compress this event type?
+}
+
+void RtcEventLogEncoderNewFormat::EncodeProbeResultSuccess(
+ rtc::ArrayView<const RtcEventProbeResultSuccess*> batch,
+ rtclog2::EventStream* event_stream) {
+ for (const RtcEventProbeResultSuccess* base_event : batch) {
+ rtclog2::BweProbeResultSuccess* proto_batch =
+ event_stream->add_probe_success();
+ proto_batch->set_timestamp_ms(base_event->timestamp_ms());
+ proto_batch->set_id(base_event->id());
+ proto_batch->set_bitrate_bps(base_event->bitrate_bps());
+ }
+ // 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::EncodeRemoteEstimate(
+ rtc::ArrayView<const RtcEventRemoteEstimate*> batch,
+ rtclog2::EventStream* event_stream) {
+ if (batch.empty())
+ return;
+
+ // Base event
+ const auto* const base_event = batch[0];
+ rtclog2::RemoteEstimates* proto_batch = event_stream->add_remote_estimates();
+
+ proto_batch->set_timestamp_ms(base_event->timestamp_ms());
+
+ absl::optional<uint64_t> base_link_capacity_lower;
+ if (base_event->link_capacity_lower_.IsFinite()) {
+ base_link_capacity_lower =
+ base_event->link_capacity_lower_.kbps<uint32_t>();
+ proto_batch->set_link_capacity_lower_kbps(*base_link_capacity_lower);
+ }
+ absl::optional<uint64_t> base_link_capacity_upper;
+ if (base_event->link_capacity_upper_.IsFinite()) {
+ base_link_capacity_upper =
+ base_event->link_capacity_upper_.kbps<uint32_t>();
+ proto_batch->set_link_capacity_upper_kbps(*base_link_capacity_upper);
+ }
+
+ if (batch.size() == 1)
+ return;
+
+ // 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;
+
+ // timestamp_ms
+ for (size_t i = 0; i < values.size(); ++i) {
+ const auto* 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);
+ }
+
+ // link_capacity_lower_kbps
+ for (size_t i = 0; i < values.size(); ++i) {
+ const auto* event = batch[i + 1];
+ if (event->link_capacity_lower_.IsFinite()) {
+ values[i] = event->link_capacity_lower_.kbps<uint32_t>();
+ } else {
+ values[i].reset();
+ }
+ }
+ encoded_deltas = EncodeDeltas(base_link_capacity_lower, values);
+ if (!encoded_deltas.empty()) {
+ proto_batch->set_link_capacity_lower_kbps_deltas(encoded_deltas);
+ }
+
+ // link_capacity_upper_kbps
+ for (size_t i = 0; i < values.size(); ++i) {
+ const auto* event = batch[i + 1];
+ if (event->link_capacity_upper_.IsFinite()) {
+ values[i] = event->link_capacity_upper_.kbps<uint32_t>();
+ } else {
+ values[i].reset();
+ }
+ }
+ encoded_deltas = EncodeDeltas(base_link_capacity_upper, values);
+ if (!encoded_deltas.empty()) {
+ proto_batch->set_link_capacity_upper_kbps_deltas(encoded_deltas);
+ }
+}
+
+void RtcEventLogEncoderNewFormat::EncodeRtcpPacketIncoming(
+ rtc::ArrayView<const RtcEventRtcpPacketIncoming*> batch,
+ rtclog2::EventStream* event_stream) {
+ if (batch.empty()) {
+ return;
+ }
+ EncodeRtcpPacket(batch, event_stream->add_incoming_rtcp_packets());
+}
+
+void RtcEventLogEncoderNewFormat::EncodeRtcpPacketOutgoing(
+ rtc::ArrayView<const RtcEventRtcpPacketOutgoing*> batch,
+ rtclog2::EventStream* event_stream) {
+ if (batch.empty()) {
+ return;
+ }
+ EncodeRtcpPacket(batch, event_stream->add_outgoing_rtcp_packets());
+}
+
+void RtcEventLogEncoderNewFormat::EncodeRtpPacketIncoming(
+ const std::map<uint32_t, std::vector<const RtcEventRtpPacketIncoming*>>&
+ batch,
+ rtclog2::EventStream* event_stream) {
+ for (const auto& it : batch) {
+ RTC_DCHECK(!it.second.empty());
+ EncodeRtpPacket(it.second, event_stream->add_incoming_rtp_packets());
+ }
+}
+
+void RtcEventLogEncoderNewFormat::EncodeFramesDecoded(
+ rtc::ArrayView<const RtcEventFrameDecoded* const> batch,
+ rtclog2::EventStream* event_stream) {
+ if (batch.empty()) {
+ return;
+ }
+ const RtcEventFrameDecoded* const base_event = batch[0];
+ rtclog2::FrameDecodedEvents* proto_batch =
+ event_stream->add_frame_decoded_events();
+ proto_batch->set_timestamp_ms(base_event->timestamp_ms());
+ proto_batch->set_ssrc(base_event->ssrc());
+ proto_batch->set_render_time_ms(base_event->render_time_ms());
+ proto_batch->set_width(base_event->width());
+ proto_batch->set_height(base_event->height());
+ proto_batch->set_codec(ConvertToProtoFormat(base_event->codec()));
+ proto_batch->set_qp(base_event->qp());
+
+ if (batch.size() == 1) {
+ return;
+ }
+
+ // 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;
+
+ // timestamp_ms
+ for (size_t i = 0; i < values.size(); ++i) {
+ const RtcEventFrameDecoded* 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);
+ }
+
+ // SSRC
+ for (size_t i = 0; i < values.size(); ++i) {
+ const RtcEventFrameDecoded* event = batch[i + 1];
+ values[i] = event->ssrc();
+ }
+ encoded_deltas = EncodeDeltas(base_event->ssrc(), values);
+ if (!encoded_deltas.empty()) {
+ proto_batch->set_ssrc_deltas(encoded_deltas);
+ }
+
+ // render_time_ms
+ for (size_t i = 0; i < values.size(); ++i) {
+ const RtcEventFrameDecoded* event = batch[i + 1];
+ values[i] = ToUnsigned(event->render_time_ms());
+ }
+ encoded_deltas =
+ EncodeDeltas(ToUnsigned(base_event->render_time_ms()), values);
+ if (!encoded_deltas.empty()) {
+ proto_batch->set_render_time_ms_deltas(encoded_deltas);
+ }
+
+ // width
+ for (size_t i = 0; i < values.size(); ++i) {
+ const RtcEventFrameDecoded* event = batch[i + 1];
+ values[i] = ToUnsigned(event->width());
+ }
+ encoded_deltas = EncodeDeltas(ToUnsigned(base_event->width()), values);
+ if (!encoded_deltas.empty()) {
+ proto_batch->set_width_deltas(encoded_deltas);
+ }
+
+ // height
+ for (size_t i = 0; i < values.size(); ++i) {
+ const RtcEventFrameDecoded* event = batch[i + 1];
+ values[i] = ToUnsigned(event->height());
+ }
+ encoded_deltas = EncodeDeltas(ToUnsigned(base_event->height()), values);
+ if (!encoded_deltas.empty()) {
+ proto_batch->set_height_deltas(encoded_deltas);
+ }
+
+ // codec
+ for (size_t i = 0; i < values.size(); ++i) {
+ const RtcEventFrameDecoded* event = batch[i + 1];
+ values[i] = static_cast<uint64_t>(ConvertToProtoFormat(event->codec()));
+ }
+ encoded_deltas = EncodeDeltas(
+ static_cast<uint64_t>(ConvertToProtoFormat(base_event->codec())), values);
+ if (!encoded_deltas.empty()) {
+ proto_batch->set_codec_deltas(encoded_deltas);
+ }
+
+ // qp
+ for (size_t i = 0; i < values.size(); ++i) {
+ const RtcEventFrameDecoded* event = batch[i + 1];
+ values[i] = event->qp();
+ }
+ encoded_deltas = EncodeDeltas(base_event->qp(), values);
+ if (!encoded_deltas.empty()) {
+ proto_batch->set_qp_deltas(encoded_deltas);
+ }
+}
+
+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,
+ rtclog2::EventStream* event_stream) {
+ for (const auto& it : batch) {
+ RTC_DCHECK(!it.second.empty());
+ EncodeRtpPacket(it.second, event_stream->add_outgoing_rtp_packets());
+ }
+}
+
+void RtcEventLogEncoderNewFormat::EncodeVideoRecvStreamConfig(
+ rtc::ArrayView<const RtcEventVideoReceiveStreamConfig*> batch,
+ rtclog2::EventStream* event_stream) {
+ for (const RtcEventVideoReceiveStreamConfig* base_event : batch) {
+ rtclog2::VideoRecvStreamConfig* proto_batch =
+ event_stream->add_video_recv_stream_configs();
+ proto_batch->set_timestamp_ms(base_event->timestamp_ms());
+ proto_batch->set_remote_ssrc(base_event->config().remote_ssrc);
+ proto_batch->set_local_ssrc(base_event->config().local_ssrc);
+ proto_batch->set_rtx_ssrc(base_event->config().rtx_ssrc);
+
+ rtclog2::RtpHeaderExtensionConfig* proto_config =
+ proto_batch->mutable_header_extensions();
+ bool has_recognized_extensions =
+ ConvertToProtoFormat(base_event->config().rtp_extensions, proto_config);
+ if (!has_recognized_extensions)
+ proto_batch->clear_header_extensions();
+ }
+}
+
+void RtcEventLogEncoderNewFormat::EncodeVideoSendStreamConfig(
+ rtc::ArrayView<const RtcEventVideoSendStreamConfig*> batch,
+ rtclog2::EventStream* event_stream) {
+ for (const RtcEventVideoSendStreamConfig* base_event : batch) {
+ rtclog2::VideoSendStreamConfig* proto_batch =
+ event_stream->add_video_send_stream_configs();
+ proto_batch->set_timestamp_ms(base_event->timestamp_ms());
+ proto_batch->set_ssrc(base_event->config().local_ssrc);
+ proto_batch->set_rtx_ssrc(base_event->config().rtx_ssrc);
+
+ rtclog2::RtpHeaderExtensionConfig* proto_config =
+ proto_batch->mutable_header_extensions();
+ bool has_recognized_extensions =
+ ConvertToProtoFormat(base_event->config().rtp_extensions, proto_config);
+ if (!has_recognized_extensions)
+ proto_batch->clear_header_extensions();
+ }
+}
+
+void RtcEventLogEncoderNewFormat::EncodeIceCandidatePairConfig(
+ rtc::ArrayView<const RtcEventIceCandidatePairConfig*> batch,
+ rtclog2::EventStream* event_stream) {
+ for (const RtcEventIceCandidatePairConfig* base_event : batch) {
+ rtclog2::IceCandidatePairConfig* proto_batch =
+ event_stream->add_ice_candidate_configs();
+
+ proto_batch->set_timestamp_ms(base_event->timestamp_ms());
+ proto_batch->set_config_type(ConvertToProtoFormat(base_event->type()));
+ proto_batch->set_candidate_pair_id(base_event->candidate_pair_id());
+ const auto& desc = base_event->candidate_pair_desc();
+ proto_batch->set_local_candidate_type(
+ ConvertToProtoFormat(desc.local_candidate_type));
+ proto_batch->set_local_relay_protocol(
+ ConvertToProtoFormat(desc.local_relay_protocol));
+ proto_batch->set_local_network_type(
+ ConvertToProtoFormat(desc.local_network_type));
+ proto_batch->set_local_address_family(
+ ConvertToProtoFormat(desc.local_address_family));
+ proto_batch->set_remote_candidate_type(
+ ConvertToProtoFormat(desc.remote_candidate_type));
+ proto_batch->set_remote_address_family(
+ ConvertToProtoFormat(desc.remote_address_family));
+ proto_batch->set_candidate_pair_protocol(
+ ConvertToProtoFormat(desc.candidate_pair_protocol));
+ }
+ // TODO(terelius): Should we delta-compress this event type?
+}
+
+void RtcEventLogEncoderNewFormat::EncodeIceCandidatePairEvent(
+ rtc::ArrayView<const RtcEventIceCandidatePair*> batch,
+ rtclog2::EventStream* event_stream) {
+ for (const RtcEventIceCandidatePair* base_event : batch) {
+ rtclog2::IceCandidatePairEvent* proto_batch =
+ event_stream->add_ice_candidate_events();
+
+ proto_batch->set_timestamp_ms(base_event->timestamp_ms());
+
+ proto_batch->set_event_type(ConvertToProtoFormat(base_event->type()));
+ proto_batch->set_candidate_pair_id(base_event->candidate_pair_id());
+ proto_batch->set_transaction_id(base_event->transaction_id());
+ }
+ // TODO(terelius): Should we delta-compress this event type?
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder_new_format.h b/third_party/libwebrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder_new_format.h
new file mode 100644
index 0000000000..6747f41f07
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder_new_format.h
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2017 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_ENCODER_RTC_EVENT_LOG_ENCODER_NEW_FORMAT_H_
+#define LOGGING_RTC_EVENT_LOG_ENCODER_RTC_EVENT_LOG_ENCODER_NEW_FORMAT_H_
+
+#include <deque>
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "api/array_view.h"
+#include "logging/rtc_event_log/encoder/rtc_event_log_encoder.h"
+
+namespace webrtc {
+
+namespace rtclog2 {
+class EventStream; // Auto-generated from protobuf.
+} // namespace rtclog2
+
+class RtcEventAlrState;
+class RtcEventRouteChange;
+class RtcEventRemoteEstimate;
+class RtcEventAudioNetworkAdaptation;
+class RtcEventAudioPlayout;
+class RtcEventAudioReceiveStreamConfig;
+class RtcEventAudioSendStreamConfig;
+class RtcEventBweUpdateDelayBased;
+class RtcEventBweUpdateLossBased;
+class RtcEventDtlsTransportState;
+class RtcEventDtlsWritableState;
+class RtcEventLoggingStarted;
+class RtcEventLoggingStopped;
+class RtcEventNetEqSetMinimumDelay;
+class RtcEventProbeClusterCreated;
+class RtcEventProbeResultFailure;
+class RtcEventProbeResultSuccess;
+class RtcEventRtcpPacketIncoming;
+class RtcEventRtcpPacketOutgoing;
+class RtcEventRtpPacketIncoming;
+class RtcEventRtpPacketOutgoing;
+class RtcEventVideoReceiveStreamConfig;
+class RtcEventVideoSendStreamConfig;
+class RtcEventIceCandidatePairConfig;
+class RtcEventIceCandidatePair;
+class RtpPacket;
+class RtcEventFrameDecoded;
+class RtcEventGenericAckReceived;
+class RtcEventGenericPacketReceived;
+class RtcEventGenericPacketSent;
+
+class RtcEventLogEncoderNewFormat final : public RtcEventLogEncoder {
+ public:
+ RtcEventLogEncoderNewFormat();
+ ~RtcEventLogEncoderNewFormat() override = default;
+
+ std::string EncodeBatch(
+ std::deque<std::unique_ptr<RtcEvent>>::const_iterator begin,
+ std::deque<std::unique_ptr<RtcEvent>>::const_iterator end) override;
+
+ std::string EncodeLogStart(int64_t timestamp_us,
+ int64_t utc_time_us) override;
+ std::string EncodeLogEnd(int64_t timestamp_us) override;
+
+ private:
+ bool encode_neteq_set_minimum_delay_kill_switch_ = false;
+
+ // Encoding entry-point for the various RtcEvent subclasses.
+ void EncodeAlrState(rtc::ArrayView<const RtcEventAlrState*> batch,
+ rtclog2::EventStream* event_stream);
+ void EncodeAudioNetworkAdaptation(
+ rtc::ArrayView<const RtcEventAudioNetworkAdaptation*> batch,
+ rtclog2::EventStream* event_stream);
+ void EncodeAudioPlayout(rtc::ArrayView<const RtcEventAudioPlayout*> batch,
+ rtclog2::EventStream* event_stream);
+ void EncodeAudioRecvStreamConfig(
+ rtc::ArrayView<const RtcEventAudioReceiveStreamConfig*> batch,
+ rtclog2::EventStream* event_stream);
+ void EncodeAudioSendStreamConfig(
+ rtc::ArrayView<const RtcEventAudioSendStreamConfig*> batch,
+ rtclog2::EventStream* event_stream);
+ void EncodeBweUpdateDelayBased(
+ rtc::ArrayView<const RtcEventBweUpdateDelayBased*> batch,
+ rtclog2::EventStream* event_stream);
+ void EncodeBweUpdateLossBased(
+ rtc::ArrayView<const RtcEventBweUpdateLossBased*> batch,
+ rtclog2::EventStream* event_stream);
+ void EncodeDtlsTransportState(
+ rtc::ArrayView<const RtcEventDtlsTransportState*> batch,
+ rtclog2::EventStream* event_stream);
+ void EncodeDtlsWritableState(
+ rtc::ArrayView<const RtcEventDtlsWritableState*> batch,
+ rtclog2::EventStream* event_stream);
+ void EncodeFramesDecoded(
+ rtc::ArrayView<const RtcEventFrameDecoded* const> 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,
+ rtclog2::EventStream* event_stream);
+ void EncodeNetEqSetMinimumDelay(
+ rtc::ArrayView<const RtcEventNetEqSetMinimumDelay*> batch,
+ rtclog2::EventStream* event_stream);
+ void EncodeProbeClusterCreated(
+ rtc::ArrayView<const RtcEventProbeClusterCreated*> batch,
+ rtclog2::EventStream* event_stream);
+ void EncodeProbeResultFailure(
+ rtc::ArrayView<const RtcEventProbeResultFailure*> batch,
+ rtclog2::EventStream* event_stream);
+ void EncodeProbeResultSuccess(
+ rtc::ArrayView<const RtcEventProbeResultSuccess*> batch,
+ rtclog2::EventStream* event_stream);
+ void EncodeRouteChange(rtc::ArrayView<const RtcEventRouteChange*> batch,
+ rtclog2::EventStream* event_stream);
+ void EncodeRemoteEstimate(rtc::ArrayView<const RtcEventRemoteEstimate*> batch,
+ rtclog2::EventStream* event_stream);
+ void EncodeRtcpPacketIncoming(
+ rtc::ArrayView<const RtcEventRtcpPacketIncoming*> batch,
+ rtclog2::EventStream* event_stream);
+ void EncodeRtcpPacketOutgoing(
+ rtc::ArrayView<const RtcEventRtcpPacketOutgoing*> batch,
+ rtclog2::EventStream* event_stream);
+ void EncodeRtpPacketIncoming(
+ const std::map<uint32_t, std::vector<const RtcEventRtpPacketIncoming*>>&
+ batch,
+ rtclog2::EventStream* event_stream);
+ void EncodeRtpPacketOutgoing(
+ const std::map<uint32_t, std::vector<const RtcEventRtpPacketOutgoing*>>&
+ 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);
+};
+
+} // namespace webrtc
+
+#endif // LOGGING_RTC_EVENT_LOG_ENCODER_RTC_EVENT_LOG_ENCODER_NEW_FORMAT_H_
diff --git a/third_party/libwebrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder_unittest.cc b/third_party/libwebrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder_unittest.cc
new file mode 100644
index 0000000000..7039fe7eb6
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder_unittest.cc
@@ -0,0 +1,1401 @@
+/*
+ * Copyright (c) 2017 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 <deque>
+#include <limits>
+#include <memory>
+#include <string>
+#include <tuple>
+
+#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/encoder/rtc_event_log_encoder_v3.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"
+#include "logging/rtc_event_log/events/rtc_event_audio_receive_stream_config.h"
+#include "logging/rtc_event_log/events/rtc_event_audio_send_stream_config.h"
+#include "logging/rtc_event_log/events/rtc_event_bwe_update_delay_based.h"
+#include "logging/rtc_event_log/events/rtc_event_bwe_update_loss_based.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"
+#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"
+#include "logging/rtc_event_log/events/rtc_event_rtp_packet_outgoing.h"
+#include "logging/rtc_event_log/events/rtc_event_video_receive_stream_config.h"
+#include "logging/rtc_event_log/events/rtc_event_video_send_stream_config.h"
+#include "logging/rtc_event_log/rtc_event_log_parser.h"
+#include "logging/rtc_event_log/rtc_event_log_unittest_helper.h"
+#include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor_config.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/bye.h"
+#include "modules/rtp_rtcp/source/rtp_header_extensions.h"
+#include "rtc_base/fake_clock.h"
+#include "rtc_base/random.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+class RtcEventLogEncoderTest
+ : public ::testing::TestWithParam<
+ std::tuple<int, RtcEventLog::EncodingType, size_t, bool>> {
+ protected:
+ RtcEventLogEncoderTest()
+ : seed_(std::get<0>(GetParam())),
+ prng_(seed_),
+ encoding_type_(std::get<1>(GetParam())),
+ event_count_(std::get<2>(GetParam())),
+ force_repeated_fields_(std::get<3>(GetParam())),
+ gen_(seed_ * 880001UL),
+ verifier_(encoding_type_) {
+ switch (encoding_type_) {
+ case RtcEventLog::EncodingType::Legacy:
+ encoder_ = std::make_unique<RtcEventLogEncoderLegacy>();
+ break;
+ case RtcEventLog::EncodingType::NewFormat:
+ encoder_ = std::make_unique<RtcEventLogEncoderNewFormat>();
+ break;
+ case RtcEventLog::EncodingType::ProtoFree:
+ encoder_ = std::make_unique<RtcEventLogEncoderV3>();
+ break;
+ }
+ encoded_ =
+ encoder_->EncodeLogStart(rtc::TimeMillis(), rtc::TimeUTCMillis());
+ }
+ ~RtcEventLogEncoderTest() override = default;
+
+ // ANA events have some optional fields, so we want to make sure that we get
+ // correct behavior both when all of the values are there, as well as when
+ // only some.
+ void TestRtcEventAudioNetworkAdaptation(
+ const std::vector<std::unique_ptr<RtcEventAudioNetworkAdaptation>>&);
+
+ template <typename EventType>
+ std::unique_ptr<EventType> NewRtpPacket(
+ uint32_t ssrc,
+ const RtpHeaderExtensionMap& extension_map);
+
+ template <typename ParsedType>
+ const std::vector<ParsedType>* GetRtpPacketsBySsrc(
+ const ParsedRtcEventLog* parsed_log,
+ uint32_t ssrc);
+
+ template <typename EventType, typename ParsedType>
+ void TestRtpPackets();
+
+ std::deque<std::unique_ptr<RtcEvent>> history_;
+ std::unique_ptr<RtcEventLogEncoder> encoder_;
+ ParsedRtcEventLog parsed_log_;
+ const uint64_t seed_;
+ Random prng_;
+ const RtcEventLog::EncodingType encoding_type_;
+ const size_t event_count_;
+ const bool force_repeated_fields_;
+ test::EventGenerator gen_;
+ test::EventVerifier verifier_;
+ std::string encoded_;
+};
+
+void RtcEventLogEncoderTest::TestRtcEventAudioNetworkAdaptation(
+ const std::vector<std::unique_ptr<RtcEventAudioNetworkAdaptation>>&
+ events) {
+ ASSERT_TRUE(history_.empty()) << "Function should be called once per test.";
+
+ for (auto& event : events) {
+ history_.push_back(event->Copy());
+ }
+
+ encoded_ += encoder_->EncodeBatch(history_.begin(), history_.end());
+ ASSERT_TRUE(parsed_log_.ParseString(encoded_).ok());
+ const auto& ana_configs = parsed_log_.audio_network_adaptation_events();
+
+ ASSERT_EQ(ana_configs.size(), events.size());
+ for (size_t i = 0; i < events.size(); ++i) {
+ verifier_.VerifyLoggedAudioNetworkAdaptationEvent(*events[i],
+ ana_configs[i]);
+ }
+}
+
+template <>
+std::unique_ptr<RtcEventRtpPacketIncoming> RtcEventLogEncoderTest::NewRtpPacket(
+ uint32_t ssrc,
+ const RtpHeaderExtensionMap& extension_map) {
+ return gen_.NewRtpPacketIncoming(ssrc, extension_map, false);
+}
+
+template <>
+std::unique_ptr<RtcEventRtpPacketOutgoing> RtcEventLogEncoderTest::NewRtpPacket(
+ uint32_t ssrc,
+ const RtpHeaderExtensionMap& extension_map) {
+ return gen_.NewRtpPacketOutgoing(ssrc, extension_map, false);
+}
+
+template <>
+const std::vector<LoggedRtpPacketIncoming>*
+RtcEventLogEncoderTest::GetRtpPacketsBySsrc(const ParsedRtcEventLog* parsed_log,
+ uint32_t ssrc) {
+ const auto& incoming_streams = parsed_log->incoming_rtp_packets_by_ssrc();
+ for (const auto& stream : incoming_streams) {
+ if (stream.ssrc == ssrc) {
+ return &stream.incoming_packets;
+ }
+ }
+ return nullptr;
+}
+
+template <>
+const std::vector<LoggedRtpPacketOutgoing>*
+RtcEventLogEncoderTest::GetRtpPacketsBySsrc(const ParsedRtcEventLog* parsed_log,
+ uint32_t ssrc) {
+ const auto& outgoing_streams = parsed_log->outgoing_rtp_packets_by_ssrc();
+ for (const auto& stream : outgoing_streams) {
+ if (stream.ssrc == ssrc) {
+ return &stream.outgoing_packets;
+ }
+ }
+ return nullptr;
+}
+
+template <typename EventType, typename ParsedType>
+void RtcEventLogEncoderTest::TestRtpPackets() {
+ // SSRCs will be randomly assigned out of this small pool, significant only
+ // in that it also covers such edge cases as SSRC = 0 and SSRC = 0xffffffff.
+ // The pool is intentionally small, so as to produce collisions.
+ const std::vector<uint32_t> kSsrcPool = {0x00000000, 0x12345678, 0xabcdef01,
+ 0xffffffff, 0x20171024, 0x19840730,
+ 0x19831230};
+
+ // TODO(terelius): Test extensions for legacy encoding, too.
+ RtpHeaderExtensionMap extension_map;
+ if (encoding_type_ != RtcEventLog::EncodingType::Legacy) {
+ extension_map = gen_.NewRtpHeaderExtensionMap(true);
+ }
+
+ // Simulate `event_count_` RTP packets, with SSRCs assigned randomly
+ // out of the small pool above.
+ std::map<uint32_t, std::vector<std::unique_ptr<EventType>>> events_by_ssrc;
+ for (size_t i = 0; i < event_count_; ++i) {
+ const uint32_t ssrc = kSsrcPool[prng_.Rand(kSsrcPool.size() - 1)];
+ std::unique_ptr<EventType> event =
+ (events_by_ssrc[ssrc].empty() || !force_repeated_fields_)
+ ? NewRtpPacket<EventType>(ssrc, extension_map)
+ : events_by_ssrc[ssrc][0]->Copy();
+ history_.push_back(event->Copy());
+ events_by_ssrc[ssrc].emplace_back(std::move(event));
+ }
+
+ // Encode and parse.
+ encoded_ += encoder_->EncodeBatch(history_.begin(), history_.end());
+ ASSERT_TRUE(parsed_log_.ParseString(encoded_).ok());
+
+ // For each SSRC, make sure the RTP packets associated with it to have been
+ // correctly encoded and parsed.
+ for (auto it = events_by_ssrc.begin(); it != events_by_ssrc.end(); ++it) {
+ const uint32_t ssrc = it->first;
+ const auto& original_packets = it->second;
+ const std::vector<ParsedType>* parsed_rtp_packets =
+ GetRtpPacketsBySsrc<ParsedType>(&parsed_log_, ssrc);
+ ASSERT_NE(parsed_rtp_packets, nullptr);
+ ASSERT_EQ(original_packets.size(), parsed_rtp_packets->size());
+ for (size_t i = 0; i < original_packets.size(); ++i) {
+ verifier_.VerifyLoggedRtpPacket<EventType, ParsedType>(
+ *original_packets[i], (*parsed_rtp_packets)[i]);
+ }
+ }
+}
+
+TEST_P(RtcEventLogEncoderTest, RtcEventAlrState) {
+ std::vector<std::unique_ptr<RtcEventAlrState>> events(event_count_);
+ for (size_t i = 0; i < event_count_; ++i) {
+ events[i] = (i == 0 || !force_repeated_fields_) ? gen_.NewAlrState()
+ : events[0]->Copy();
+ history_.push_back(events[i]->Copy());
+ }
+
+ encoded_ += encoder_->EncodeBatch(history_.begin(), history_.end());
+ ASSERT_TRUE(parsed_log_.ParseString(encoded_).ok());
+ const auto& alr_state_events = parsed_log_.alr_state_events();
+
+ ASSERT_EQ(alr_state_events.size(), event_count_);
+ for (size_t i = 0; i < event_count_; ++i) {
+ verifier_.VerifyLoggedAlrStateEvent(*events[i], alr_state_events[i]);
+ }
+}
+
+TEST_P(RtcEventLogEncoderTest, RtcEventRouteChange) {
+ if (encoding_type_ == RtcEventLog::EncodingType::Legacy) {
+ 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());
+ }
+
+ encoded_ += encoder_->EncodeBatch(history_.begin(), history_.end());
+ ASSERT_TRUE(parsed_log_.ParseString(encoded_).ok());
+ 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, RtcEventRemoteEstimate) {
+ std::vector<std::unique_ptr<RtcEventRemoteEstimate>> events(event_count_);
+ for (size_t i = 0; i < event_count_; ++i) {
+ events[i] = (i == 0 || !force_repeated_fields_)
+ ? gen_.NewRemoteEstimate()
+ : std::make_unique<RtcEventRemoteEstimate>(*events[0]);
+ history_.push_back(std::make_unique<RtcEventRemoteEstimate>(*events[i]));
+ }
+
+ encoded_ += encoder_->EncodeBatch(history_.begin(), history_.end());
+ ASSERT_TRUE(parsed_log_.ParseString(encoded_).ok());
+ const auto& parsed_events = parsed_log_.remote_estimate_events();
+
+ ASSERT_EQ(parsed_events.size(), event_count_);
+ for (size_t i = 0; i < event_count_; ++i) {
+ verifier_.VerifyLoggedRemoteEstimateEvent(*events[i], parsed_events[i]);
+ }
+}
+
+TEST_P(RtcEventLogEncoderTest, RtcEventAudioNetworkAdaptationBitrate) {
+ std::vector<std::unique_ptr<RtcEventAudioNetworkAdaptation>> events(
+ event_count_);
+ for (size_t i = 0; i < event_count_; ++i) {
+ if (i == 0 || !force_repeated_fields_) {
+ auto runtime_config = std::make_unique<AudioEncoderRuntimeConfig>();
+ const int bitrate_bps = rtc::checked_cast<int>(
+ prng_.Rand(0, std::numeric_limits<int32_t>::max()));
+ runtime_config->bitrate_bps = bitrate_bps;
+ events[i] = std::make_unique<RtcEventAudioNetworkAdaptation>(
+ std::move(runtime_config));
+ } else {
+ events[i] = events[0]->Copy();
+ }
+ }
+ TestRtcEventAudioNetworkAdaptation(events);
+}
+
+TEST_P(RtcEventLogEncoderTest, RtcEventAudioNetworkAdaptationFrameLength) {
+ std::vector<std::unique_ptr<RtcEventAudioNetworkAdaptation>> events(
+ event_count_);
+ for (size_t i = 0; i < event_count_; ++i) {
+ if (i == 0 || !force_repeated_fields_) {
+ auto runtime_config = std::make_unique<AudioEncoderRuntimeConfig>();
+ const int frame_length_ms = prng_.Rand(1, 1000);
+ runtime_config->frame_length_ms = frame_length_ms;
+ events[i] = std::make_unique<RtcEventAudioNetworkAdaptation>(
+ std::move(runtime_config));
+ } else {
+ events[i] = events[0]->Copy();
+ }
+ }
+ TestRtcEventAudioNetworkAdaptation(events);
+}
+
+TEST_P(RtcEventLogEncoderTest, RtcEventAudioNetworkAdaptationPacketLoss) {
+ std::vector<std::unique_ptr<RtcEventAudioNetworkAdaptation>> events(
+ event_count_);
+ for (size_t i = 0; i < event_count_; ++i) {
+ if (i == 0 || !force_repeated_fields_) {
+ // To simplify the test, we just check powers of two.
+ const float plr = std::pow(0.5f, prng_.Rand(1, 8));
+ auto runtime_config = std::make_unique<AudioEncoderRuntimeConfig>();
+ runtime_config->uplink_packet_loss_fraction = plr;
+ events[i] = std::make_unique<RtcEventAudioNetworkAdaptation>(
+ std::move(runtime_config));
+ } else {
+ events[i] = events[0]->Copy();
+ }
+ }
+ TestRtcEventAudioNetworkAdaptation(events);
+}
+
+TEST_P(RtcEventLogEncoderTest, RtcEventAudioNetworkAdaptationFec) {
+ std::vector<std::unique_ptr<RtcEventAudioNetworkAdaptation>> events(
+ event_count_);
+ for (size_t i = 0; i < event_count_; ++i) {
+ if (i == 0 || !force_repeated_fields_) {
+ auto runtime_config = std::make_unique<AudioEncoderRuntimeConfig>();
+ runtime_config->enable_fec = prng_.Rand<bool>();
+ events[i] = std::make_unique<RtcEventAudioNetworkAdaptation>(
+ std::move(runtime_config));
+ } else {
+ events[i] = events[0]->Copy();
+ }
+ }
+ TestRtcEventAudioNetworkAdaptation(events);
+}
+
+TEST_P(RtcEventLogEncoderTest, RtcEventAudioNetworkAdaptationDtx) {
+ std::vector<std::unique_ptr<RtcEventAudioNetworkAdaptation>> events(
+ event_count_);
+ for (size_t i = 0; i < event_count_; ++i) {
+ if (i == 0 || !force_repeated_fields_) {
+ auto runtime_config = std::make_unique<AudioEncoderRuntimeConfig>();
+ runtime_config->enable_dtx = prng_.Rand<bool>();
+ events[i] = std::make_unique<RtcEventAudioNetworkAdaptation>(
+ std::move(runtime_config));
+ } else {
+ events[i] = events[0]->Copy();
+ }
+ }
+ TestRtcEventAudioNetworkAdaptation(events);
+}
+
+TEST_P(RtcEventLogEncoderTest, RtcEventAudioNetworkAdaptationChannels) {
+ std::vector<std::unique_ptr<RtcEventAudioNetworkAdaptation>> events(
+ event_count_);
+ for (size_t i = 0; i < event_count_; ++i) {
+ if (i == 0 || !force_repeated_fields_) {
+ auto runtime_config = std::make_unique<AudioEncoderRuntimeConfig>();
+ runtime_config->num_channels = prng_.Rand(1, 2);
+ events[i] = std::make_unique<RtcEventAudioNetworkAdaptation>(
+ std::move(runtime_config));
+ } else {
+ events[i] = events[0]->Copy();
+ }
+ }
+ TestRtcEventAudioNetworkAdaptation(events);
+}
+
+TEST_P(RtcEventLogEncoderTest, RtcEventAudioNetworkAdaptationAll) {
+ std::vector<std::unique_ptr<RtcEventAudioNetworkAdaptation>> events(
+ event_count_);
+ for (size_t i = 0; i < event_count_; ++i) {
+ if (i == 0 || !force_repeated_fields_) {
+ auto runtime_config = std::make_unique<AudioEncoderRuntimeConfig>();
+ runtime_config->bitrate_bps = rtc::checked_cast<int>(
+ prng_.Rand(0, std::numeric_limits<int32_t>::max()));
+ runtime_config->frame_length_ms = prng_.Rand(1, 1000);
+ runtime_config->uplink_packet_loss_fraction =
+ std::pow(0.5f, prng_.Rand(1, 8));
+ runtime_config->enable_fec = prng_.Rand<bool>();
+ runtime_config->enable_dtx = prng_.Rand<bool>();
+ runtime_config->num_channels = prng_.Rand(1, 2);
+ events[i] = std::make_unique<RtcEventAudioNetworkAdaptation>(
+ std::move(runtime_config));
+ } else {
+ events[i] = events[0]->Copy();
+ }
+ }
+ TestRtcEventAudioNetworkAdaptation(events);
+}
+
+TEST_P(RtcEventLogEncoderTest, RtcEventAudioPlayout) {
+ // SSRCs will be randomly assigned out of this small pool, significant only
+ // in that it also covers such edge cases as SSRC = 0 and SSRC = 0xffffffff.
+ // The pool is intentionally small, so as to produce collisions.
+ const std::vector<uint32_t> kSsrcPool = {0x00000000, 0x12345678, 0xabcdef01,
+ 0xffffffff, 0x20171024, 0x19840730,
+ 0x19831230};
+
+ std::map<uint32_t, std::vector<std::unique_ptr<RtcEventAudioPlayout>>>
+ original_events_by_ssrc;
+ for (size_t i = 0; i < event_count_; ++i) {
+ const uint32_t ssrc = kSsrcPool[prng_.Rand(kSsrcPool.size() - 1)];
+ std::unique_ptr<RtcEventAudioPlayout> event =
+ (original_events_by_ssrc[ssrc].empty() || !force_repeated_fields_)
+ ? gen_.NewAudioPlayout(ssrc)
+ : original_events_by_ssrc[ssrc][0]->Copy();
+ history_.push_back(event->Copy());
+ original_events_by_ssrc[ssrc].push_back(std::move(event));
+ }
+
+ encoded_ += encoder_->EncodeBatch(history_.begin(), history_.end());
+ ASSERT_TRUE(parsed_log_.ParseString(encoded_).ok());
+
+ const auto& parsed_playout_events_by_ssrc =
+ parsed_log_.audio_playout_events();
+
+ // Same number of distinct SSRCs.
+ ASSERT_EQ(parsed_playout_events_by_ssrc.size(),
+ original_events_by_ssrc.size());
+
+ for (auto& original_event_it : original_events_by_ssrc) {
+ const uint32_t ssrc = original_event_it.first;
+ const auto& original_playout_events = original_event_it.second;
+
+ const auto& parsed_event_it = parsed_playout_events_by_ssrc.find(ssrc);
+ ASSERT_TRUE(parsed_event_it != parsed_playout_events_by_ssrc.end());
+ const auto& parsed_playout_events = parsed_event_it->second;
+
+ // Same number playout events for the SSRC under examination.
+ ASSERT_EQ(original_playout_events.size(), parsed_playout_events.size());
+
+ for (size_t i = 0; i < original_playout_events.size(); ++i) {
+ verifier_.VerifyLoggedAudioPlayoutEvent(*original_playout_events[i],
+ parsed_playout_events[i]);
+ }
+ }
+}
+
+TEST_P(RtcEventLogEncoderTest, RtcEventNetEqSetMinimumDelayDecoded) {
+ // SSRCs will be randomly assigned out of this small pool, significant only
+ // in that it also covers such edge cases as SSRC = 0 and SSRC = 0xffffffff.
+ // The pool is intentionally small, so as to produce collisions.
+ const std::vector<uint32_t> kSsrcPool = {0x00000000, 0x12345678, 0xabcdef01,
+ 0xffffffff, 0x20171024, 0x19840730,
+ 0x19831230};
+ std::map<uint32_t, std::vector<std::unique_ptr<RtcEventNetEqSetMinimumDelay>>>
+ original_events_by_ssrc;
+ for (size_t i = 0; i < event_count_; ++i) {
+ const uint32_t ssrc = kSsrcPool[prng_.Rand(kSsrcPool.size() - 1)];
+ std::unique_ptr<RtcEventNetEqSetMinimumDelay> event =
+ (original_events_by_ssrc[ssrc].empty() || !force_repeated_fields_)
+ ? gen_.NewNetEqSetMinimumDelay(ssrc)
+ : original_events_by_ssrc[ssrc][0]->Copy();
+ history_.push_back(event->Copy());
+ original_events_by_ssrc[ssrc].push_back(std::move(event));
+ }
+
+ encoded_ += encoder_->EncodeBatch(history_.begin(), history_.end());
+ ASSERT_TRUE(parsed_log_.ParseString(encoded_).ok());
+
+ const auto& parsed_neteq_set_minimum_delay_events_by_ssrc =
+ parsed_log_.neteq_set_minimum_delay_events();
+
+ if (encoding_type_ == RtcEventLog::EncodingType::Legacy) {
+ ASSERT_EQ(parsed_neteq_set_minimum_delay_events_by_ssrc.size(), 0u);
+ return;
+ }
+
+ // Same number of distinct SSRCs.
+ ASSERT_EQ(parsed_neteq_set_minimum_delay_events_by_ssrc.size(),
+ original_events_by_ssrc.size());
+
+ for (auto& original_event_it : original_events_by_ssrc) {
+ const uint32_t ssrc = original_event_it.first;
+ const auto& original_neteq_set_minimum_delay_events =
+ original_event_it.second;
+
+ const auto& parsed_event_it =
+ parsed_neteq_set_minimum_delay_events_by_ssrc.find(ssrc);
+ ASSERT_TRUE(parsed_event_it !=
+ parsed_neteq_set_minimum_delay_events_by_ssrc.end());
+ const auto& parsed_neteq_set_minimum_delay_events = parsed_event_it->second;
+
+ // Same number playout events for the SSRC under examination.
+ ASSERT_EQ(original_neteq_set_minimum_delay_events.size(),
+ parsed_neteq_set_minimum_delay_events.size());
+
+ for (size_t i = 0; i < original_neteq_set_minimum_delay_events.size();
+ ++i) {
+ verifier_.VerifyLoggedNetEqSetMinimumDelay(
+ *original_neteq_set_minimum_delay_events[i],
+ parsed_neteq_set_minimum_delay_events[i]);
+ }
+ }
+}
+
+// TODO(eladalon/terelius): Test with multiple events in the batch.
+TEST_P(RtcEventLogEncoderTest, RtcEventAudioReceiveStreamConfig) {
+ uint32_t ssrc = prng_.Rand<uint32_t>();
+ RtpHeaderExtensionMap extensions = gen_.NewRtpHeaderExtensionMap();
+ std::unique_ptr<RtcEventAudioReceiveStreamConfig> event =
+ gen_.NewAudioReceiveStreamConfig(ssrc, extensions);
+ history_.push_back(event->Copy());
+
+ encoded_ += encoder_->EncodeBatch(history_.begin(), history_.end());
+ ASSERT_TRUE(parsed_log_.ParseString(encoded_).ok());
+ const auto& audio_recv_configs = parsed_log_.audio_recv_configs();
+
+ ASSERT_EQ(audio_recv_configs.size(), 1u);
+ verifier_.VerifyLoggedAudioRecvConfig(*event, audio_recv_configs[0]);
+}
+
+// TODO(eladalon/terelius): Test with multiple events in the batch.
+TEST_P(RtcEventLogEncoderTest, RtcEventAudioSendStreamConfig) {
+ uint32_t ssrc = prng_.Rand<uint32_t>();
+ RtpHeaderExtensionMap extensions = gen_.NewRtpHeaderExtensionMap();
+ std::unique_ptr<RtcEventAudioSendStreamConfig> event =
+ gen_.NewAudioSendStreamConfig(ssrc, extensions);
+ history_.push_back(event->Copy());
+
+ encoded_ += encoder_->EncodeBatch(history_.begin(), history_.end());
+ ASSERT_TRUE(parsed_log_.ParseString(encoded_).ok());
+ const auto& audio_send_configs = parsed_log_.audio_send_configs();
+
+ ASSERT_EQ(audio_send_configs.size(), 1u);
+ verifier_.VerifyLoggedAudioSendConfig(*event, audio_send_configs[0]);
+}
+
+TEST_P(RtcEventLogEncoderTest, RtcEventBweUpdateDelayBased) {
+ std::vector<std::unique_ptr<RtcEventBweUpdateDelayBased>> events(
+ event_count_);
+ for (size_t i = 0; i < event_count_; ++i) {
+ events[i] = (i == 0 || !force_repeated_fields_)
+ ? gen_.NewBweUpdateDelayBased()
+ : events[0]->Copy();
+ history_.push_back(events[i]->Copy());
+ }
+
+ encoded_ += encoder_->EncodeBatch(history_.begin(), history_.end());
+ ASSERT_TRUE(parsed_log_.ParseString(encoded_).ok());
+
+ const auto& bwe_delay_updates = parsed_log_.bwe_delay_updates();
+ ASSERT_EQ(bwe_delay_updates.size(), event_count_);
+
+ for (size_t i = 0; i < event_count_; ++i) {
+ verifier_.VerifyLoggedBweDelayBasedUpdate(*events[i], bwe_delay_updates[i]);
+ }
+}
+
+TEST_P(RtcEventLogEncoderTest, RtcEventBweUpdateLossBased) {
+ std::vector<std::unique_ptr<RtcEventBweUpdateLossBased>> events(event_count_);
+ for (size_t i = 0; i < event_count_; ++i) {
+ events[i] = (i == 0 || !force_repeated_fields_)
+ ? gen_.NewBweUpdateLossBased()
+ : events[0]->Copy();
+ history_.push_back(events[i]->Copy());
+ }
+
+ encoded_ += encoder_->EncodeBatch(history_.begin(), history_.end());
+ ASSERT_TRUE(parsed_log_.ParseString(encoded_).ok());
+
+ const auto& bwe_loss_updates = parsed_log_.bwe_loss_updates();
+ ASSERT_EQ(bwe_loss_updates.size(), event_count_);
+
+ for (size_t i = 0; i < event_count_; ++i) {
+ verifier_.VerifyLoggedBweLossBasedUpdate(*events[i], bwe_loss_updates[i]);
+ }
+}
+
+TEST_P(RtcEventLogEncoderTest, RtcEventGenericPacketReceived) {
+ if (encoding_type_ == RtcEventLog::EncodingType::Legacy) {
+ 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());
+ }
+
+ encoded_ += encoder_->EncodeBatch(history_.begin(), history_.end());
+ ASSERT_TRUE(parsed_log_.ParseString(encoded_).ok());
+
+ 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 (encoding_type_ == RtcEventLog::EncodingType::Legacy) {
+ 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());
+ }
+
+ encoded_ += encoder_->EncodeBatch(history_.begin(), history_.end());
+ ASSERT_TRUE(parsed_log_.ParseString(encoded_).ok());
+
+ 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 (encoding_type_ == RtcEventLog::EncodingType::Legacy) {
+ 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());
+ }
+
+ encoded_ += encoder_->EncodeBatch(history_.begin(), history_.end());
+ ASSERT_TRUE(parsed_log_.ParseString(encoded_).ok());
+
+ 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) {
+ events[i] = (i == 0 || !force_repeated_fields_)
+ ? gen_.NewDtlsTransportState()
+ : events[0]->Copy();
+ history_.push_back(events[i]->Copy());
+ }
+
+ encoded_ += encoder_->EncodeBatch(history_.begin(), history_.end());
+ ASSERT_TRUE(parsed_log_.ParseString(encoded_).ok());
+
+ const auto& dtls_transport_states = parsed_log_.dtls_transport_states();
+ if (encoding_type_ == RtcEventLog::EncodingType::Legacy) {
+ ASSERT_EQ(dtls_transport_states.size(), 0u);
+ return;
+ }
+
+ ASSERT_EQ(dtls_transport_states.size(), event_count_);
+ for (size_t i = 0; i < event_count_; ++i) {
+ verifier_.VerifyLoggedDtlsTransportState(*events[i],
+ dtls_transport_states[i]);
+ }
+}
+
+TEST_P(RtcEventLogEncoderTest, RtcEventDtlsWritableState) {
+ std::vector<std::unique_ptr<RtcEventDtlsWritableState>> events(event_count_);
+ for (size_t i = 0; i < event_count_; ++i) {
+ events[i] = (i == 0 || !force_repeated_fields_)
+ ? gen_.NewDtlsWritableState()
+ : events[0]->Copy();
+ history_.push_back(events[i]->Copy());
+ }
+
+ encoded_ += encoder_->EncodeBatch(history_.begin(), history_.end());
+ ASSERT_TRUE(parsed_log_.ParseString(encoded_).ok());
+
+ const auto& dtls_writable_states = parsed_log_.dtls_writable_states();
+ if (encoding_type_ == RtcEventLog::EncodingType::Legacy) {
+ ASSERT_EQ(dtls_writable_states.size(), 0u);
+ return;
+ }
+
+ ASSERT_EQ(dtls_writable_states.size(), event_count_);
+
+ for (size_t i = 0; i < event_count_; ++i) {
+ verifier_.VerifyLoggedDtlsWritableState(*events[i],
+ dtls_writable_states[i]);
+ }
+}
+
+TEST_P(RtcEventLogEncoderTest, RtcEventFrameDecoded) {
+ // SSRCs will be randomly assigned out of this small pool, significant only
+ // in that it also covers such edge cases as SSRC = 0 and SSRC = 0xffffffff.
+ // The pool is intentionally small, so as to produce collisions.
+ const std::vector<uint32_t> kSsrcPool = {0x00000000, 0x12345678, 0xabcdef01,
+ 0xffffffff, 0x20171024, 0x19840730,
+ 0x19831230};
+
+ std::map<uint32_t, std::vector<std::unique_ptr<RtcEventFrameDecoded>>>
+ original_events_by_ssrc;
+ for (size_t i = 0; i < event_count_; ++i) {
+ const uint32_t ssrc = kSsrcPool[prng_.Rand(kSsrcPool.size() - 1)];
+ std::unique_ptr<RtcEventFrameDecoded> event =
+ (original_events_by_ssrc[ssrc].empty() || !force_repeated_fields_)
+ ? gen_.NewFrameDecodedEvent(ssrc)
+ : original_events_by_ssrc[ssrc][0]->Copy();
+ history_.push_back(event->Copy());
+ original_events_by_ssrc[ssrc].push_back(std::move(event));
+ }
+
+ encoded_ += encoder_->EncodeBatch(history_.begin(), history_.end());
+ auto status = parsed_log_.ParseString(encoded_);
+ if (!status.ok())
+ RTC_LOG(LS_ERROR) << status.message();
+ ASSERT_TRUE(status.ok());
+
+ const auto& decoded_frames_by_ssrc = parsed_log_.decoded_frames();
+ if (encoding_type_ == RtcEventLog::EncodingType::Legacy) {
+ ASSERT_EQ(decoded_frames_by_ssrc.size(), 0u);
+ return;
+ }
+
+ // Same number of distinct SSRCs.
+ ASSERT_EQ(decoded_frames_by_ssrc.size(), original_events_by_ssrc.size());
+
+ for (const auto& original_event_it : original_events_by_ssrc) {
+ const uint32_t ssrc = original_event_it.first;
+ const std::vector<std::unique_ptr<RtcEventFrameDecoded>>& original_frames =
+ original_event_it.second;
+
+ const auto& parsed_event_it = decoded_frames_by_ssrc.find(ssrc);
+ ASSERT_TRUE(parsed_event_it != decoded_frames_by_ssrc.end());
+ const std::vector<LoggedFrameDecoded>& parsed_frames =
+ parsed_event_it->second;
+
+ // Same number events for the SSRC under examination.
+ ASSERT_EQ(original_frames.size(), parsed_frames.size());
+
+ for (size_t i = 0; i < original_frames.size(); ++i) {
+ verifier_.VerifyLoggedFrameDecoded(*original_frames[i], parsed_frames[i]);
+ }
+ }
+}
+
+// TODO(eladalon/terelius): Test with multiple events in the batch.
+TEST_P(RtcEventLogEncoderTest, RtcEventIceCandidatePairConfig) {
+ std::unique_ptr<RtcEventIceCandidatePairConfig> event =
+ gen_.NewIceCandidatePairConfig();
+ history_.push_back(event->Copy());
+
+ encoded_ += encoder_->EncodeBatch(history_.begin(), history_.end());
+ ASSERT_TRUE(parsed_log_.ParseString(encoded_).ok());
+ const auto& ice_candidate_pair_configs =
+ parsed_log_.ice_candidate_pair_configs();
+
+ ASSERT_EQ(ice_candidate_pair_configs.size(), 1u);
+ verifier_.VerifyLoggedIceCandidatePairConfig(*event,
+ ice_candidate_pair_configs[0]);
+}
+
+// TODO(eladalon/terelius): Test with multiple events in the batch.
+TEST_P(RtcEventLogEncoderTest, RtcEventIceCandidatePair) {
+ std::unique_ptr<RtcEventIceCandidatePair> event = gen_.NewIceCandidatePair();
+ history_.push_back(event->Copy());
+
+ encoded_ += encoder_->EncodeBatch(history_.begin(), history_.end());
+ ASSERT_TRUE(parsed_log_.ParseString(encoded_).ok());
+ const auto& ice_candidate_pair_events =
+ parsed_log_.ice_candidate_pair_events();
+
+ ASSERT_EQ(ice_candidate_pair_events.size(), 1u);
+ verifier_.VerifyLoggedIceCandidatePairEvent(*event,
+ ice_candidate_pair_events[0]);
+}
+
+TEST_P(RtcEventLogEncoderTest, RtcEventLoggingStarted) {
+ const int64_t timestamp_ms = prng_.Rand(1'000'000'000);
+ const int64_t utc_time_ms = prng_.Rand(1'000'000'000);
+
+ // Overwrite the previously encoded LogStart event.
+ encoded_ = encoder_->EncodeLogStart(timestamp_ms * 1000, utc_time_ms * 1000);
+ ASSERT_TRUE(parsed_log_.ParseString(encoded_).ok());
+ const auto& start_log_events = parsed_log_.start_log_events();
+
+ ASSERT_EQ(start_log_events.size(), 1u);
+ verifier_.VerifyLoggedStartEvent(timestamp_ms * 1000, utc_time_ms * 1000,
+ start_log_events[0]);
+}
+
+TEST_P(RtcEventLogEncoderTest, RtcEventLoggingStopped) {
+ const int64_t start_timestamp_ms = prng_.Rand(1'000'000'000);
+ const int64_t start_utc_time_ms = prng_.Rand(1'000'000'000);
+
+ // Overwrite the previously encoded LogStart event.
+ encoded_ = encoder_->EncodeLogStart(start_timestamp_ms * 1000,
+ start_utc_time_ms * 1000);
+
+ const int64_t stop_timestamp_ms =
+ prng_.Rand(start_timestamp_ms, 2'000'000'000);
+ encoded_ += encoder_->EncodeLogEnd(stop_timestamp_ms * 1000);
+ ASSERT_TRUE(parsed_log_.ParseString(encoded_).ok());
+ const auto& stop_log_events = parsed_log_.stop_log_events();
+
+ ASSERT_EQ(stop_log_events.size(), 1u);
+ verifier_.VerifyLoggedStopEvent(stop_timestamp_ms * 1000, stop_log_events[0]);
+}
+
+// TODO(eladalon/terelius): Test with multiple events in the batch.
+TEST_P(RtcEventLogEncoderTest, RtcEventProbeClusterCreated) {
+ std::unique_ptr<RtcEventProbeClusterCreated> event =
+ gen_.NewProbeClusterCreated();
+ history_.push_back(event->Copy());
+
+ encoded_ += encoder_->EncodeBatch(history_.begin(), history_.end());
+ ASSERT_TRUE(parsed_log_.ParseString(encoded_).ok());
+ const auto& bwe_probe_cluster_created_events =
+ parsed_log_.bwe_probe_cluster_created_events();
+
+ ASSERT_EQ(bwe_probe_cluster_created_events.size(), 1u);
+ verifier_.VerifyLoggedBweProbeClusterCreatedEvent(
+ *event, bwe_probe_cluster_created_events[0]);
+}
+
+// TODO(eladalon/terelius): Test with multiple events in the batch.
+TEST_P(RtcEventLogEncoderTest, RtcEventProbeResultFailure) {
+ std::unique_ptr<RtcEventProbeResultFailure> event =
+ gen_.NewProbeResultFailure();
+ history_.push_back(event->Copy());
+
+ encoded_ += encoder_->EncodeBatch(history_.begin(), history_.end());
+ ASSERT_TRUE(parsed_log_.ParseString(encoded_).ok());
+ const auto& bwe_probe_failure_events = parsed_log_.bwe_probe_failure_events();
+
+ ASSERT_EQ(bwe_probe_failure_events.size(), 1u);
+ verifier_.VerifyLoggedBweProbeFailureEvent(*event,
+ bwe_probe_failure_events[0]);
+}
+
+// TODO(eladalon/terelius): Test with multiple events in the batch.
+TEST_P(RtcEventLogEncoderTest, RtcEventProbeResultSuccess) {
+ std::unique_ptr<RtcEventProbeResultSuccess> event =
+ gen_.NewProbeResultSuccess();
+ history_.push_back(event->Copy());
+
+ encoded_ += encoder_->EncodeBatch(history_.begin(), history_.end());
+ ASSERT_TRUE(parsed_log_.ParseString(encoded_).ok());
+ const auto& bwe_probe_success_events = parsed_log_.bwe_probe_success_events();
+
+ ASSERT_EQ(bwe_probe_success_events.size(), 1u);
+ verifier_.VerifyLoggedBweProbeSuccessEvent(*event,
+ bwe_probe_success_events[0]);
+}
+
+TEST_P(RtcEventLogEncoderTest, RtcEventRtcpPacketIncoming) {
+ if (force_repeated_fields_) {
+ // RTCP packets maybe delivered twice (once for audio and once for video).
+ // As a work around, we're removing duplicates in the parser.
+ return;
+ }
+
+ std::vector<std::unique_ptr<RtcEventRtcpPacketIncoming>> events(event_count_);
+ for (size_t i = 0; i < event_count_; ++i) {
+ events[i] = (i == 0 || !force_repeated_fields_)
+ ? gen_.NewRtcpPacketIncoming()
+ : events[0]->Copy();
+ history_.push_back(events[i]->Copy());
+ }
+
+ encoded_ += encoder_->EncodeBatch(history_.begin(), history_.end());
+ ASSERT_TRUE(parsed_log_.ParseString(encoded_).ok());
+
+ const auto& incoming_rtcp_packets = parsed_log_.incoming_rtcp_packets();
+ ASSERT_EQ(incoming_rtcp_packets.size(), event_count_);
+
+ for (size_t i = 0; i < event_count_; ++i) {
+ verifier_.VerifyLoggedRtcpPacketIncoming(*events[i],
+ incoming_rtcp_packets[i]);
+ }
+}
+
+TEST_P(RtcEventLogEncoderTest, RtcEventRtcpPacketOutgoing) {
+ std::vector<std::unique_ptr<RtcEventRtcpPacketOutgoing>> events(event_count_);
+ for (size_t i = 0; i < event_count_; ++i) {
+ events[i] = (i == 0 || !force_repeated_fields_)
+ ? gen_.NewRtcpPacketOutgoing()
+ : events[0]->Copy();
+ history_.push_back(events[i]->Copy());
+ }
+
+ encoded_ += encoder_->EncodeBatch(history_.begin(), history_.end());
+ ASSERT_TRUE(parsed_log_.ParseString(encoded_).ok());
+
+ const auto& outgoing_rtcp_packets = parsed_log_.outgoing_rtcp_packets();
+ ASSERT_EQ(outgoing_rtcp_packets.size(), event_count_);
+
+ for (size_t i = 0; i < event_count_; ++i) {
+ verifier_.VerifyLoggedRtcpPacketOutgoing(*events[i],
+ outgoing_rtcp_packets[i]);
+ }
+}
+
+TEST_P(RtcEventLogEncoderTest, RtcEventRtcpReceiverReport) {
+ if (force_repeated_fields_) {
+ return;
+ }
+
+ rtc::ScopedFakeClock fake_clock;
+ fake_clock.SetTime(Timestamp::Millis(prng_.Rand<uint32_t>()));
+
+ for (auto direction : {kIncomingPacket, kOutgoingPacket}) {
+ std::vector<rtcp::ReceiverReport> events(event_count_);
+ std::vector<int64_t> timestamps_ms(event_count_);
+ for (size_t i = 0; i < event_count_; ++i) {
+ timestamps_ms[i] = rtc::TimeMillis();
+ events[i] = gen_.NewReceiverReport();
+ rtc::Buffer buffer = events[i].Build();
+ if (direction == kIncomingPacket) {
+ history_.push_back(
+ std::make_unique<RtcEventRtcpPacketIncoming>(buffer));
+ } else {
+ history_.push_back(
+ std::make_unique<RtcEventRtcpPacketOutgoing>(buffer));
+ }
+ fake_clock.AdvanceTime(TimeDelta::Millis(prng_.Rand(0, 1000)));
+ }
+
+ encoded_ += encoder_->EncodeBatch(history_.begin(), history_.end());
+ ASSERT_TRUE(parsed_log_.ParseString(encoded_).ok());
+
+ const auto& receiver_reports = parsed_log_.receiver_reports(direction);
+ ASSERT_EQ(receiver_reports.size(), event_count_);
+
+ for (size_t i = 0; i < event_count_; ++i) {
+ verifier_.VerifyLoggedReceiverReport(timestamps_ms[i], events[i],
+ receiver_reports[i]);
+ }
+ }
+}
+
+TEST_P(RtcEventLogEncoderTest, RtcEventRtcpSenderReport) {
+ if (force_repeated_fields_) {
+ return;
+ }
+
+ rtc::ScopedFakeClock fake_clock;
+ fake_clock.SetTime(Timestamp::Millis(prng_.Rand<uint32_t>()));
+
+ for (auto direction : {kIncomingPacket, kOutgoingPacket}) {
+ std::vector<rtcp::SenderReport> events(event_count_);
+ std::vector<int64_t> timestamps_ms(event_count_);
+ for (size_t i = 0; i < event_count_; ++i) {
+ timestamps_ms[i] = rtc::TimeMillis();
+ events[i] = gen_.NewSenderReport();
+ rtc::Buffer buffer = events[i].Build();
+ if (direction == kIncomingPacket) {
+ history_.push_back(
+ std::make_unique<RtcEventRtcpPacketIncoming>(buffer));
+ } else {
+ history_.push_back(
+ std::make_unique<RtcEventRtcpPacketOutgoing>(buffer));
+ }
+ fake_clock.AdvanceTime(TimeDelta::Millis(prng_.Rand(0, 1000)));
+ }
+
+ encoded_ += encoder_->EncodeBatch(history_.begin(), history_.end());
+ ASSERT_TRUE(parsed_log_.ParseString(encoded_).ok());
+
+ const auto& sender_reports = parsed_log_.sender_reports(direction);
+ ASSERT_EQ(sender_reports.size(), event_count_);
+
+ for (size_t i = 0; i < event_count_; ++i) {
+ verifier_.VerifyLoggedSenderReport(timestamps_ms[i], events[i],
+ sender_reports[i]);
+ }
+ }
+}
+
+TEST_P(RtcEventLogEncoderTest, RtcEventRtcpExtendedReports) {
+ if (force_repeated_fields_) {
+ return;
+ }
+
+ rtc::ScopedFakeClock fake_clock;
+ fake_clock.SetTime(Timestamp::Millis(prng_.Rand<uint32_t>()));
+
+ for (auto direction : {kIncomingPacket, kOutgoingPacket}) {
+ std::vector<rtcp::ExtendedReports> events(event_count_);
+ std::vector<int64_t> timestamps_ms(event_count_);
+ for (size_t i = 0; i < event_count_; ++i) {
+ timestamps_ms[i] = rtc::TimeMillis();
+ events[i] = gen_.NewExtendedReports();
+ rtc::Buffer buffer = events[i].Build();
+ if (direction == kIncomingPacket) {
+ history_.push_back(
+ std::make_unique<RtcEventRtcpPacketIncoming>(buffer));
+ } else {
+ history_.push_back(
+ std::make_unique<RtcEventRtcpPacketOutgoing>(buffer));
+ }
+ fake_clock.AdvanceTime(TimeDelta::Millis(prng_.Rand(0, 1000)));
+ }
+
+ encoded_ += encoder_->EncodeBatch(history_.begin(), history_.end());
+ ASSERT_TRUE(parsed_log_.ParseString(encoded_).ok());
+
+ const auto& extended_reports = parsed_log_.extended_reports(direction);
+ ASSERT_EQ(extended_reports.size(), event_count_);
+
+ for (size_t i = 0; i < event_count_; ++i) {
+ verifier_.VerifyLoggedExtendedReports(timestamps_ms[i], events[i],
+ extended_reports[i]);
+ }
+ }
+}
+
+TEST_P(RtcEventLogEncoderTest, RtcEventRtcpFir) {
+ if (force_repeated_fields_) {
+ return;
+ }
+
+ rtc::ScopedFakeClock fake_clock;
+ fake_clock.SetTime(Timestamp::Millis(prng_.Rand<uint32_t>()));
+
+ for (auto direction : {kIncomingPacket, kOutgoingPacket}) {
+ std::vector<rtcp::Fir> events(event_count_);
+ std::vector<int64_t> timestamps_ms(event_count_);
+ for (size_t i = 0; i < event_count_; ++i) {
+ timestamps_ms[i] = rtc::TimeMillis();
+ events[i] = gen_.NewFir();
+ rtc::Buffer buffer = events[i].Build();
+ if (direction == kIncomingPacket) {
+ history_.push_back(
+ std::make_unique<RtcEventRtcpPacketIncoming>(buffer));
+ } else {
+ history_.push_back(
+ std::make_unique<RtcEventRtcpPacketOutgoing>(buffer));
+ }
+ fake_clock.AdvanceTime(TimeDelta::Millis(prng_.Rand(0, 1000)));
+ }
+
+ encoded_ += encoder_->EncodeBatch(history_.begin(), history_.end());
+ ASSERT_TRUE(parsed_log_.ParseString(encoded_).ok());
+
+ const auto& firs = parsed_log_.firs(direction);
+ ASSERT_EQ(firs.size(), event_count_);
+
+ for (size_t i = 0; i < event_count_; ++i) {
+ verifier_.VerifyLoggedFir(timestamps_ms[i], events[i], firs[i]);
+ }
+ }
+}
+
+TEST_P(RtcEventLogEncoderTest, RtcEventRtcpPli) {
+ if (force_repeated_fields_) {
+ return;
+ }
+
+ rtc::ScopedFakeClock fake_clock;
+ fake_clock.SetTime(Timestamp::Millis(prng_.Rand<uint32_t>()));
+
+ for (auto direction : {kIncomingPacket, kOutgoingPacket}) {
+ std::vector<rtcp::Pli> events(event_count_);
+ std::vector<int64_t> timestamps_ms(event_count_);
+ for (size_t i = 0; i < event_count_; ++i) {
+ timestamps_ms[i] = rtc::TimeMillis();
+ events[i] = gen_.NewPli();
+ rtc::Buffer buffer = events[i].Build();
+ if (direction == kIncomingPacket) {
+ history_.push_back(
+ std::make_unique<RtcEventRtcpPacketIncoming>(buffer));
+ } else {
+ history_.push_back(
+ std::make_unique<RtcEventRtcpPacketOutgoing>(buffer));
+ }
+ fake_clock.AdvanceTime(TimeDelta::Millis(prng_.Rand(0, 1000)));
+ }
+
+ encoded_ += encoder_->EncodeBatch(history_.begin(), history_.end());
+ ASSERT_TRUE(parsed_log_.ParseString(encoded_).ok());
+
+ const auto& plis = parsed_log_.plis(direction);
+ ASSERT_EQ(plis.size(), event_count_);
+
+ for (size_t i = 0; i < event_count_; ++i) {
+ verifier_.VerifyLoggedPli(timestamps_ms[i], events[i], plis[i]);
+ }
+ }
+}
+
+TEST_P(RtcEventLogEncoderTest, RtcEventRtcpBye) {
+ if (force_repeated_fields_) {
+ return;
+ }
+
+ rtc::ScopedFakeClock fake_clock;
+ fake_clock.SetTime(Timestamp::Millis(prng_.Rand<uint32_t>()));
+
+ for (auto direction : {kIncomingPacket, kOutgoingPacket}) {
+ std::vector<rtcp::Bye> events(event_count_);
+ std::vector<int64_t> timestamps_ms(event_count_);
+ for (size_t i = 0; i < event_count_; ++i) {
+ timestamps_ms[i] = rtc::TimeMillis();
+ events[i] = gen_.NewBye();
+ rtc::Buffer buffer = events[i].Build();
+ if (direction == kIncomingPacket) {
+ history_.push_back(
+ std::make_unique<RtcEventRtcpPacketIncoming>(buffer));
+ } else {
+ history_.push_back(
+ std::make_unique<RtcEventRtcpPacketOutgoing>(buffer));
+ }
+ fake_clock.AdvanceTime(TimeDelta::Millis(prng_.Rand(0, 1000)));
+ }
+
+ encoded_ += encoder_->EncodeBatch(history_.begin(), history_.end());
+ ASSERT_TRUE(parsed_log_.ParseString(encoded_).ok());
+
+ const auto& byes = parsed_log_.byes(direction);
+ ASSERT_EQ(byes.size(), event_count_);
+
+ for (size_t i = 0; i < event_count_; ++i) {
+ verifier_.VerifyLoggedBye(timestamps_ms[i], events[i], byes[i]);
+ }
+ }
+}
+
+TEST_P(RtcEventLogEncoderTest, RtcEventRtcpNack) {
+ if (force_repeated_fields_) {
+ return;
+ }
+
+ rtc::ScopedFakeClock fake_clock;
+ fake_clock.SetTime(Timestamp::Millis(prng_.Rand<uint32_t>()));
+
+ for (auto direction : {kIncomingPacket, kOutgoingPacket}) {
+ std::vector<rtcp::Nack> events(event_count_);
+ std::vector<int64_t> timestamps_ms(event_count_);
+ for (size_t i = 0; i < event_count_; ++i) {
+ timestamps_ms[i] = rtc::TimeMillis();
+ events[i] = gen_.NewNack();
+ rtc::Buffer buffer = events[i].Build();
+ if (direction == kIncomingPacket) {
+ history_.push_back(
+ std::make_unique<RtcEventRtcpPacketIncoming>(buffer));
+ } else {
+ history_.push_back(
+ std::make_unique<RtcEventRtcpPacketOutgoing>(buffer));
+ }
+ fake_clock.AdvanceTime(TimeDelta::Millis(prng_.Rand(0, 1000)));
+ }
+
+ encoded_ += encoder_->EncodeBatch(history_.begin(), history_.end());
+ ASSERT_TRUE(parsed_log_.ParseString(encoded_).ok());
+
+ const auto& nacks = parsed_log_.nacks(direction);
+ ASSERT_EQ(nacks.size(), event_count_);
+
+ for (size_t i = 0; i < event_count_; ++i) {
+ verifier_.VerifyLoggedNack(timestamps_ms[i], events[i], nacks[i]);
+ }
+ }
+}
+
+TEST_P(RtcEventLogEncoderTest, RtcEventRtcpRemb) {
+ if (force_repeated_fields_) {
+ return;
+ }
+
+ rtc::ScopedFakeClock fake_clock;
+ fake_clock.SetTime(Timestamp::Millis(prng_.Rand<uint32_t>()));
+
+ for (auto direction : {kIncomingPacket, kOutgoingPacket}) {
+ std::vector<rtcp::Remb> events(event_count_);
+ std::vector<int64_t> timestamps_ms(event_count_);
+ for (size_t i = 0; i < event_count_; ++i) {
+ timestamps_ms[i] = rtc::TimeMillis();
+ events[i] = gen_.NewRemb();
+ rtc::Buffer buffer = events[i].Build();
+ if (direction == kIncomingPacket) {
+ history_.push_back(
+ std::make_unique<RtcEventRtcpPacketIncoming>(buffer));
+ } else {
+ history_.push_back(
+ std::make_unique<RtcEventRtcpPacketOutgoing>(buffer));
+ }
+ fake_clock.AdvanceTime(TimeDelta::Millis(prng_.Rand(0, 1000)));
+ }
+
+ encoded_ += encoder_->EncodeBatch(history_.begin(), history_.end());
+ ASSERT_TRUE(parsed_log_.ParseString(encoded_).ok());
+
+ const auto& rembs = parsed_log_.rembs(direction);
+ ASSERT_EQ(rembs.size(), event_count_);
+
+ for (size_t i = 0; i < event_count_; ++i) {
+ verifier_.VerifyLoggedRemb(timestamps_ms[i], events[i], rembs[i]);
+ }
+ }
+}
+
+TEST_P(RtcEventLogEncoderTest, RtcEventRtcpTransportFeedback) {
+ if (force_repeated_fields_) {
+ return;
+ }
+
+ rtc::ScopedFakeClock fake_clock;
+ fake_clock.SetTime(Timestamp::Millis(prng_.Rand<uint32_t>()));
+
+ for (auto direction : {kIncomingPacket, kOutgoingPacket}) {
+ std::vector<rtcp::TransportFeedback> events;
+ events.reserve(event_count_);
+ std::vector<int64_t> timestamps_ms(event_count_);
+ for (size_t i = 0; i < event_count_; ++i) {
+ timestamps_ms[i] = rtc::TimeMillis();
+ events.emplace_back(gen_.NewTransportFeedback());
+ rtc::Buffer buffer = events[i].Build();
+ if (direction == kIncomingPacket) {
+ history_.push_back(
+ std::make_unique<RtcEventRtcpPacketIncoming>(buffer));
+ } else {
+ history_.push_back(
+ std::make_unique<RtcEventRtcpPacketOutgoing>(buffer));
+ }
+ fake_clock.AdvanceTime(TimeDelta::Millis(prng_.Rand(0, 1000)));
+ }
+
+ encoded_ += encoder_->EncodeBatch(history_.begin(), history_.end());
+ ASSERT_TRUE(parsed_log_.ParseString(encoded_).ok());
+
+ const auto& transport_feedbacks =
+ parsed_log_.transport_feedbacks(direction);
+ ASSERT_EQ(transport_feedbacks.size(), event_count_);
+
+ for (size_t i = 0; i < event_count_; ++i) {
+ verifier_.VerifyLoggedTransportFeedback(timestamps_ms[i], events[i],
+ transport_feedbacks[i]);
+ }
+ }
+}
+
+TEST_P(RtcEventLogEncoderTest, RtcEventRtcpLossNotification) {
+ if (force_repeated_fields_) {
+ return;
+ }
+
+ rtc::ScopedFakeClock fake_clock;
+ fake_clock.SetTime(Timestamp::Millis(prng_.Rand<uint32_t>()));
+
+ for (auto direction : {kIncomingPacket, kOutgoingPacket}) {
+ std::vector<rtcp::LossNotification> events;
+ events.reserve(event_count_);
+ std::vector<int64_t> timestamps_ms(event_count_);
+ for (size_t i = 0; i < event_count_; ++i) {
+ timestamps_ms[i] = rtc::TimeMillis();
+ events.emplace_back(gen_.NewLossNotification());
+ rtc::Buffer buffer = events[i].Build();
+ if (direction == kIncomingPacket) {
+ history_.push_back(
+ std::make_unique<RtcEventRtcpPacketIncoming>(buffer));
+ } else {
+ history_.push_back(
+ std::make_unique<RtcEventRtcpPacketOutgoing>(buffer));
+ }
+ fake_clock.AdvanceTime(TimeDelta::Millis(prng_.Rand(0, 1000)));
+ }
+
+ encoded_ += encoder_->EncodeBatch(history_.begin(), history_.end());
+ ASSERT_TRUE(parsed_log_.ParseString(encoded_).ok());
+
+ const auto& loss_notifications = parsed_log_.loss_notifications(direction);
+ ASSERT_EQ(loss_notifications.size(), event_count_);
+
+ for (size_t i = 0; i < event_count_; ++i) {
+ verifier_.VerifyLoggedLossNotification(timestamps_ms[i], events[i],
+ loss_notifications[i]);
+ }
+ }
+}
+
+TEST_P(RtcEventLogEncoderTest, RtcEventRtpPacketIncoming) {
+ TestRtpPackets<RtcEventRtpPacketIncoming, LoggedRtpPacketIncoming>();
+}
+
+TEST_P(RtcEventLogEncoderTest, RtcEventRtpPacketOutgoing) {
+ TestRtpPackets<RtcEventRtpPacketOutgoing, LoggedRtpPacketOutgoing>();
+}
+
+// TODO(eladalon/terelius): Test with multiple events in the batch.
+TEST_P(RtcEventLogEncoderTest, RtcEventVideoReceiveStreamConfig) {
+ uint32_t ssrc = prng_.Rand<uint32_t>();
+ RtpHeaderExtensionMap extensions = gen_.NewRtpHeaderExtensionMap();
+ std::unique_ptr<RtcEventVideoReceiveStreamConfig> event =
+ gen_.NewVideoReceiveStreamConfig(ssrc, extensions);
+ history_.push_back(event->Copy());
+
+ encoded_ += encoder_->EncodeBatch(history_.begin(), history_.end());
+ ASSERT_TRUE(parsed_log_.ParseString(encoded_).ok());
+ const auto& video_recv_configs = parsed_log_.video_recv_configs();
+
+ ASSERT_EQ(video_recv_configs.size(), 1u);
+ verifier_.VerifyLoggedVideoRecvConfig(*event, video_recv_configs[0]);
+}
+
+// TODO(eladalon/terelius): Test with multiple events in the batch.
+TEST_P(RtcEventLogEncoderTest, RtcEventVideoSendStreamConfig) {
+ uint32_t ssrc = prng_.Rand<uint32_t>();
+ RtpHeaderExtensionMap extensions = gen_.NewRtpHeaderExtensionMap();
+ std::unique_ptr<RtcEventVideoSendStreamConfig> event =
+ gen_.NewVideoSendStreamConfig(ssrc, extensions);
+ history_.push_back(event->Copy());
+
+ encoded_ += encoder_->EncodeBatch(history_.begin(), history_.end());
+ ASSERT_TRUE(parsed_log_.ParseString(encoded_).ok());
+ const auto& video_send_configs = parsed_log_.video_send_configs();
+
+ ASSERT_EQ(video_send_configs.size(), 1u);
+ verifier_.VerifyLoggedVideoSendConfig(*event, video_send_configs[0]);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ RandomSeeds,
+ RtcEventLogEncoderTest,
+ ::testing::Combine(/* Random seed*: */ ::testing::Values(1, 2, 3, 4, 5),
+ /* Encoding: */
+ ::testing::Values(RtcEventLog::EncodingType::Legacy,
+ RtcEventLog::EncodingType::NewFormat),
+ /* Event count: */ ::testing::Values(1, 2, 10, 100),
+ /* Repeated fields: */ ::testing::Bool()));
+
+class RtcEventLogEncoderSimpleTest
+ : public ::testing::TestWithParam<RtcEventLog::EncodingType> {
+ protected:
+ RtcEventLogEncoderSimpleTest() : encoding_type_(GetParam()) {
+ switch (encoding_type_) {
+ case RtcEventLog::EncodingType::Legacy:
+ encoder_ = std::make_unique<RtcEventLogEncoderLegacy>();
+ break;
+ case RtcEventLog::EncodingType::NewFormat:
+ encoder_ = std::make_unique<RtcEventLogEncoderNewFormat>();
+ break;
+ case RtcEventLog::EncodingType::ProtoFree:
+ encoder_ = std::make_unique<RtcEventLogEncoderV3>();
+ break;
+ }
+ encoded_ =
+ encoder_->EncodeLogStart(rtc::TimeMillis(), rtc::TimeUTCMillis());
+ }
+ ~RtcEventLogEncoderSimpleTest() override = default;
+
+ std::deque<std::unique_ptr<RtcEvent>> history_;
+ std::unique_ptr<RtcEventLogEncoder> encoder_;
+ ParsedRtcEventLog parsed_log_;
+ const RtcEventLog::EncodingType encoding_type_;
+ std::string encoded_;
+};
+
+TEST_P(RtcEventLogEncoderSimpleTest, RtcEventLargeCompoundRtcpPacketIncoming) {
+ // Create a compound packet containing multiple Bye messages.
+ rtc::Buffer packet;
+ size_t index = 0;
+ for (int i = 0; i < 8; i++) {
+ rtcp::Bye bye;
+ std::string reason(255, 'a'); // Add some arbitrary data.
+ bye.SetReason(reason);
+ bye.SetSenderSsrc(0x12345678);
+ packet.SetSize(packet.size() + bye.BlockLength());
+ bool created =
+ bye.Create(packet.data(), &index, packet.capacity(), nullptr);
+ ASSERT_TRUE(created);
+ ASSERT_EQ(index, packet.size());
+ }
+
+ EXPECT_GT(packet.size(), static_cast<size_t>(IP_PACKET_SIZE));
+ auto event = std::make_unique<RtcEventRtcpPacketIncoming>(packet);
+ history_.push_back(event->Copy());
+ encoded_ += encoder_->EncodeBatch(history_.begin(), history_.end());
+
+ ParsedRtcEventLog::ParseStatus status = parsed_log_.ParseString(encoded_);
+ ASSERT_TRUE(status.ok()) << status.message();
+
+ const auto& incoming_rtcp_packets = parsed_log_.incoming_rtcp_packets();
+ ASSERT_EQ(incoming_rtcp_packets.size(), 1u);
+ ASSERT_EQ(incoming_rtcp_packets[0].rtcp.raw_data.size(), packet.size());
+ EXPECT_EQ(memcmp(incoming_rtcp_packets[0].rtcp.raw_data.data(), packet.data(),
+ packet.size()),
+ 0);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ LargeCompoundRtcp,
+ RtcEventLogEncoderSimpleTest,
+ ::testing::Values(RtcEventLog::EncodingType::Legacy,
+ RtcEventLog::EncodingType::NewFormat));
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder_v3.cc b/third_party/libwebrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder_v3.cc
new file mode 100644
index 0000000000..131aae1de8
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder_v3.cc
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2021 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/encoder/rtc_event_log_encoder_v3.h"
+
+#include <string>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "logging/rtc_event_log/encoder/rtc_event_log_encoder_common.h"
+#include "logging/rtc_event_log/encoder/var_int.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"
+#include "logging/rtc_event_log/events/rtc_event_audio_receive_stream_config.h"
+#include "logging/rtc_event_log/events/rtc_event_audio_send_stream_config.h"
+#include "logging/rtc_event_log/events/rtc_event_begin_log.h"
+#include "logging/rtc_event_log/events/rtc_event_bwe_update_delay_based.h"
+#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_end_log.h"
+#include "logging/rtc_event_log/events/rtc_event_frame_decoded.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"
+#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_remote_estimate.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"
+#include "logging/rtc_event_log/events/rtc_event_rtp_packet_outgoing.h"
+#include "logging/rtc_event_log/events/rtc_event_video_receive_stream_config.h"
+#include "logging/rtc_event_log/events/rtc_event_video_send_stream_config.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+
+namespace webrtc {
+
+std::string RtcEventLogEncoderV3::EncodeLogStart(int64_t timestamp_us,
+ int64_t utc_time_us) {
+ std::unique_ptr<RtcEventBeginLog> begin_log =
+ std::make_unique<RtcEventBeginLog>(Timestamp::Micros(timestamp_us),
+ Timestamp::Micros(utc_time_us));
+ std::vector<const RtcEvent*> batch;
+ batch.push_back(begin_log.get());
+
+ std::string encoded_event = RtcEventBeginLog::Encode(batch);
+
+ return encoded_event;
+}
+
+std::string RtcEventLogEncoderV3::EncodeLogEnd(int64_t timestamp_us) {
+ std::unique_ptr<RtcEventEndLog> end_log =
+ std::make_unique<RtcEventEndLog>(Timestamp::Micros(timestamp_us));
+ std::vector<const RtcEvent*> batch;
+ batch.push_back(end_log.get());
+
+ std::string encoded_event = RtcEventEndLog::Encode(batch);
+
+ return encoded_event;
+}
+
+RtcEventLogEncoderV3::RtcEventLogEncoderV3() {
+ encoders_[RtcEvent::Type::AlrStateEvent] = RtcEventAlrState::Encode;
+ encoders_[RtcEvent::Type::AudioNetworkAdaptation] =
+ RtcEventAudioNetworkAdaptation::Encode;
+ encoders_[RtcEvent::Type::AudioPlayout] = RtcEventAudioPlayout::Encode;
+ encoders_[RtcEvent::Type::AudioReceiveStreamConfig] =
+ RtcEventAudioReceiveStreamConfig::Encode;
+ encoders_[RtcEvent::Type::AudioSendStreamConfig] =
+ RtcEventAudioSendStreamConfig::Encode;
+ encoders_[RtcEvent::Type::BweUpdateDelayBased] =
+ RtcEventBweUpdateDelayBased::Encode;
+ encoders_[RtcEvent::Type::BweUpdateLossBased] =
+ RtcEventBweUpdateLossBased::Encode;
+ encoders_[RtcEvent::Type::DtlsTransportState] =
+ RtcEventDtlsTransportState::Encode;
+ encoders_[RtcEvent::Type::DtlsWritableState] =
+ RtcEventDtlsWritableState::Encode;
+ encoders_[RtcEvent::Type::FrameDecoded] = RtcEventFrameDecoded::Encode;
+ encoders_[RtcEvent::Type::GenericAckReceived] =
+ RtcEventGenericAckReceived::Encode;
+ encoders_[RtcEvent::Type::GenericPacketReceived] =
+ RtcEventGenericPacketReceived::Encode;
+ encoders_[RtcEvent::Type::GenericPacketSent] =
+ RtcEventGenericPacketSent::Encode;
+ encoders_[RtcEvent::Type::IceCandidatePairConfig] =
+ RtcEventIceCandidatePairConfig::Encode;
+ encoders_[RtcEvent::Type::IceCandidatePairEvent] =
+ RtcEventIceCandidatePair::Encode;
+ encoders_[RtcEvent::Type::ProbeClusterCreated] =
+ RtcEventProbeClusterCreated::Encode;
+ encoders_[RtcEvent::Type::ProbeResultFailure] =
+ RtcEventProbeResultFailure::Encode;
+ encoders_[RtcEvent::Type::ProbeResultSuccess] =
+ RtcEventProbeResultSuccess::Encode;
+ encoders_[RtcEvent::Type::RemoteEstimateEvent] =
+ RtcEventRemoteEstimate::Encode;
+ encoders_[RtcEvent::Type::RouteChangeEvent] = RtcEventRouteChange::Encode;
+ encoders_[RtcEvent::Type::RtcpPacketIncoming] =
+ RtcEventRtcpPacketIncoming::Encode;
+ encoders_[RtcEvent::Type::RtcpPacketOutgoing] =
+ RtcEventRtcpPacketOutgoing::Encode;
+ encoders_[RtcEvent::Type::RtpPacketIncoming] =
+ RtcEventRtpPacketIncoming::Encode;
+ encoders_[RtcEvent::Type::RtpPacketOutgoing] =
+ RtcEventRtpPacketOutgoing::Encode;
+ encoders_[RtcEvent::Type::VideoReceiveStreamConfig] =
+ RtcEventVideoReceiveStreamConfig::Encode;
+ encoders_[RtcEvent::Type::VideoSendStreamConfig] =
+ RtcEventVideoSendStreamConfig::Encode;
+}
+
+std::string RtcEventLogEncoderV3::EncodeBatch(
+ std::deque<std::unique_ptr<RtcEvent>>::const_iterator begin,
+ std::deque<std::unique_ptr<RtcEvent>>::const_iterator end) {
+ struct EventGroupKey {
+ // Events are grouped by event type. For compression efficiency,
+ // events can optionally have a secondary key, in most cases the
+ // SSRC.
+ RtcEvent::Type type;
+ uint32_t secondary_group_key;
+
+ bool operator<(EventGroupKey other) const {
+ return type < other.type ||
+ (type == other.type &&
+ secondary_group_key < other.secondary_group_key);
+ }
+ };
+
+ std::map<EventGroupKey, std::vector<const RtcEvent*>> event_groups;
+
+ for (auto it = begin; it != end; ++it) {
+ event_groups[{(*it)->GetType(), (*it)->GetGroupKey()}].push_back(it->get());
+ }
+
+ std::string encoded_output;
+ for (auto& kv : event_groups) {
+ auto it = encoders_.find(kv.first.type);
+ RTC_DCHECK(it != encoders_.end());
+ if (it != encoders_.end()) {
+ auto& encoder = it->second;
+ // TODO(terelius): Use some "string builder" or preallocate?
+ encoded_output += encoder(kv.second);
+ }
+ }
+
+ return encoded_output;
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder_v3.h b/third_party/libwebrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder_v3.h
new file mode 100644
index 0000000000..cb796ec562
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder_v3.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2021 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_ENCODER_RTC_EVENT_LOG_ENCODER_V3_H_
+#define LOGGING_RTC_EVENT_LOG_ENCODER_RTC_EVENT_LOG_ENCODER_V3_H_
+
+#include <deque>
+#include <map>
+#include <memory>
+#include <string>
+
+#include "api/array_view.h"
+#include "logging/rtc_event_log/encoder/rtc_event_log_encoder.h"
+#include "logging/rtc_event_log/events/rtc_event_definition.h"
+
+namespace webrtc {
+
+class RtcEventLogEncoderV3 final : public RtcEventLogEncoder {
+ public:
+ RtcEventLogEncoderV3();
+ ~RtcEventLogEncoderV3() override = default;
+
+ std::string EncodeBatch(
+ std::deque<std::unique_ptr<RtcEvent>>::const_iterator begin,
+ std::deque<std::unique_ptr<RtcEvent>>::const_iterator end) override;
+
+ std::string EncodeLogStart(int64_t timestamp_us,
+ int64_t utc_time_us) override;
+ std::string EncodeLogEnd(int64_t timestamp_us) override;
+
+ private:
+ std::map<RtcEvent::Type,
+ std::function<std::string(rtc::ArrayView<const RtcEvent*>)>>
+ encoders_;
+};
+
+} // namespace webrtc
+
+#endif // LOGGING_RTC_EVENT_LOG_ENCODER_RTC_EVENT_LOG_ENCODER_V3_H_
diff --git a/third_party/libwebrtc/logging/rtc_event_log/encoder/var_int.cc b/third_party/libwebrtc/logging/rtc_event_log/encoder/var_int.cc
new file mode 100644
index 0000000000..a84a233d6b
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/encoder/var_int.cc
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2018 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/encoder/var_int.h"
+
+#include "rtc_base/bitstream_reader.h"
+#include "rtc_base/checks.h"
+
+// TODO(eladalon): Add unit tests.
+
+namespace webrtc {
+
+const size_t kMaxVarIntLengthBytes = 10; // ceil(64 / 7.0) is 10.
+
+std::string EncodeVarInt(uint64_t input) {
+ std::string output;
+ output.reserve(kMaxVarIntLengthBytes);
+
+ do {
+ uint8_t byte = static_cast<uint8_t>(input & 0x7f);
+ input >>= 7;
+ if (input > 0) {
+ byte |= 0x80;
+ }
+ output += byte;
+ } while (input > 0);
+
+ RTC_DCHECK_GE(output.size(), 1u);
+ RTC_DCHECK_LE(output.size(), kMaxVarIntLengthBytes);
+
+ return output;
+}
+
+// There is some code duplication between the flavors of this function.
+// For performance's sake, it's best to just keep it.
+std::pair<bool, absl::string_view> DecodeVarInt(absl::string_view input,
+ uint64_t* output) {
+ RTC_DCHECK(output);
+
+ uint64_t decoded = 0;
+ for (size_t i = 0; i < input.length() && i < kMaxVarIntLengthBytes; ++i) {
+ decoded += (static_cast<uint64_t>(input[i] & 0x7f)
+ << static_cast<uint64_t>(7 * i));
+ if (!(input[i] & 0x80)) {
+ *output = decoded;
+ return {true, input.substr(i + 1)};
+ }
+ }
+
+ return {false, input};
+}
+
+// There is some code duplication between the flavors of this function.
+// For performance's sake, it's best to just keep it.
+uint64_t DecodeVarInt(BitstreamReader& input) {
+ uint64_t decoded = 0;
+ for (size_t i = 0; i < kMaxVarIntLengthBytes; ++i) {
+ uint8_t byte = input.Read<uint8_t>();
+ decoded +=
+ (static_cast<uint64_t>(byte & 0x7f) << static_cast<uint64_t>(7 * i));
+ if (!(byte & 0x80)) {
+ return decoded;
+ }
+ }
+
+ input.Invalidate();
+ return 0;
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/logging/rtc_event_log/encoder/var_int.h b/third_party/libwebrtc/logging/rtc_event_log/encoder/var_int.h
new file mode 100644
index 0000000000..4624e046ba
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/encoder/var_int.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2018 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_ENCODER_VAR_INT_H_
+#define LOGGING_RTC_EVENT_LOG_ENCODER_VAR_INT_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+#include <utility>
+
+#include "absl/strings/string_view.h"
+#include "rtc_base/bitstream_reader.h"
+
+namespace webrtc {
+
+extern const size_t kMaxVarIntLengthBytes;
+
+// Encode a given uint64_t as a varint. From least to most significant,
+// each batch of seven bits are put into the lower bits of a byte, and the last
+// remaining bit in that byte (the highest one) marks whether additional bytes
+// follow (which happens if and only if there are other bits in `input` which
+// are non-zero).
+// Notes: If input == 0, one byte is used. If input is uint64_t::max, exactly
+// kMaxVarIntLengthBytes are used.
+std::string EncodeVarInt(uint64_t input);
+
+// Inverse of EncodeVarInt().
+// Returns true and the remaining (unread) slice of the input if decoding
+// succeeds. Returns false otherwise and `output` is not modified.
+std::pair<bool, absl::string_view> DecodeVarInt(absl::string_view input,
+ uint64_t* output);
+
+// Same as other version, but uses a BitstreamReader for input.
+// If decoding is successful returns the decoded varint.
+// If not successful, `input` reader is set into the failure state, return value
+// is unspecified.
+uint64_t DecodeVarInt(BitstreamReader& input);
+
+} // namespace webrtc
+
+#endif // LOGGING_RTC_EVENT_LOG_ENCODER_VAR_INT_H_
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/fixed_length_encoding_parameters_v3.cc b/third_party/libwebrtc/logging/rtc_event_log/events/fixed_length_encoding_parameters_v3.cc
new file mode 100644
index 0000000000..0c93e6226d
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/fixed_length_encoding_parameters_v3.cc
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2021 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/fixed_length_encoding_parameters_v3.h"
+
+#include <algorithm>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "logging/rtc_event_log/events/rtc_event_field_extraction.h"
+#include "rtc_base/logging.h"
+
+using webrtc_event_logging::MaxUnsignedValueOfBitWidth;
+using webrtc_event_logging::SignedBitWidth;
+using webrtc_event_logging::UnsignedBitWidth;
+using webrtc_event_logging::UnsignedDelta;
+
+namespace webrtc {
+
+FixedLengthEncodingParametersV3
+FixedLengthEncodingParametersV3::CalculateParameters(
+ uint64_t base,
+ const rtc::ArrayView<const uint64_t> values,
+ uint64_t value_bit_width,
+ bool values_optional) {
+ // As a special case, if all of the elements are identical to the base
+ // we just encode the base value with a special delta header.
+ if (std::all_of(values.cbegin(), values.cend(),
+ [base](uint64_t val) { return val == base; })) {
+ // Delta header with signed=true and delta_bitwidth=64
+ return FixedLengthEncodingParametersV3(/*delta_bit_width=*/64,
+ /*signed_deltas=*/true,
+ values_optional, value_bit_width);
+ }
+
+ const uint64_t bit_mask = MaxUnsignedValueOfBitWidth(value_bit_width);
+
+ // Calculate the bitwidth required to encode all deltas when using a
+ // unsigned or signed represenation, respectively. For the unsigned
+ // representation, we just track the largest delta. For the signed
+ // representation, we have two possibilities for each delta; either
+ // going "forward" (i.e. current - previous) or "backwards"
+ // (i.e. previous - current) where both values are calculated with
+ // wrap around. We then track the largest positive and negative
+ // magnitude across the batch, assuming that we choose the smaller
+ // delta for each element.
+ uint64_t max_unsigned_delta = 0;
+ uint64_t max_positive_signed_delta = 0;
+ uint64_t min_negative_signed_delta = 0;
+ uint64_t prev = base;
+ for (uint64_t current : values) {
+ uint64_t positive_delta = UnsignedDelta(prev, current, bit_mask);
+ uint64_t negative_delta = UnsignedDelta(current, prev, bit_mask);
+
+ max_unsigned_delta = std::max(max_unsigned_delta, positive_delta);
+
+ if (positive_delta < negative_delta) {
+ max_positive_signed_delta =
+ std::max(max_positive_signed_delta, positive_delta);
+ } else {
+ min_negative_signed_delta =
+ std::max(min_negative_signed_delta, negative_delta);
+ }
+
+ prev = current;
+ }
+
+ // We now know the largest unsigned delta and the largest magnitudes of
+ // positive and negative signed deltas. Get the bitwidths required for
+ // each of the two encodings.
+ const uint64_t unsigned_delta_bit_width =
+ UnsignedBitWidth(max_unsigned_delta);
+ const uint64_t signed_delta_bit_width =
+ SignedBitWidth(max_positive_signed_delta, min_negative_signed_delta);
+
+ // Note: Preference for unsigned if the two have the same width (efficiency).
+ bool use_signed_deltas = signed_delta_bit_width < unsigned_delta_bit_width;
+ uint64_t delta_bit_width =
+ use_signed_deltas ? signed_delta_bit_width : unsigned_delta_bit_width;
+
+ // use_signed_deltas && delta_bit_width==64 is reserved for "all values
+ // equal".
+ RTC_DCHECK(!use_signed_deltas || delta_bit_width < 64);
+
+ RTC_DCHECK(ValidParameters(delta_bit_width, use_signed_deltas,
+ values_optional, value_bit_width));
+ return FixedLengthEncodingParametersV3(delta_bit_width, use_signed_deltas,
+ values_optional, value_bit_width);
+}
+
+uint64_t FixedLengthEncodingParametersV3::DeltaHeaderAsInt() const {
+ uint64_t header = delta_bit_width_ - 1;
+ RTC_CHECK_LT(header, 1u << 6);
+ if (signed_deltas_) {
+ header += 1u << 6;
+ }
+ RTC_CHECK_LT(header, 1u << 7);
+ if (values_optional_) {
+ header += 1u << 7;
+ }
+ return header;
+}
+
+absl::optional<FixedLengthEncodingParametersV3>
+FixedLengthEncodingParametersV3::ParseDeltaHeader(uint64_t header,
+ uint64_t value_bit_width) {
+ uint64_t delta_bit_width = (header & ((1u << 6) - 1)) + 1;
+ bool signed_deltas = header & (1u << 6);
+ bool values_optional = header & (1u << 7);
+
+ if (header >= (1u << 8)) {
+ RTC_LOG(LS_ERROR) << "Failed to parse delta header; unread bits remaining.";
+ return absl::nullopt;
+ }
+
+ if (!ValidParameters(delta_bit_width, signed_deltas, values_optional,
+ value_bit_width)) {
+ RTC_LOG(LS_ERROR) << "Failed to parse delta header. Invalid combination of "
+ "values: delta_bit_width="
+ << delta_bit_width << " signed_deltas=" << signed_deltas
+ << " values_optional=" << values_optional
+ << " value_bit_width=" << value_bit_width;
+ return absl::nullopt;
+ }
+
+ return FixedLengthEncodingParametersV3(delta_bit_width, signed_deltas,
+ values_optional, value_bit_width);
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/fixed_length_encoding_parameters_v3.h b/third_party/libwebrtc/logging/rtc_event_log/events/fixed_length_encoding_parameters_v3.h
new file mode 100644
index 0000000000..666fae1c63
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/fixed_length_encoding_parameters_v3.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2021 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_FIXED_LENGTH_ENCODING_PARAMETERS_V3_H_
+#define LOGGING_RTC_EVENT_LOG_EVENTS_FIXED_LENGTH_ENCODING_PARAMETERS_V3_H_
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "logging/rtc_event_log/events/rtc_event_field_extraction.h"
+
+namespace webrtc {
+
+// Parameters for fixed-size delta-encoding/decoding.
+// These are tailored for the sequence which will be encoded (e.g. widths).
+class FixedLengthEncodingParametersV3 final {
+ public:
+ static bool ValidParameters(uint64_t delta_bit_width,
+ bool signed_deltas,
+ bool values_optional,
+ uint64_t value_bit_width) {
+ return (1 <= delta_bit_width && delta_bit_width <= 64 &&
+ 1 <= value_bit_width && value_bit_width <= 64 &&
+ (delta_bit_width <= value_bit_width ||
+ (signed_deltas && delta_bit_width == 64)));
+ }
+
+ static FixedLengthEncodingParametersV3 CalculateParameters(
+ uint64_t base,
+ rtc::ArrayView<const uint64_t> values,
+ uint64_t value_bit_width,
+ bool values_optional);
+ static absl::optional<FixedLengthEncodingParametersV3> ParseDeltaHeader(
+ uint64_t header,
+ uint64_t value_bit_width);
+
+ uint64_t DeltaHeaderAsInt() const;
+
+ // Number of bits necessary to hold the widest(*) of the deltas between the
+ // values in the sequence.
+ // (*) - Widest might not be the largest, if signed deltas are used.
+ uint64_t delta_bit_width() const { return delta_bit_width_; }
+
+ // Whether deltas are signed.
+ bool signed_deltas() const { return signed_deltas_; }
+
+ // Whether the values of the sequence are optional. That is, it may be
+ // that some of them do not have a value (not even a sentinel value indicating
+ // invalidity).
+ bool values_optional() const { return values_optional_; }
+
+ // Whether all values are equal. 64-bit signed deltas are assumed to not
+ // occur, since those could equally well be represented using 64 bit unsigned
+ // deltas.
+ bool values_equal() const {
+ return delta_bit_width() == 64 && signed_deltas();
+ }
+
+ // Number of bits necessary to hold the largest value in the sequence.
+ uint64_t value_bit_width() const { return value_bit_width_; }
+
+ // Masks where only the bits relevant to the deltas/values are turned on.
+ uint64_t delta_mask() const { return delta_mask_; }
+ uint64_t value_mask() const { return value_mask_; }
+
+ private:
+ FixedLengthEncodingParametersV3(uint64_t delta_bit_width,
+ bool signed_deltas,
+ bool values_optional,
+ uint64_t value_bit_width)
+ : delta_bit_width_(delta_bit_width),
+ signed_deltas_(signed_deltas),
+ values_optional_(values_optional),
+ value_bit_width_(value_bit_width),
+ delta_mask_(
+ webrtc_event_logging::MaxUnsignedValueOfBitWidth(delta_bit_width_)),
+ value_mask_(webrtc_event_logging::MaxUnsignedValueOfBitWidth(
+ value_bit_width_)) {}
+
+ uint64_t delta_bit_width_;
+ bool signed_deltas_;
+ bool values_optional_;
+ uint64_t value_bit_width_;
+
+ uint64_t delta_mask_;
+ uint64_t value_mask_;
+};
+
+} // namespace webrtc
+#endif // LOGGING_RTC_EVENT_LOG_EVENTS_FIXED_LENGTH_ENCODING_PARAMETERS_V3_H_
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/logged_rtp_rtcp.h b/third_party/libwebrtc/logging/rtc_event_log/events/logged_rtp_rtcp.h
new file mode 100644
index 0000000000..c441dea1a4
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/logged_rtp_rtcp.h
@@ -0,0 +1,259 @@
+/*
+ * Copyright 2022 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_LOGGED_RTP_RTCP_H_
+#define LOGGING_RTC_EVENT_LOG_EVENTS_LOGGED_RTP_RTCP_H_
+
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/rtp_headers.h"
+#include "api/units/timestamp.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/bye.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/extended_reports.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/fir.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/loss_notification.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/nack.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/pli.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/receiver_report.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/remb.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/sender_report.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
+
+namespace webrtc {
+
+struct LoggedRtpPacket {
+ LoggedRtpPacket(Timestamp timestamp,
+ RTPHeader header,
+ size_t header_length,
+ size_t total_length)
+ : timestamp(timestamp),
+ header(header),
+ header_length(header_length),
+ total_length(total_length) {}
+
+ int64_t log_time_us() const { return timestamp.us(); }
+ int64_t log_time_ms() const { return timestamp.ms(); }
+ Timestamp log_time() const { return timestamp; }
+
+ Timestamp timestamp;
+ // TODO(terelius): This allocates space for 15 CSRCs even if none are used.
+ RTPHeader header;
+ size_t header_length;
+ size_t total_length;
+};
+
+struct LoggedRtpPacketIncoming {
+ LoggedRtpPacketIncoming(Timestamp timestamp,
+ RTPHeader header,
+ size_t header_length,
+ size_t total_length)
+ : rtp(timestamp, header, header_length, total_length) {}
+ int64_t log_time_us() const { return rtp.timestamp.us(); }
+ int64_t log_time_ms() const { return rtp.timestamp.ms(); }
+ Timestamp log_time() const { return rtp.timestamp; }
+
+ LoggedRtpPacket rtp;
+};
+
+struct LoggedRtpPacketOutgoing {
+ LoggedRtpPacketOutgoing(Timestamp timestamp,
+ RTPHeader header,
+ size_t header_length,
+ size_t total_length)
+ : rtp(timestamp, header, header_length, total_length) {}
+ int64_t log_time_us() const { return rtp.timestamp.us(); }
+ int64_t log_time_ms() const { return rtp.timestamp.ms(); }
+ Timestamp log_time() const { return rtp.timestamp; }
+
+ LoggedRtpPacket rtp;
+};
+
+struct LoggedRtcpPacket {
+ LoggedRtcpPacket(Timestamp timestamp, const std::vector<uint8_t>& packet)
+ : timestamp(timestamp), raw_data(packet) {}
+ LoggedRtcpPacket(Timestamp timestamp, absl::string_view packet)
+ : timestamp(timestamp), raw_data(packet.size()) {
+ memcpy(raw_data.data(), packet.data(), packet.size());
+ }
+
+ LoggedRtcpPacket(const LoggedRtcpPacket& rhs) = default;
+
+ ~LoggedRtcpPacket() = default;
+
+ int64_t log_time_us() const { return timestamp.us(); }
+ int64_t log_time_ms() const { return timestamp.ms(); }
+ Timestamp log_time() const { return timestamp; }
+
+ Timestamp timestamp;
+ std::vector<uint8_t> raw_data;
+};
+
+struct LoggedRtcpPacketIncoming {
+ LoggedRtcpPacketIncoming(Timestamp timestamp,
+ const std::vector<uint8_t>& packet)
+ : rtcp(timestamp, packet) {}
+ LoggedRtcpPacketIncoming(Timestamp timestamp, absl::string_view packet)
+ : rtcp(timestamp, packet) {}
+
+ int64_t log_time_us() const { return rtcp.timestamp.us(); }
+ int64_t log_time_ms() const { return rtcp.timestamp.ms(); }
+ Timestamp log_time() const { return rtcp.timestamp; }
+
+ LoggedRtcpPacket rtcp;
+};
+
+struct LoggedRtcpPacketOutgoing {
+ LoggedRtcpPacketOutgoing(Timestamp timestamp,
+ const std::vector<uint8_t>& packet)
+ : rtcp(timestamp, packet) {}
+ LoggedRtcpPacketOutgoing(Timestamp timestamp, absl::string_view packet)
+ : rtcp(timestamp, packet) {}
+
+ int64_t log_time_us() const { return rtcp.timestamp.us(); }
+ int64_t log_time_ms() const { return rtcp.timestamp.ms(); }
+ Timestamp log_time() const { return rtcp.timestamp; }
+
+ LoggedRtcpPacket rtcp;
+};
+
+struct LoggedRtcpPacketReceiverReport {
+ LoggedRtcpPacketReceiverReport() = default;
+ LoggedRtcpPacketReceiverReport(Timestamp timestamp,
+ const rtcp::ReceiverReport& rr)
+ : timestamp(timestamp), rr(rr) {}
+
+ int64_t log_time_us() const { return timestamp.us(); }
+ int64_t log_time_ms() const { return timestamp.ms(); }
+ Timestamp log_time() const { return timestamp; }
+
+ Timestamp timestamp = Timestamp::MinusInfinity();
+ rtcp::ReceiverReport rr;
+};
+
+struct LoggedRtcpPacketSenderReport {
+ LoggedRtcpPacketSenderReport() = default;
+ LoggedRtcpPacketSenderReport(Timestamp timestamp,
+ const rtcp::SenderReport& sr)
+ : timestamp(timestamp), sr(sr) {}
+
+ int64_t log_time_us() const { return timestamp.us(); }
+ int64_t log_time_ms() const { return timestamp.ms(); }
+ Timestamp log_time() const { return timestamp; }
+
+ Timestamp timestamp = Timestamp::MinusInfinity();
+ rtcp::SenderReport sr;
+};
+
+struct LoggedRtcpPacketExtendedReports {
+ LoggedRtcpPacketExtendedReports() = default;
+
+ int64_t log_time_us() const { return timestamp.us(); }
+ int64_t log_time_ms() const { return timestamp.ms(); }
+ Timestamp log_time() const { return timestamp; }
+
+ Timestamp timestamp = Timestamp::MinusInfinity();
+ rtcp::ExtendedReports xr;
+};
+
+struct LoggedRtcpPacketRemb {
+ LoggedRtcpPacketRemb() = default;
+ LoggedRtcpPacketRemb(Timestamp timestamp, const rtcp::Remb& remb)
+ : timestamp(timestamp), remb(remb) {}
+
+ int64_t log_time_us() const { return timestamp.us(); }
+ int64_t log_time_ms() const { return timestamp.ms(); }
+ Timestamp log_time() const { return timestamp; }
+
+ Timestamp timestamp = Timestamp::MinusInfinity();
+ rtcp::Remb remb;
+};
+
+struct LoggedRtcpPacketNack {
+ LoggedRtcpPacketNack() = default;
+ LoggedRtcpPacketNack(Timestamp timestamp, const rtcp::Nack& nack)
+ : timestamp(timestamp), nack(nack) {}
+
+ int64_t log_time_us() const { return timestamp.us(); }
+ int64_t log_time_ms() const { return timestamp.ms(); }
+ Timestamp log_time() const { return timestamp; }
+
+ Timestamp timestamp = Timestamp::MinusInfinity();
+ rtcp::Nack nack;
+};
+
+struct LoggedRtcpPacketFir {
+ LoggedRtcpPacketFir() = default;
+
+ int64_t log_time_us() const { return timestamp.us(); }
+ int64_t log_time_ms() const { return timestamp.ms(); }
+ Timestamp log_time() const { return timestamp; }
+
+ Timestamp timestamp = Timestamp::MinusInfinity();
+ rtcp::Fir fir;
+};
+
+struct LoggedRtcpPacketPli {
+ LoggedRtcpPacketPli() = default;
+
+ int64_t log_time_us() const { return timestamp.us(); }
+ int64_t log_time_ms() const { return timestamp.ms(); }
+ Timestamp log_time() const { return timestamp; }
+
+ Timestamp timestamp = Timestamp::MinusInfinity();
+ rtcp::Pli pli;
+};
+
+struct LoggedRtcpPacketTransportFeedback {
+ LoggedRtcpPacketTransportFeedback()
+ : transport_feedback(/*include_timestamps=*/true) {}
+ LoggedRtcpPacketTransportFeedback(
+ Timestamp timestamp,
+ const rtcp::TransportFeedback& transport_feedback)
+ : timestamp(timestamp), transport_feedback(transport_feedback) {}
+
+ int64_t log_time_us() const { return timestamp.us(); }
+ int64_t log_time_ms() const { return timestamp.ms(); }
+ Timestamp log_time() const { return timestamp; }
+
+ Timestamp timestamp = Timestamp::MinusInfinity();
+ rtcp::TransportFeedback transport_feedback;
+};
+
+struct LoggedRtcpPacketLossNotification {
+ LoggedRtcpPacketLossNotification() = default;
+ LoggedRtcpPacketLossNotification(
+ Timestamp timestamp,
+ const rtcp::LossNotification& loss_notification)
+ : timestamp(timestamp), loss_notification(loss_notification) {}
+
+ int64_t log_time_us() const { return timestamp.us(); }
+ int64_t log_time_ms() const { return timestamp.ms(); }
+ Timestamp log_time() const { return timestamp; }
+
+ Timestamp timestamp = Timestamp::MinusInfinity();
+ rtcp::LossNotification loss_notification;
+};
+
+struct LoggedRtcpPacketBye {
+ LoggedRtcpPacketBye() = default;
+
+ int64_t log_time_us() const { return timestamp.us(); }
+ int64_t log_time_ms() const { return timestamp.ms(); }
+ Timestamp log_time() const { return timestamp; }
+
+ Timestamp timestamp = Timestamp::MinusInfinity();
+ rtcp::Bye bye;
+};
+
+} // namespace webrtc
+
+#endif // LOGGING_RTC_EVENT_LOG_EVENTS_LOGGED_RTP_RTCP_H_
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_alr_state.cc b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_alr_state.cc
new file mode 100644
index 0000000000..25941eb16b
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_alr_state.cc
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2017 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_alr_state.h"
+
+#include "absl/memory/memory.h"
+
+namespace webrtc {
+constexpr RtcEvent::Type RtcEventAlrState::kType;
+constexpr RtcEventDefinition<RtcEventAlrState, LoggedAlrStateEvent, bool>
+ RtcEventAlrState::definition_;
+
+RtcEventAlrState::RtcEventAlrState(bool in_alr) : in_alr_(in_alr) {}
+
+RtcEventAlrState::RtcEventAlrState(const RtcEventAlrState& other)
+ : RtcEvent(other.timestamp_us_), in_alr_(other.in_alr_) {}
+
+RtcEventAlrState::~RtcEventAlrState() = default;
+
+std::unique_ptr<RtcEventAlrState> RtcEventAlrState::Copy() const {
+ return absl::WrapUnique<RtcEventAlrState>(new RtcEventAlrState(*this));
+}
+
+RtcEventLogParseStatus RtcEventAlrState::Parse(
+ absl::string_view s,
+ bool batched,
+ std::vector<LoggedAlrStateEvent>& output) {
+ return RtcEventAlrState::definition_.ParseBatch(s, batched, output);
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_alr_state.h b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_alr_state.h
new file mode 100644
index 0000000000..9f595ecd90
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_alr_state.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2017 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_ALR_STATE_H_
+#define LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_ALR_STATE_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/rtc_event_log/rtc_event.h"
+#include "api/units/timestamp.h"
+#include "logging/rtc_event_log/events/rtc_event_definition.h"
+#include "logging/rtc_event_log/events/rtc_event_field_encoding.h"
+#include "logging/rtc_event_log/events/rtc_event_field_encoding_parser.h"
+#include "logging/rtc_event_log/events/rtc_event_field_extraction.h"
+
+namespace webrtc {
+
+struct LoggedAlrStateEvent {
+ LoggedAlrStateEvent() = default;
+ LoggedAlrStateEvent(Timestamp timestamp, bool in_alr)
+ : timestamp(timestamp), in_alr(in_alr) {}
+
+ int64_t log_time_us() const { return timestamp.us(); }
+ int64_t log_time_ms() const { return timestamp.ms(); }
+ Timestamp log_time() const { return timestamp; }
+
+ Timestamp timestamp = Timestamp::MinusInfinity();
+ bool in_alr;
+};
+
+class RtcEventAlrState final : public RtcEvent {
+ public:
+ static constexpr Type kType = Type::AlrStateEvent;
+
+ explicit RtcEventAlrState(bool in_alr);
+ ~RtcEventAlrState() override;
+
+ Type GetType() const override { return kType; }
+ bool IsConfigEvent() const override { return false; }
+
+ std::unique_ptr<RtcEventAlrState> Copy() const;
+
+ bool in_alr() const { return in_alr_; }
+
+ static std::string Encode(rtc::ArrayView<const RtcEvent*> batch) {
+ return RtcEventAlrState::definition_.EncodeBatch(batch);
+ }
+
+ static RtcEventLogParseStatus Parse(absl::string_view s,
+ bool batched,
+ std::vector<LoggedAlrStateEvent>& output);
+
+ private:
+ RtcEventAlrState(const RtcEventAlrState& other);
+
+ const bool in_alr_;
+
+ static constexpr RtcEventDefinition<RtcEventAlrState,
+ LoggedAlrStateEvent,
+ bool>
+ definition_{{"AlrState", RtcEventAlrState::kType},
+ {&RtcEventAlrState::in_alr_,
+ &LoggedAlrStateEvent::in_alr,
+ {"in_alr", /*id=*/1, FieldType::kFixed8, /*width=*/1}}};
+};
+
+} // namespace webrtc
+#endif // LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_ALR_STATE_H_
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_audio_network_adaptation.cc b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_audio_network_adaptation.cc
new file mode 100644
index 0000000000..5f2d55c357
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_audio_network_adaptation.cc
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2017 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_audio_network_adaptation.h"
+
+#include <utility>
+
+#include "absl/memory/memory.h"
+#include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor_config.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+RtcEventAudioNetworkAdaptation::RtcEventAudioNetworkAdaptation(
+ std::unique_ptr<AudioEncoderRuntimeConfig> config)
+ : config_(std::move(config)) {
+ RTC_DCHECK(config_);
+}
+
+RtcEventAudioNetworkAdaptation::RtcEventAudioNetworkAdaptation(
+ const RtcEventAudioNetworkAdaptation& other)
+ : RtcEvent(other.timestamp_us_),
+ config_(std::make_unique<AudioEncoderRuntimeConfig>(*other.config_)) {}
+
+RtcEventAudioNetworkAdaptation::~RtcEventAudioNetworkAdaptation() = default;
+
+std::unique_ptr<RtcEventAudioNetworkAdaptation>
+RtcEventAudioNetworkAdaptation::Copy() const {
+ return absl::WrapUnique(new RtcEventAudioNetworkAdaptation(*this));
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_audio_network_adaptation.h b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_audio_network_adaptation.h
new file mode 100644
index 0000000000..d4cae3abfa
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_audio_network_adaptation.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2017 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_AUDIO_NETWORK_ADAPTATION_H_
+#define LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_AUDIO_NETWORK_ADAPTATION_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/rtc_event_log/rtc_event.h"
+#include "api/units/timestamp.h"
+#include "logging/rtc_event_log/events/rtc_event_field_encoding_parser.h"
+#include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor_config.h"
+
+namespace webrtc {
+
+struct LoggedAudioNetworkAdaptationEvent {
+ LoggedAudioNetworkAdaptationEvent() = default;
+ LoggedAudioNetworkAdaptationEvent(Timestamp timestamp,
+ const AudioEncoderRuntimeConfig& config)
+ : timestamp(timestamp), config(config) {}
+
+ int64_t log_time_us() const { return timestamp.us(); }
+ int64_t log_time_ms() const { return timestamp.ms(); }
+ Timestamp log_time() const { return timestamp; }
+
+ Timestamp timestamp = Timestamp::MinusInfinity();
+ AudioEncoderRuntimeConfig config;
+};
+
+struct AudioEncoderRuntimeConfig;
+
+class RtcEventAudioNetworkAdaptation final : public RtcEvent {
+ public:
+ static constexpr Type kType = Type::AudioNetworkAdaptation;
+
+ explicit RtcEventAudioNetworkAdaptation(
+ std::unique_ptr<AudioEncoderRuntimeConfig> config);
+ ~RtcEventAudioNetworkAdaptation() override;
+
+ Type GetType() const override { return kType; }
+ bool IsConfigEvent() const override { return false; }
+
+ std::unique_ptr<RtcEventAudioNetworkAdaptation> Copy() const;
+
+ const AudioEncoderRuntimeConfig& config() const { return *config_; }
+
+ static std::string Encode(rtc::ArrayView<const RtcEvent*> batch) {
+ // TODO(terelius): Implement
+ return "";
+ }
+
+ static RtcEventLogParseStatus Parse(
+ absl::string_view encoded_bytes,
+ bool batched,
+ std::vector<LoggedAudioNetworkAdaptationEvent>& output) {
+ // TODO(terelius): Implement
+ return RtcEventLogParseStatus::Error("Not Implemented", __FILE__, __LINE__);
+ }
+
+ private:
+ RtcEventAudioNetworkAdaptation(const RtcEventAudioNetworkAdaptation& other);
+
+ const std::unique_ptr<const AudioEncoderRuntimeConfig> config_;
+};
+
+} // namespace webrtc
+
+#endif // LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_AUDIO_NETWORK_ADAPTATION_H_
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_audio_playout.cc b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_audio_playout.cc
new file mode 100644
index 0000000000..21a3f9266c
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_audio_playout.cc
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2017 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_audio_playout.h"
+
+#include "absl/memory/memory.h"
+
+namespace webrtc {
+
+constexpr RtcEventDefinition<RtcEventAudioPlayout,
+ LoggedAudioPlayoutEvent,
+ uint32_t>
+ RtcEventAudioPlayout::definition_;
+
+RtcEventAudioPlayout::RtcEventAudioPlayout(uint32_t ssrc) : ssrc_(ssrc) {}
+
+RtcEventAudioPlayout::RtcEventAudioPlayout(const RtcEventAudioPlayout& other)
+ : RtcEvent(other.timestamp_us_), ssrc_(other.ssrc_) {}
+
+std::unique_ptr<RtcEventAudioPlayout> RtcEventAudioPlayout::Copy() const {
+ return absl::WrapUnique<RtcEventAudioPlayout>(
+ new RtcEventAudioPlayout(*this));
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_audio_playout.h b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_audio_playout.h
new file mode 100644
index 0000000000..196c3ca247
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_audio_playout.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2017 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_AUDIO_PLAYOUT_H_
+#define LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_AUDIO_PLAYOUT_H_
+
+#include <stdint.h>
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/rtc_event_log/rtc_event.h"
+#include "api/units/timestamp.h"
+#include "logging/rtc_event_log/events/rtc_event_definition.h"
+
+namespace webrtc {
+
+struct LoggedAudioPlayoutEvent {
+ LoggedAudioPlayoutEvent() = default;
+ LoggedAudioPlayoutEvent(Timestamp timestamp, uint32_t ssrc)
+ : timestamp(timestamp), ssrc(ssrc) {}
+
+ int64_t log_time_us() const { return timestamp.us(); }
+ int64_t log_time_ms() const { return timestamp.ms(); }
+ Timestamp log_time() const { return timestamp; }
+
+ Timestamp timestamp = Timestamp::MinusInfinity();
+ uint32_t ssrc;
+};
+
+class RtcEventAudioPlayout final : public RtcEvent {
+ public:
+ static constexpr Type kType = Type::AudioPlayout;
+
+ explicit RtcEventAudioPlayout(uint32_t ssrc);
+ ~RtcEventAudioPlayout() override = default;
+
+ Type GetType() const override { return kType; }
+ bool IsConfigEvent() const override { return false; }
+
+ std::unique_ptr<RtcEventAudioPlayout> Copy() const;
+
+ uint32_t ssrc() const { return ssrc_; }
+
+ static std::string Encode(rtc::ArrayView<const RtcEvent*> batch) {
+ return RtcEventAudioPlayout::definition_.EncodeBatch(batch);
+ }
+
+ static RtcEventLogParseStatus Parse(
+ absl::string_view encoded_bytes,
+ bool batched,
+ std::map<uint32_t, std::vector<LoggedAudioPlayoutEvent>>& output) {
+ std::vector<LoggedAudioPlayoutEvent> temp_output;
+ auto status = RtcEventAudioPlayout::definition_.ParseBatch(
+ encoded_bytes, batched, temp_output);
+ for (const LoggedAudioPlayoutEvent& event : temp_output) {
+ output[event.ssrc].push_back(event);
+ }
+ return status;
+ }
+
+ private:
+ RtcEventAudioPlayout(const RtcEventAudioPlayout& other);
+
+ const uint32_t ssrc_;
+
+ static constexpr RtcEventDefinition<RtcEventAudioPlayout,
+ LoggedAudioPlayoutEvent,
+ uint32_t>
+ definition_{{"AudioPlayout", RtcEventAudioPlayout::kType},
+ {&RtcEventAudioPlayout::ssrc_,
+ &LoggedAudioPlayoutEvent::ssrc,
+ {"ssrc", /*id=*/1, FieldType::kFixed32, /*width=*/32}}};
+};
+
+} // namespace webrtc
+
+#endif // LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_AUDIO_PLAYOUT_H_
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_audio_receive_stream_config.cc b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_audio_receive_stream_config.cc
new file mode 100644
index 0000000000..87caaff098
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_audio_receive_stream_config.cc
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2017 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_audio_receive_stream_config.h"
+
+#include <utility>
+
+#include "absl/memory/memory.h"
+#include "logging/rtc_event_log/rtc_stream_config.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+RtcEventAudioReceiveStreamConfig::RtcEventAudioReceiveStreamConfig(
+ std::unique_ptr<rtclog::StreamConfig> config)
+ : config_(std::move(config)) {
+ RTC_DCHECK(config_);
+}
+
+RtcEventAudioReceiveStreamConfig::RtcEventAudioReceiveStreamConfig(
+ const RtcEventAudioReceiveStreamConfig& other)
+ : RtcEvent(other.timestamp_us_),
+ config_(std::make_unique<rtclog::StreamConfig>(*other.config_)) {}
+
+RtcEventAudioReceiveStreamConfig::~RtcEventAudioReceiveStreamConfig() = default;
+
+std::unique_ptr<RtcEventAudioReceiveStreamConfig>
+RtcEventAudioReceiveStreamConfig::Copy() const {
+ return absl::WrapUnique<RtcEventAudioReceiveStreamConfig>(
+ new RtcEventAudioReceiveStreamConfig(*this));
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_audio_receive_stream_config.h b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_audio_receive_stream_config.h
new file mode 100644
index 0000000000..9863e235af
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_audio_receive_stream_config.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2017 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_AUDIO_RECEIVE_STREAM_CONFIG_H_
+#define LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_AUDIO_RECEIVE_STREAM_CONFIG_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/rtc_event_log/rtc_event.h"
+#include "api/units/timestamp.h"
+#include "logging/rtc_event_log/events/rtc_event_field_encoding_parser.h"
+#include "logging/rtc_event_log/rtc_stream_config.h"
+
+namespace webrtc {
+
+struct LoggedAudioRecvConfig {
+ LoggedAudioRecvConfig() = default;
+ LoggedAudioRecvConfig(Timestamp timestamp, const rtclog::StreamConfig config)
+ : timestamp(timestamp), config(config) {}
+
+ int64_t log_time_us() const { return timestamp.us(); }
+ int64_t log_time_ms() const { return timestamp.ms(); }
+ Timestamp log_time() const { return timestamp; }
+
+ Timestamp timestamp = Timestamp::MinusInfinity();
+ rtclog::StreamConfig config;
+};
+
+class RtcEventAudioReceiveStreamConfig final : public RtcEvent {
+ public:
+ static constexpr Type kType = Type::AudioReceiveStreamConfig;
+
+ explicit RtcEventAudioReceiveStreamConfig(
+ std::unique_ptr<rtclog::StreamConfig> config);
+ ~RtcEventAudioReceiveStreamConfig() override;
+
+ Type GetType() const override { return kType; }
+ bool IsConfigEvent() const override { return true; }
+
+ std::unique_ptr<RtcEventAudioReceiveStreamConfig> Copy() const;
+
+ const rtclog::StreamConfig& config() const { return *config_; }
+
+ static std::string Encode(rtc::ArrayView<const RtcEvent*> batch) {
+ // TODO(terelius): Implement
+ return "";
+ }
+
+ static RtcEventLogParseStatus Parse(
+ absl::string_view encoded_bytes,
+ bool batched,
+ std::vector<LoggedAudioRecvConfig>& output) {
+ // TODO(terelius): Implement
+ return RtcEventLogParseStatus::Error("Not Implemented", __FILE__, __LINE__);
+ }
+
+ private:
+ RtcEventAudioReceiveStreamConfig(
+ const RtcEventAudioReceiveStreamConfig& other);
+
+ const std::unique_ptr<const rtclog::StreamConfig> config_;
+};
+
+} // namespace webrtc
+
+#endif // LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_AUDIO_RECEIVE_STREAM_CONFIG_H_
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_audio_send_stream_config.cc b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_audio_send_stream_config.cc
new file mode 100644
index 0000000000..681ae11e63
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_audio_send_stream_config.cc
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2017 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_audio_send_stream_config.h"
+
+#include <utility>
+
+#include "absl/memory/memory.h"
+#include "logging/rtc_event_log/rtc_stream_config.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+RtcEventAudioSendStreamConfig::RtcEventAudioSendStreamConfig(
+ std::unique_ptr<rtclog::StreamConfig> config)
+ : config_(std::move(config)) {
+ RTC_DCHECK(config_);
+}
+
+RtcEventAudioSendStreamConfig::RtcEventAudioSendStreamConfig(
+ const RtcEventAudioSendStreamConfig& other)
+ : RtcEvent(other.timestamp_us_),
+ config_(std::make_unique<rtclog::StreamConfig>(*other.config_)) {}
+
+RtcEventAudioSendStreamConfig::~RtcEventAudioSendStreamConfig() = default;
+
+std::unique_ptr<RtcEventAudioSendStreamConfig>
+RtcEventAudioSendStreamConfig::Copy() const {
+ return absl::WrapUnique<RtcEventAudioSendStreamConfig>(
+ new RtcEventAudioSendStreamConfig(*this));
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_audio_send_stream_config.h b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_audio_send_stream_config.h
new file mode 100644
index 0000000000..550723bcf0
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_audio_send_stream_config.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2017 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_AUDIO_SEND_STREAM_CONFIG_H_
+#define LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_AUDIO_SEND_STREAM_CONFIG_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/rtc_event_log/rtc_event.h"
+#include "logging/rtc_event_log/events/rtc_event_field_encoding_parser.h"
+#include "logging/rtc_event_log/rtc_stream_config.h"
+
+namespace webrtc {
+
+struct LoggedAudioSendConfig {
+ LoggedAudioSendConfig() = default;
+ LoggedAudioSendConfig(Timestamp timestamp, const rtclog::StreamConfig config)
+ : timestamp(timestamp), config(config) {}
+
+ int64_t log_time_us() const { return timestamp.us(); }
+ int64_t log_time_ms() const { return timestamp.ms(); }
+ Timestamp log_time() const { return timestamp; }
+
+ Timestamp timestamp = Timestamp::MinusInfinity();
+ rtclog::StreamConfig config;
+};
+
+class RtcEventAudioSendStreamConfig final : public RtcEvent {
+ public:
+ static constexpr Type kType = Type::AudioSendStreamConfig;
+
+ explicit RtcEventAudioSendStreamConfig(
+ std::unique_ptr<rtclog::StreamConfig> config);
+ ~RtcEventAudioSendStreamConfig() override;
+
+ Type GetType() const override { return kType; }
+ bool IsConfigEvent() const override { return true; }
+
+ std::unique_ptr<RtcEventAudioSendStreamConfig> Copy() const;
+
+ const rtclog::StreamConfig& config() const { return *config_; }
+
+ static std::string Encode(rtc::ArrayView<const RtcEvent*> batch) {
+ // TODO(terelius): Implement
+ return "";
+ }
+
+ static RtcEventLogParseStatus Parse(
+ absl::string_view encoded_bytes,
+ bool batched,
+ std::vector<LoggedAudioSendConfig>& output) {
+ // TODO(terelius): Implement
+ return RtcEventLogParseStatus::Error("Not Implemented", __FILE__, __LINE__);
+ }
+
+ private:
+ RtcEventAudioSendStreamConfig(const RtcEventAudioSendStreamConfig& other);
+
+ const std::unique_ptr<const rtclog::StreamConfig> config_;
+};
+
+} // namespace webrtc
+
+#endif // LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_AUDIO_SEND_STREAM_CONFIG_H_
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_begin_log.cc b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_begin_log.cc
new file mode 100644
index 0000000000..49b9effa9e
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_begin_log.cc
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2021 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_begin_log.h"
+
+#include "absl/strings/string_view.h"
+
+namespace webrtc {
+constexpr RtcEvent::Type RtcEventBeginLog::kType;
+constexpr EventParameters RtcEventBeginLog::event_params_;
+constexpr FieldParameters RtcEventBeginLog::utc_start_time_params_;
+
+RtcEventBeginLog::RtcEventBeginLog(Timestamp timestamp,
+ Timestamp utc_start_time)
+ : RtcEvent(timestamp.us()), utc_start_time_ms_(utc_start_time.ms()) {}
+
+RtcEventBeginLog::RtcEventBeginLog(const RtcEventBeginLog& other)
+ : RtcEvent(other.timestamp_us_) {}
+
+RtcEventBeginLog::~RtcEventBeginLog() = default;
+
+std::string RtcEventBeginLog::Encode(rtc::ArrayView<const RtcEvent*> batch) {
+ EventEncoder encoder(event_params_, batch);
+
+ encoder.EncodeField(
+ utc_start_time_params_,
+ ExtractRtcEventMember(batch, &RtcEventBeginLog::utc_start_time_ms_));
+
+ return encoder.AsString();
+}
+
+RtcEventLogParseStatus RtcEventBeginLog::Parse(
+ absl::string_view encoded_bytes,
+ bool batched,
+ std::vector<LoggedStartEvent>& output) {
+ EventParser parser;
+ auto status = parser.Initialize(encoded_bytes, batched);
+ if (!status.ok())
+ return status;
+
+ rtc::ArrayView<LoggedStartEvent> output_batch =
+ ExtendLoggedBatch(output, parser.NumEventsInBatch());
+
+ constexpr FieldParameters timestamp_params{
+ "timestamp_ms", FieldParameters::kTimestampField, FieldType::kVarInt, 64};
+ RtcEventLogParseStatusOr<rtc::ArrayView<uint64_t>> result =
+ parser.ParseNumericField(timestamp_params);
+ if (!result.ok())
+ return result.status();
+ status = PopulateRtcEventTimestamp(
+ result.value(), &LoggedStartEvent::timestamp, output_batch);
+ if (!status.ok())
+ return status;
+
+ result = parser.ParseNumericField(utc_start_time_params_);
+ if (!result.ok())
+ return result.status();
+ status = PopulateRtcEventTimestamp(
+ result.value(), &LoggedStartEvent::utc_start_time, output_batch);
+ if (!status.ok())
+ return status;
+
+ return RtcEventLogParseStatus::Success();
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_begin_log.h b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_begin_log.h
new file mode 100644
index 0000000000..f3b74c117e
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_begin_log.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2021 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_BEGIN_LOG_H_
+#define LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_BEGIN_LOG_H_
+
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/array_view.h"
+#include "api/rtc_event_log/rtc_event.h"
+#include "api/units/timestamp.h"
+#include "logging/rtc_event_log/events/rtc_event_field_encoding.h"
+#include "logging/rtc_event_log/events/rtc_event_field_encoding_parser.h"
+#include "logging/rtc_event_log/events/rtc_event_field_extraction.h"
+
+namespace webrtc {
+
+struct LoggedStartEvent {
+ LoggedStartEvent() = default;
+
+ explicit LoggedStartEvent(Timestamp timestamp)
+ : LoggedStartEvent(timestamp, timestamp) {}
+
+ LoggedStartEvent(Timestamp timestamp, Timestamp utc_start_time)
+ : timestamp(timestamp), utc_start_time(utc_start_time) {}
+
+ int64_t log_time_us() const { return timestamp.us(); }
+ int64_t log_time_ms() const { return timestamp.ms(); }
+ Timestamp log_time() const { return timestamp; }
+
+ Timestamp utc_time() const { return utc_start_time; }
+
+ Timestamp timestamp = Timestamp::PlusInfinity();
+ Timestamp utc_start_time = Timestamp::PlusInfinity();
+};
+
+class RtcEventBeginLog final : public RtcEvent {
+ public:
+ static constexpr Type kType = Type::BeginV3Log;
+
+ RtcEventBeginLog(Timestamp timestamp, Timestamp utc_start_time);
+ ~RtcEventBeginLog() override;
+
+ Type GetType() const override { return kType; }
+ bool IsConfigEvent() const override { return false; }
+
+ static std::string Encode(rtc::ArrayView<const RtcEvent*> batch);
+
+ static RtcEventLogParseStatus Parse(absl::string_view encoded_bytes,
+ bool batched,
+ std::vector<LoggedStartEvent>& output);
+
+ private:
+ RtcEventBeginLog(const RtcEventBeginLog& other);
+
+ int64_t utc_start_time_ms_;
+
+ static constexpr EventParameters event_params_{"BeginLog",
+ RtcEventBeginLog::kType};
+ static constexpr FieldParameters utc_start_time_params_{
+ "utc_start_time_ms", /*id=*/1, FieldType::kVarInt, /*width=*/64};
+};
+
+} // namespace webrtc
+#endif // LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_BEGIN_LOG_H_
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_bwe_update_delay_based.cc b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_bwe_update_delay_based.cc
new file mode 100644
index 0000000000..0e98b2ff11
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_bwe_update_delay_based.cc
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2017 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_bwe_update_delay_based.h"
+
+#include "absl/memory/memory.h"
+#include "api/network_state_predictor.h"
+
+namespace webrtc {
+
+constexpr RtcEventDefinition<RtcEventBweUpdateDelayBased,
+ LoggedBweDelayBasedUpdate,
+ int32_t,
+ BandwidthUsage>
+ RtcEventBweUpdateDelayBased::definition_;
+
+RtcEventBweUpdateDelayBased::RtcEventBweUpdateDelayBased(
+ int32_t bitrate_bps,
+ BandwidthUsage detector_state)
+ : bitrate_bps_(bitrate_bps), detector_state_(detector_state) {}
+
+RtcEventBweUpdateDelayBased::RtcEventBweUpdateDelayBased(
+ const RtcEventBweUpdateDelayBased& other)
+ : RtcEvent(other.timestamp_us_),
+ bitrate_bps_(other.bitrate_bps_),
+ detector_state_(other.detector_state_) {}
+
+RtcEventBweUpdateDelayBased::~RtcEventBweUpdateDelayBased() = default;
+
+std::unique_ptr<RtcEventBweUpdateDelayBased> RtcEventBweUpdateDelayBased::Copy()
+ const {
+ return absl::WrapUnique<RtcEventBweUpdateDelayBased>(
+ new RtcEventBweUpdateDelayBased(*this));
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_bwe_update_delay_based.h b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_bwe_update_delay_based.h
new file mode 100644
index 0000000000..796f119388
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_bwe_update_delay_based.h
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2017 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_BWE_UPDATE_DELAY_BASED_H_
+#define LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_BWE_UPDATE_DELAY_BASED_H_
+
+#include <stdint.h>
+
+#include <limits>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/network_state_predictor.h"
+#include "api/rtc_event_log/rtc_event.h"
+#include "api/units/timestamp.h"
+#include "logging/rtc_event_log/events/rtc_event_definition.h"
+
+namespace webrtc {
+
+// Separate the event log encoding from the enum values.
+// As long as the enum values are the same as the encodings,
+// the two conversion functions can be compiled to (roughly)
+// a range check each.
+template <>
+class RtcEventLogEnum<BandwidthUsage> {
+ static constexpr uint64_t kBwNormal = 0;
+ static constexpr uint64_t kBwUnderusing = 1;
+ static constexpr uint64_t kBwOverusing = 2;
+
+ public:
+ static uint64_t Encode(BandwidthUsage x) {
+ switch (x) {
+ case BandwidthUsage::kBwNormal:
+ return kBwNormal;
+ case BandwidthUsage::kBwUnderusing:
+ return kBwUnderusing;
+ case BandwidthUsage::kBwOverusing:
+ return kBwOverusing;
+ case BandwidthUsage::kLast:
+ RTC_DCHECK_NOTREACHED();
+ }
+ RTC_DCHECK_NOTREACHED();
+ return std::numeric_limits<uint64_t>::max();
+ }
+ static RtcEventLogParseStatusOr<BandwidthUsage> Decode(uint64_t x) {
+ switch (x) {
+ case kBwNormal:
+ return BandwidthUsage::kBwNormal;
+ case kBwUnderusing:
+ return BandwidthUsage::kBwUnderusing;
+ case kBwOverusing:
+ return BandwidthUsage::kBwOverusing;
+ }
+ return RtcEventLogParseStatus::Error("Failed to decode BandwidthUsage enum",
+ __FILE__, __LINE__);
+ }
+};
+
+struct LoggedBweDelayBasedUpdate {
+ LoggedBweDelayBasedUpdate() = default;
+ LoggedBweDelayBasedUpdate(Timestamp timestamp,
+ int32_t bitrate_bps,
+ BandwidthUsage detector_state)
+ : timestamp(timestamp),
+ bitrate_bps(bitrate_bps),
+ detector_state(detector_state) {}
+
+ int64_t log_time_us() const { return timestamp.us(); }
+ int64_t log_time_ms() const { return timestamp.ms(); }
+ Timestamp log_time() const { return timestamp; }
+
+ Timestamp timestamp = Timestamp::MinusInfinity();
+ int32_t bitrate_bps;
+ BandwidthUsage detector_state;
+};
+
+class RtcEventBweUpdateDelayBased final : public RtcEvent {
+ public:
+ static constexpr Type kType = Type::BweUpdateDelayBased;
+
+ RtcEventBweUpdateDelayBased(int32_t bitrate_bps,
+ BandwidthUsage detector_state);
+ ~RtcEventBweUpdateDelayBased() override;
+
+ Type GetType() const override { return kType; }
+ bool IsConfigEvent() const override { return false; }
+
+ std::unique_ptr<RtcEventBweUpdateDelayBased> Copy() const;
+
+ int32_t bitrate_bps() const { return bitrate_bps_; }
+ BandwidthUsage detector_state() const { return detector_state_; }
+
+ static std::string Encode(rtc::ArrayView<const RtcEvent*> batch) {
+ return RtcEventBweUpdateDelayBased::definition_.EncodeBatch(batch);
+ }
+
+ static RtcEventLogParseStatus Parse(
+ absl::string_view encoded_bytes,
+ bool batched,
+ std::vector<LoggedBweDelayBasedUpdate>& output) {
+ return RtcEventBweUpdateDelayBased::definition_.ParseBatch(encoded_bytes,
+ batched, output);
+ }
+
+ private:
+ RtcEventBweUpdateDelayBased(const RtcEventBweUpdateDelayBased& other);
+
+ const int32_t bitrate_bps_;
+ const BandwidthUsage detector_state_;
+
+ static constexpr RtcEventDefinition<RtcEventBweUpdateDelayBased,
+ LoggedBweDelayBasedUpdate,
+ int32_t,
+ BandwidthUsage>
+ definition_{
+ {"BweDelayBased", RtcEventBweUpdateDelayBased::kType},
+ {&RtcEventBweUpdateDelayBased::bitrate_bps_,
+ &LoggedBweDelayBasedUpdate::bitrate_bps,
+ {"bitrate_bps", /*id=*/1, FieldType::kVarInt, /*width=*/32}},
+ {&RtcEventBweUpdateDelayBased::detector_state_,
+ &LoggedBweDelayBasedUpdate::detector_state,
+ {"detector_state", /*id=*/2, FieldType::kVarInt, /*width=*/64}}};
+};
+
+} // namespace webrtc
+
+#endif // LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_BWE_UPDATE_DELAY_BASED_H_
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_bwe_update_loss_based.cc b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_bwe_update_loss_based.cc
new file mode 100644
index 0000000000..44524ab033
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_bwe_update_loss_based.cc
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2017 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_bwe_update_loss_based.h"
+
+#include "absl/memory/memory.h"
+
+namespace webrtc {
+
+RtcEventBweUpdateLossBased::RtcEventBweUpdateLossBased(int32_t bitrate_bps,
+ uint8_t fraction_loss,
+ int32_t total_packets)
+ : bitrate_bps_(bitrate_bps),
+ fraction_loss_(fraction_loss),
+ total_packets_(total_packets) {}
+
+RtcEventBweUpdateLossBased::RtcEventBweUpdateLossBased(
+ const RtcEventBweUpdateLossBased& other)
+ : RtcEvent(other.timestamp_us_),
+ bitrate_bps_(other.bitrate_bps_),
+ fraction_loss_(other.fraction_loss_),
+ total_packets_(other.total_packets_) {}
+
+RtcEventBweUpdateLossBased::~RtcEventBweUpdateLossBased() = default;
+
+std::unique_ptr<RtcEventBweUpdateLossBased> RtcEventBweUpdateLossBased::Copy()
+ const {
+ return absl::WrapUnique<RtcEventBweUpdateLossBased>(
+ new RtcEventBweUpdateLossBased(*this));
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_bwe_update_loss_based.h b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_bwe_update_loss_based.h
new file mode 100644
index 0000000000..fd41b316e0
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_bwe_update_loss_based.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2017 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_BWE_UPDATE_LOSS_BASED_H_
+#define LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_BWE_UPDATE_LOSS_BASED_H_
+
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/rtc_event_log/rtc_event.h"
+#include "api/units/timestamp.h"
+#include "logging/rtc_event_log/events/rtc_event_field_encoding_parser.h"
+
+namespace webrtc {
+
+struct LoggedBweLossBasedUpdate {
+ LoggedBweLossBasedUpdate() = default;
+ LoggedBweLossBasedUpdate(Timestamp timestamp,
+ int32_t bitrate_bps,
+ uint8_t fraction_lost,
+ int32_t expected_packets)
+ : timestamp(timestamp),
+ bitrate_bps(bitrate_bps),
+ fraction_lost(fraction_lost),
+ expected_packets(expected_packets) {}
+
+ int64_t log_time_us() const { return timestamp.us(); }
+ int64_t log_time_ms() const { return timestamp.ms(); }
+ Timestamp log_time() const { return timestamp; }
+
+ Timestamp timestamp = Timestamp::MinusInfinity();
+ int32_t bitrate_bps;
+ uint8_t fraction_lost;
+ int32_t expected_packets;
+};
+
+class RtcEventBweUpdateLossBased final : public RtcEvent {
+ public:
+ static constexpr Type kType = Type::BweUpdateLossBased;
+
+ RtcEventBweUpdateLossBased(int32_t bitrate_bps_,
+ uint8_t fraction_loss_,
+ int32_t total_packets_);
+ ~RtcEventBweUpdateLossBased() override;
+
+ Type GetType() const override { return kType; }
+ bool IsConfigEvent() const override { return false; }
+
+ std::unique_ptr<RtcEventBweUpdateLossBased> Copy() const;
+
+ int32_t bitrate_bps() const { return bitrate_bps_; }
+ uint8_t fraction_loss() const { return fraction_loss_; }
+ int32_t total_packets() const { return total_packets_; }
+
+ static std::string Encode(rtc::ArrayView<const RtcEvent*> batch) {
+ // TODO(terelius): Implement
+ return "";
+ }
+
+ static RtcEventLogParseStatus Parse(
+ absl::string_view encoded_bytes,
+ bool batched,
+ std::vector<LoggedBweLossBasedUpdate>& output) {
+ // TODO(terelius): Implement
+ return RtcEventLogParseStatus::Error("Not Implemented", __FILE__, __LINE__);
+ }
+
+ private:
+ RtcEventBweUpdateLossBased(const RtcEventBweUpdateLossBased& other);
+
+ const int32_t bitrate_bps_;
+ const uint8_t fraction_loss_;
+ const int32_t total_packets_;
+};
+
+} // namespace webrtc
+
+#endif // LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_BWE_UPDATE_LOSS_BASED_H_
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_definition.h b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_definition.h
new file mode 100644
index 0000000000..8688c5fc7b
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_definition.h
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2021 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_DEFINITION_H_
+#define LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_DEFINITION_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "api/units/timestamp.h"
+#include "logging/rtc_event_log/events/rtc_event_field_encoding.h"
+#include "logging/rtc_event_log/events/rtc_event_field_encoding_parser.h"
+#include "logging/rtc_event_log/events/rtc_event_field_extraction.h"
+#include "rtc_base/logging.h"
+
+namespace webrtc {
+
+template <typename EventType, typename LoggedType, typename T>
+struct RtcEventFieldDefinition {
+ const T EventType::*event_member;
+ T LoggedType::*logged_member;
+ FieldParameters params;
+};
+
+// Base case
+template <typename EventType, typename LoggedType, typename... Ts>
+class RtcEventDefinitionImpl {
+ public:
+ void EncodeImpl(EventEncoder&, rtc::ArrayView<const RtcEvent*>) const {}
+ RtcEventLogParseStatus ParseImpl(EventParser&,
+ rtc::ArrayView<LoggedType>) const {
+ return RtcEventLogParseStatus::Success();
+ }
+};
+
+// Recursive case
+template <typename EventType, typename LoggedType, typename T, typename... Ts>
+class RtcEventDefinitionImpl<EventType, LoggedType, T, Ts...> {
+ public:
+ constexpr RtcEventDefinitionImpl(
+ RtcEventFieldDefinition<EventType, LoggedType, T> field,
+ RtcEventFieldDefinition<EventType, LoggedType, Ts>... rest)
+ : field_(field), rest_(rest...) {}
+
+ void EncodeImpl(EventEncoder& encoder,
+ rtc::ArrayView<const RtcEvent*> batch) const {
+ auto values = ExtractRtcEventMember(batch, field_.event_member);
+ encoder.EncodeField(field_.params, values);
+ rest_.EncodeImpl(encoder, batch);
+ }
+
+ RtcEventLogParseStatus ParseImpl(
+ EventParser& parser,
+ rtc::ArrayView<LoggedType> output_batch) const {
+ RtcEventLogParseStatusOr<rtc::ArrayView<uint64_t>> result =
+ parser.ParseNumericField(field_.params);
+ if (!result.ok())
+ return result.status();
+ auto status = PopulateRtcEventMember(result.value(), field_.logged_member,
+ output_batch);
+ if (!status.ok())
+ return status;
+
+ return rest_.ParseImpl(parser, output_batch);
+ }
+
+ private:
+ RtcEventFieldDefinition<EventType, LoggedType, T> field_;
+ RtcEventDefinitionImpl<EventType, LoggedType, Ts...> rest_;
+};
+
+// The RtcEventDefinition sets up a mapping between the fields
+// in an RtcEvent and the corresponding fields in the parsed struct.
+// For example, an RtcFoo class containing two fields; `uint32_t bar`
+// and `bool baz` (a log timestamp is always implicitly added)
+// might have a definition
+// RtcEventDefinition<RtcFoo, LoggedFoo, uint32_t, bool>(
+// {"foo", RtcFoo::Type},
+// {&RtcFoo::bar_, &LoggedFoo::bar, {"bar", 1, FieldType::kVarInt, 32}},
+// {&RtcFoo::baz_, &LoggedFoo::baz, {"baz", 2, FieldType::kFixed8, 1}},
+// );
+// In addition to defining string names to aid debugging,
+// this specifies that
+// * RtcFoo::Type uniquely identifies an RtcFoo in the encoded stream
+// * The `bar` field has ID 1, is encoded as a VarInt
+// (when not delta compressed), and wraps around after 32 bits.
+// * The `baz` field has ID 2, is encoded as an 8-bit field
+// (when not delta compressed), and wraps around after 1 bit.
+// Note that the numerical field and event IDs can't be changed since
+// that would break compatibility with old logs.
+// In most cases (including all cases where wrap around isn't
+// expected), the wrap around should be equal to the bitwidth of
+// the field.
+template <typename EventType, typename LoggedType, typename... Ts>
+class RtcEventDefinition {
+ public:
+ constexpr RtcEventDefinition(
+ EventParameters params,
+ RtcEventFieldDefinition<EventType, LoggedType, Ts>... fields)
+ : params_(params), fields_(fields...) {}
+
+ std::string EncodeBatch(rtc::ArrayView<const RtcEvent*> batch) const {
+ EventEncoder encoder(params_, batch);
+ fields_.EncodeImpl(encoder, batch);
+ return encoder.AsString();
+ }
+
+ RtcEventLogParseStatus ParseBatch(absl::string_view s,
+ bool batched,
+ std::vector<LoggedType>& output) const {
+ EventParser parser;
+ auto status = parser.Initialize(s, batched);
+ if (!status.ok())
+ return status;
+
+ rtc::ArrayView<LoggedType> output_batch =
+ ExtendLoggedBatch(output, parser.NumEventsInBatch());
+
+ constexpr FieldParameters timestamp_params{"timestamp_ms",
+ FieldParameters::kTimestampField,
+ FieldType::kVarInt, 64};
+ RtcEventLogParseStatusOr<rtc::ArrayView<uint64_t>> result =
+ parser.ParseNumericField(timestamp_params);
+ if (!result.ok())
+ return result.status();
+ status = PopulateRtcEventTimestamp(result.value(), &LoggedType::timestamp,
+ output_batch);
+ if (!status.ok())
+ return status;
+
+ return fields_.ParseImpl(parser, output_batch);
+ }
+
+ private:
+ EventParameters params_;
+ RtcEventDefinitionImpl<EventType, LoggedType, Ts...> fields_;
+};
+
+} // namespace webrtc
+
+#endif // LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_DEFINITION_H_
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_dtls_transport_state.cc b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_dtls_transport_state.cc
new file mode 100644
index 0000000000..f00342df72
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_dtls_transport_state.cc
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2018 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_dtls_transport_state.h"
+
+#include "absl/memory/memory.h"
+
+namespace webrtc {
+
+RtcEventDtlsTransportState::RtcEventDtlsTransportState(DtlsTransportState state)
+ : dtls_transport_state_(state) {}
+
+RtcEventDtlsTransportState::RtcEventDtlsTransportState(
+ const RtcEventDtlsTransportState& other)
+ : RtcEvent(other.timestamp_us_),
+ dtls_transport_state_(other.dtls_transport_state_) {}
+
+RtcEventDtlsTransportState::~RtcEventDtlsTransportState() = default;
+
+std::unique_ptr<RtcEventDtlsTransportState> RtcEventDtlsTransportState::Copy()
+ const {
+ return absl::WrapUnique<RtcEventDtlsTransportState>(
+ new RtcEventDtlsTransportState(*this));
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_dtls_transport_state.h b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_dtls_transport_state.h
new file mode 100644
index 0000000000..b9af213256
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_dtls_transport_state.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2018 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_DTLS_TRANSPORT_STATE_H_
+#define LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_DTLS_TRANSPORT_STATE_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/dtls_transport_interface.h"
+#include "api/rtc_event_log/rtc_event.h"
+#include "api/units/timestamp.h"
+#include "logging/rtc_event_log/events/rtc_event_field_encoding_parser.h"
+
+namespace webrtc {
+
+struct LoggedDtlsTransportState {
+ int64_t log_time_us() const { return timestamp.us(); }
+ int64_t log_time_ms() const { return timestamp.ms(); }
+ Timestamp log_time() const { return timestamp; }
+
+ Timestamp timestamp = Timestamp::MinusInfinity();
+ DtlsTransportState dtls_transport_state;
+};
+
+class RtcEventDtlsTransportState : public RtcEvent {
+ public:
+ static constexpr Type kType = Type::DtlsTransportState;
+
+ explicit RtcEventDtlsTransportState(DtlsTransportState state);
+ ~RtcEventDtlsTransportState() override;
+
+ Type GetType() const override { return kType; }
+ bool IsConfigEvent() const override { return false; }
+
+ std::unique_ptr<RtcEventDtlsTransportState> Copy() const;
+
+ DtlsTransportState dtls_transport_state() const {
+ return dtls_transport_state_;
+ }
+
+ static std::string Encode(rtc::ArrayView<const RtcEvent*> batch) {
+ // TODO(terelius): Implement
+ return "";
+ }
+
+ static RtcEventLogParseStatus Parse(
+ absl::string_view encoded_bytes,
+ bool batched,
+ std::vector<LoggedDtlsTransportState>& output) {
+ // TODO(terelius): Implement
+ return RtcEventLogParseStatus::Error("Not Implemented", __FILE__, __LINE__);
+ }
+
+ private:
+ RtcEventDtlsTransportState(const RtcEventDtlsTransportState& other);
+
+ const DtlsTransportState dtls_transport_state_;
+};
+
+} // namespace webrtc
+
+#endif // LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_DTLS_TRANSPORT_STATE_H_
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_dtls_writable_state.cc b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_dtls_writable_state.cc
new file mode 100644
index 0000000000..d4cb093ce6
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_dtls_writable_state.cc
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2018 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_dtls_writable_state.h"
+
+#include "absl/memory/memory.h"
+
+namespace webrtc {
+
+RtcEventDtlsWritableState::RtcEventDtlsWritableState(bool writable)
+ : writable_(writable) {}
+
+RtcEventDtlsWritableState::RtcEventDtlsWritableState(
+ const RtcEventDtlsWritableState& other)
+ : RtcEvent(other.timestamp_us_), writable_(other.writable_) {}
+
+RtcEventDtlsWritableState::~RtcEventDtlsWritableState() = default;
+
+std::unique_ptr<RtcEventDtlsWritableState> RtcEventDtlsWritableState::Copy()
+ const {
+ return absl::WrapUnique<RtcEventDtlsWritableState>(
+ new RtcEventDtlsWritableState(*this));
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_dtls_writable_state.h b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_dtls_writable_state.h
new file mode 100644
index 0000000000..c820f184d7
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_dtls_writable_state.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2018 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_DTLS_WRITABLE_STATE_H_
+#define LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_DTLS_WRITABLE_STATE_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/rtc_event_log/rtc_event.h"
+#include "api/units/timestamp.h"
+#include "logging/rtc_event_log/events/rtc_event_field_encoding_parser.h"
+
+namespace webrtc {
+
+struct LoggedDtlsWritableState {
+ LoggedDtlsWritableState() = default;
+ explicit LoggedDtlsWritableState(bool writable) : writable(writable) {}
+
+ int64_t log_time_us() const { return timestamp.us(); }
+ int64_t log_time_ms() const { return timestamp.ms(); }
+ Timestamp log_time() const { return timestamp; }
+
+ Timestamp timestamp = Timestamp::MinusInfinity();
+ bool writable;
+};
+
+class RtcEventDtlsWritableState : public RtcEvent {
+ public:
+ static constexpr Type kType = Type::DtlsWritableState;
+
+ explicit RtcEventDtlsWritableState(bool writable);
+ ~RtcEventDtlsWritableState() override;
+
+ Type GetType() const override { return kType; }
+ bool IsConfigEvent() const override { return false; }
+
+ std::unique_ptr<RtcEventDtlsWritableState> Copy() const;
+
+ bool writable() const { return writable_; }
+
+ static std::string Encode(rtc::ArrayView<const RtcEvent*> batch) {
+ // TODO(terelius): Implement
+ return "";
+ }
+
+ static RtcEventLogParseStatus Parse(
+ absl::string_view encoded_bytes,
+ bool batched,
+ std::vector<LoggedDtlsWritableState>& output) {
+ // TODO(terelius): Implement
+ return RtcEventLogParseStatus::Error("Not Implemented", __FILE__, __LINE__);
+ }
+
+ private:
+ RtcEventDtlsWritableState(const RtcEventDtlsWritableState& other);
+
+ const bool writable_;
+};
+
+} // namespace webrtc
+
+#endif // LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_DTLS_WRITABLE_STATE_H_
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_end_log.cc b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_end_log.cc
new file mode 100644
index 0000000000..52abf9e842
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_end_log.cc
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2021 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_end_log.h"
+
+#include "absl/strings/string_view.h"
+
+namespace webrtc {
+constexpr RtcEvent::Type RtcEventEndLog::kType;
+constexpr EventParameters RtcEventEndLog::event_params_;
+
+RtcEventEndLog::RtcEventEndLog(Timestamp timestamp)
+ : RtcEvent(timestamp.us()) {}
+
+RtcEventEndLog::RtcEventEndLog(const RtcEventEndLog& other)
+ : RtcEvent(other.timestamp_us_) {}
+
+RtcEventEndLog::~RtcEventEndLog() = default;
+
+std::string RtcEventEndLog::Encode(rtc::ArrayView<const RtcEvent*> batch) {
+ EventEncoder encoder(event_params_, batch);
+ return encoder.AsString();
+}
+
+RtcEventLogParseStatus RtcEventEndLog::Parse(
+ absl::string_view encoded_bytes,
+ bool batched,
+ std::vector<LoggedStopEvent>& output) {
+ EventParser parser;
+ auto status = parser.Initialize(encoded_bytes, batched);
+ if (!status.ok())
+ return status;
+
+ rtc::ArrayView<LoggedStopEvent> output_batch =
+ ExtendLoggedBatch(output, parser.NumEventsInBatch());
+
+ constexpr FieldParameters timestamp_params{
+ "timestamp_ms", FieldParameters::kTimestampField, FieldType::kVarInt, 64};
+ RtcEventLogParseStatusOr<rtc::ArrayView<uint64_t>> result =
+ parser.ParseNumericField(timestamp_params);
+ if (!result.ok())
+ return result.status();
+ status = PopulateRtcEventTimestamp(result.value(),
+ &LoggedStopEvent::timestamp, output_batch);
+ if (!status.ok())
+ return status;
+
+ return RtcEventLogParseStatus::Success();
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_end_log.h b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_end_log.h
new file mode 100644
index 0000000000..79648bdb8d
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_end_log.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2021 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_END_LOG_H_
+#define LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_END_LOG_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/array_view.h"
+#include "api/rtc_event_log/rtc_event.h"
+#include "api/units/timestamp.h"
+#include "logging/rtc_event_log/events/rtc_event_field_encoding.h"
+#include "logging/rtc_event_log/events/rtc_event_field_encoding_parser.h"
+#include "logging/rtc_event_log/events/rtc_event_field_extraction.h"
+
+namespace webrtc {
+
+struct LoggedStopEvent {
+ LoggedStopEvent() = default;
+
+ explicit LoggedStopEvent(Timestamp timestamp) : timestamp(timestamp) {}
+
+ int64_t log_time_us() const { return timestamp.us(); }
+ int64_t log_time_ms() const { return timestamp.ms(); }
+ Timestamp log_time() const { return timestamp; }
+
+ Timestamp timestamp = Timestamp::PlusInfinity();
+};
+
+class RtcEventEndLog final : public RtcEvent {
+ public:
+ static constexpr Type kType = Type::EndV3Log;
+
+ explicit RtcEventEndLog(Timestamp timestamp);
+ ~RtcEventEndLog() override;
+
+ Type GetType() const override { return kType; }
+ bool IsConfigEvent() const override { return false; }
+
+ static std::string Encode(rtc::ArrayView<const RtcEvent*> batch);
+
+ static RtcEventLogParseStatus Parse(absl::string_view encoded_bytes,
+ bool batched,
+ std::vector<LoggedStopEvent>& output);
+
+ private:
+ RtcEventEndLog(const RtcEventEndLog& other);
+
+ static constexpr EventParameters event_params_{"EndLog",
+ RtcEventEndLog::kType};
+};
+
+} // namespace webrtc
+#endif // LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_END_LOG_H_
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_field_encoding.cc b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_field_encoding.cc
new file mode 100644
index 0000000000..68188ce856
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_field_encoding.cc
@@ -0,0 +1,299 @@
+/*
+ * Copyright (c) 2021 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_field_encoding.h"
+
+#include <algorithm>
+#include <limits>
+#include <memory>
+#include <utility>
+
+#include "logging/rtc_event_log/encoder/bit_writer.h"
+#include "logging/rtc_event_log/encoder/var_int.h"
+#include "logging/rtc_event_log/events/rtc_event_field_extraction.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+
+using webrtc_event_logging::UnsignedDelta;
+
+namespace {
+
+std::string SerializeLittleEndian(uint64_t value, uint8_t bytes) {
+ RTC_DCHECK_LE(bytes, sizeof(uint64_t));
+ RTC_DCHECK_GE(bytes, 1);
+ if (bytes < sizeof(uint64_t)) {
+ // Note that shifting a 64-bit value by 64 (or more) bits is undefined.
+ RTC_DCHECK_EQ(value >> (8 * bytes), 0);
+ }
+ std::string output(bytes, 0);
+ // Getting a non-const pointer to the representation. See e.g.
+ // https://en.cppreference.com/w/cpp/string/basic_string:
+ // "The elements of a basic_string are stored contiguously,
+ // that is, [...] a pointer to s[0] can be passed to functions
+ // that expect a pointer to the first element of a null-terminated
+ // CharT[] array."
+ uint8_t* p = reinterpret_cast<uint8_t*>(&output[0]);
+#ifdef WEBRTC_ARCH_LITTLE_ENDIAN
+ memcpy(p, &value, bytes);
+#else
+ while (bytes > 0) {
+ *p = static_cast<uint8_t>(value & 0xFF);
+ value >>= 8;
+ ++p;
+ --bytes;
+ }
+#endif // WEBRTC_ARCH_LITTLE_ENDIAN
+ return output;
+}
+
+} // namespace
+
+namespace webrtc {
+
+std::string EncodeOptionalValuePositions(std::vector<bool> positions) {
+ BitWriter writer((positions.size() + 7) / 8);
+ for (bool position : positions) {
+ writer.WriteBits(position ? 1u : 0u, 1);
+ }
+ return writer.GetString();
+}
+
+std::string EncodeSingleValue(uint64_t value, FieldType field_type) {
+ switch (field_type) {
+ case FieldType::kFixed8:
+ return SerializeLittleEndian(value, /*bytes=*/1);
+ case FieldType::kFixed32:
+ return SerializeLittleEndian(value, /*bytes=*/4);
+ case FieldType::kFixed64:
+ return SerializeLittleEndian(value, /*bytes=*/8);
+ case FieldType::kVarInt:
+ return EncodeVarInt(value);
+ case FieldType::kString:
+ RTC_DCHECK_NOTREACHED();
+ return std::string();
+ }
+ RTC_DCHECK_NOTREACHED();
+ return std::string();
+}
+
+absl::optional<FieldType> ConvertFieldType(uint64_t value) {
+ switch (value) {
+ case static_cast<uint64_t>(FieldType::kFixed8):
+ return FieldType::kFixed8;
+ case static_cast<uint64_t>(FieldType::kFixed32):
+ return FieldType::kFixed32;
+ case static_cast<uint64_t>(FieldType::kFixed64):
+ return FieldType::kFixed64;
+ case static_cast<uint64_t>(FieldType::kVarInt):
+ return FieldType::kVarInt;
+ case static_cast<uint64_t>(FieldType::kString):
+ return FieldType::kString;
+ default:
+ return absl::nullopt;
+ }
+}
+
+std::string EncodeDeltasV3(FixedLengthEncodingParametersV3 params,
+ uint64_t base,
+ rtc::ArrayView<const uint64_t> values) {
+ size_t outputbound = (values.size() * params.delta_bit_width() + 7) / 8;
+ BitWriter writer(outputbound);
+
+ uint64_t previous = base;
+ for (uint64_t value : values) {
+ if (params.signed_deltas()) {
+ uint64_t positive_delta =
+ UnsignedDelta(previous, value, params.value_mask());
+ uint64_t negative_delta =
+ UnsignedDelta(value, previous, params.value_mask());
+ uint64_t delta;
+ if (positive_delta <= negative_delta) {
+ delta = positive_delta;
+ } else {
+ // Compute the two's complement representation of a negative
+ // delta, in a field width params_.delta_mask().
+ RTC_DCHECK_GE(params.delta_mask(), negative_delta);
+ RTC_DCHECK_LT(params.delta_mask() - negative_delta,
+ params.delta_mask());
+ delta = params.delta_mask() - negative_delta + 1;
+ RTC_DCHECK_LE(delta, params.delta_mask());
+ }
+ writer.WriteBits(delta, params.delta_bit_width());
+ } else {
+ uint64_t delta = UnsignedDelta(previous, value, params.value_mask());
+ writer.WriteBits(delta, params.delta_bit_width());
+ }
+ previous = value;
+ }
+
+ return writer.GetString();
+}
+
+EventEncoder::EventEncoder(EventParameters params,
+ rtc::ArrayView<const RtcEvent*> batch) {
+ batch_size_ = batch.size();
+ if (!batch.empty()) {
+ // Encode event type.
+ uint32_t batched = batch.size() > 1 ? 1 : 0;
+ event_tag_ = (static_cast<uint32_t>(params.id) << 1) + batched;
+
+ // Event tag and number of encoded bytes will be filled in when the
+ // encoding is finalized in AsString().
+
+ // Encode number of events in batch
+ if (batched) {
+ encoded_fields_.push_back(EncodeVarInt(batch.size()));
+ }
+
+ // Encode timestamp
+ std::vector<uint64_t> timestamps;
+ timestamps.reserve(batch.size());
+ for (const RtcEvent* event : batch) {
+ timestamps.push_back(EncodeAsUnsigned(event->timestamp_ms()));
+ }
+ constexpr FieldParameters timestamp_params{"timestamp_ms",
+ FieldParameters::kTimestampField,
+ FieldType::kVarInt, 64};
+ EncodeField(timestamp_params, timestamps);
+ }
+}
+
+void EventEncoder::EncodeField(const FieldParameters& params,
+ const ValuesWithPositions& values) {
+ return EncodeField(params, values.values, &values.position_mask);
+}
+
+void EventEncoder::EncodeField(const FieldParameters& params,
+ const std::vector<uint64_t>& values,
+ const std::vector<bool>* positions) {
+ if (positions) {
+ RTC_DCHECK_EQ(positions->size(), batch_size_);
+ RTC_DCHECK_LE(values.size(), batch_size_);
+ } else {
+ RTC_DCHECK_EQ(values.size(), batch_size_);
+ }
+
+ if (values.size() == 0) {
+ // If all values for a particular field is empty/nullopt,
+ // then we completely skip the field even if the the batch is non-empty.
+ return;
+ }
+
+ // We know that each event starts with the varint encoded timestamp,
+ // so we omit that field tag (field id + field type). In all other
+ // cases, we write the field tag.
+ if (params.field_id != FieldParameters::kTimestampField) {
+ RTC_DCHECK_LE(params.field_id, std::numeric_limits<uint64_t>::max() >> 3);
+ uint64_t field_tag = params.field_id << 3;
+ field_tag += static_cast<uint64_t>(params.field_type);
+ encoded_fields_.push_back(EncodeVarInt(field_tag));
+ }
+
+ RTC_CHECK_GE(values.size(), 1);
+ if (batch_size_ == 1) {
+ encoded_fields_.push_back(EncodeSingleValue(values[0], params.field_type));
+ return;
+ }
+
+ const bool values_optional = values.size() != batch_size_;
+
+ // Compute delta parameters
+ rtc::ArrayView<const uint64_t> all_values(values);
+ uint64_t base = values[0];
+ rtc::ArrayView<const uint64_t> remaining_values(all_values.subview(1));
+
+ FixedLengthEncodingParametersV3 delta_params =
+ FixedLengthEncodingParametersV3::CalculateParameters(
+ base, remaining_values, params.value_width, values_optional);
+
+ encoded_fields_.push_back(EncodeVarInt(delta_params.DeltaHeaderAsInt()));
+
+ if (values_optional) {
+ RTC_CHECK(positions);
+ encoded_fields_.push_back(EncodeOptionalValuePositions(*positions));
+ }
+ // Base element, encoded as uint8, uint32, uint64 or varint
+ encoded_fields_.push_back(EncodeSingleValue(base, params.field_type));
+
+ // If all (existing) values are equal to the base, then we can skip
+ // writing the all-zero deltas, and instead infer those from the delta
+ // header.
+ if (!delta_params.values_equal()) {
+ encoded_fields_.push_back(
+ EncodeDeltasV3(delta_params, base, remaining_values));
+ }
+}
+
+void EventEncoder::EncodeField(const FieldParameters& params,
+ const std::vector<absl::string_view>& values) {
+ RTC_DCHECK_EQ(values.size(), batch_size_);
+
+ if (values.size() == 0) {
+ // If all values for a particular field is empty/nullopt,
+ // then we completely skip the field even if the the batch is non-empty.
+ return;
+ }
+
+ // Write the field tag.
+ RTC_CHECK_NE(params.field_id, FieldParameters::kTimestampField);
+ RTC_DCHECK_LE(params.field_id, std::numeric_limits<uint64_t>::max() >> 3);
+ RTC_DCHECK_EQ(params.field_type, FieldType::kString);
+ uint64_t field_tag = params.field_id << 3;
+ field_tag += static_cast<uint64_t>(params.field_type);
+ encoded_fields_.push_back(EncodeVarInt(field_tag));
+
+ if (values.size() > 1) {
+ // If multiple values in the batch, write the encoding
+ // parameters. (Values >0 reserved for future use.)
+ uint64_t encoding_params = 0;
+ encoded_fields_.push_back(EncodeVarInt(encoding_params));
+ }
+
+ // Write the strings as (length, data) pairs.
+ for (absl::string_view s : values) {
+ encoded_fields_.push_back(EncodeVarInt(s.size()));
+ encoded_fields_.push_back(std::string(s));
+ }
+}
+
+std::string EventEncoder::AsString() {
+ std::string encoded_event;
+
+ if (batch_size_ == 0) {
+ RTC_DCHECK_EQ(encoded_fields_.size(), 0);
+ return encoded_event;
+ }
+
+ // Compute size of encoded fields.
+ size_t total_fields_size = 0;
+ for (const std::string& s : encoded_fields_) {
+ total_fields_size += s.size();
+ }
+
+ constexpr size_t kExpectedMaxEventTagBytes = 4;
+ constexpr size_t kExpectedMaxSizeEncodingBytes = 4;
+ encoded_event.reserve(kExpectedMaxEventTagBytes +
+ kExpectedMaxSizeEncodingBytes + total_fields_size);
+
+ // Encode event tag (event id and whether batch or single event).
+ encoded_event.append(EncodeVarInt(event_tag_));
+
+ // Encode size of the remaining fields.
+ encoded_event.append(EncodeVarInt(total_fields_size));
+
+ // Append encoded fields.
+ for (const std::string& s : encoded_fields_) {
+ encoded_event.append(s);
+ }
+
+ return encoded_event;
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_field_encoding.h b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_field_encoding.h
new file mode 100644
index 0000000000..33b77b80f5
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_field_encoding.h
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2021 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_FIELD_ENCODING_H_
+#define LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_FIELD_ENCODING_H_
+
+#include <string>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "api/rtc_event_log/rtc_event.h"
+#include "logging/rtc_event_log/encoder/rtc_event_log_encoder_common.h"
+#include "logging/rtc_event_log/events/fixed_length_encoding_parameters_v3.h"
+#include "logging/rtc_event_log/events/rtc_event_field_extraction.h"
+#include "rtc_base/logging.h"
+
+namespace webrtc {
+
+// To maintain backwards compatibility with past (or future) logs,
+// the constants in this enum must not be changed.
+// New field types with numerical IDs 5-7 can be added, but old
+// parsers will fail to parse events containing the new fields.
+enum class FieldType : uint8_t {
+ kFixed8 = 0,
+ kFixed32 = 1,
+ kFixed64 = 2,
+ kVarInt = 3,
+ kString = 4,
+};
+
+// EventParameters map an event name to a numerical ID.
+struct EventParameters {
+ // The name is primarily used for debugging purposes.
+ const char* const name;
+ //
+ const RtcEvent::Type id;
+};
+
+// FieldParameters define the encoding for a field.
+struct FieldParameters {
+ // The name is primarily used for debugging purposes.
+ const char* const name;
+ // Numerical ID for the field. Must be strictly greater than 0,
+ // and unique within each event type.
+ const uint64_t field_id;
+ // Encoding type for the base (i.e. non-delta) field in a batch.
+ const FieldType field_type;
+ // Number of bits after which wrap-around occurs. In most cases,
+ // this should be the number of bits in the field data type, i.e.
+ // 8 for an uint8_t, 32 for a int32_t and so on. However, `value_width`
+ // can be used to achieve a more efficient encoding if it is known
+ // that the field uses a smaller number of bits. For example, a
+ // 15-bit counter could set `value_width` to 15 even if the data is
+ // actually stored in a uint32_t.
+ const uint64_t value_width;
+ // Field ID 0 is reserved for timestamps.
+ static constexpr uint64_t kTimestampField = 0;
+};
+
+// The EventEncoder is used to encode a batch of events.
+class EventEncoder {
+ public:
+ EventEncoder(EventParameters params, rtc::ArrayView<const RtcEvent*> batch);
+
+ void EncodeField(const FieldParameters& params,
+ const std::vector<uint64_t>& values,
+ const std::vector<bool>* positions = nullptr);
+
+ void EncodeField(const FieldParameters& params,
+ const ValuesWithPositions& values);
+
+ void EncodeField(const FieldParameters& params,
+ const std::vector<absl::string_view>& values);
+
+ std::string AsString();
+
+ private:
+ size_t batch_size_;
+ uint32_t event_tag_;
+ std::vector<std::string> encoded_fields_;
+};
+
+std::string EncodeSingleValue(uint64_t value, FieldType field_type);
+std::string EncodeDeltasV3(FixedLengthEncodingParametersV3 params,
+ uint64_t base,
+ rtc::ArrayView<const uint64_t> values);
+
+// Given a batch of RtcEvents and a member pointer, extract that
+// member from each event in the batch. Signed integer members are
+// encoded as unsigned, and the bitsize increased so the result can
+// represented as a std::vector<uint64_t>.
+// This is intended to be used in conjuction with
+// EventEncoder::EncodeField to encode a batch of events as follows:
+// auto values = ExtractRtcEventMember(batch, RtcEventFoo::timestamp_ms);
+// encoder.EncodeField(timestamp_params, values)
+template <typename T,
+ typename E,
+ std::enable_if_t<std::is_integral<T>::value, bool> = true>
+std::vector<uint64_t> ExtractRtcEventMember(
+ rtc::ArrayView<const RtcEvent*> batch,
+ const T E::*member) {
+ std::vector<uint64_t> values;
+ values.reserve(batch.size());
+ for (const RtcEvent* event : batch) {
+ RTC_CHECK_EQ(event->GetType(), E::kType);
+ T value = static_cast<const E*>(event)->*member;
+ values.push_back(EncodeAsUnsigned(value));
+ }
+ return values;
+}
+
+// Extract an optional field from a batch of RtcEvents.
+// The function returns a vector of positions in addition to the vector of
+// values. The vector `positions` has the same length as the batch where
+// `positions[i] == true` iff the batch[i]->member has a value.
+// The values vector only contains the values that exists, so it
+// may be shorter than the batch.
+template <typename T,
+ typename E,
+ std::enable_if_t<std::is_integral<T>::value, bool> = true>
+ValuesWithPositions ExtractRtcEventMember(rtc::ArrayView<const RtcEvent*> batch,
+ const absl::optional<T> E::*member) {
+ ValuesWithPositions result;
+ result.position_mask.reserve(batch.size());
+ result.values.reserve(batch.size());
+ for (const RtcEvent* event : batch) {
+ RTC_CHECK_EQ(event->GetType(), E::kType);
+ absl::optional<T> field = static_cast<const E*>(event)->*member;
+ result.position_mask.push_back(field.has_value());
+ if (field.has_value()) {
+ result.values.push_back(EncodeAsUnsigned(field.value()));
+ }
+ }
+ return result;
+}
+
+// Extract an enum field from a batch of RtcEvents.
+// Requires specializing RtcEventLogEnum<T> for the enum type T.
+template <typename T,
+ typename E,
+ std::enable_if_t<std::is_enum<T>::value, bool> = true>
+std::vector<uint64_t> ExtractRtcEventMember(
+ rtc::ArrayView<const RtcEvent*> batch,
+ const T E::*member) {
+ std::vector<uint64_t> values;
+ values.reserve(batch.size());
+ for (const RtcEvent* event : batch) {
+ RTC_CHECK_EQ(event->GetType(), E::kType);
+ T value = static_cast<const E*>(event)->*member;
+ values.push_back(RtcEventLogEnum<T>::Encode(value));
+ }
+ return values;
+}
+
+// Extract a string field from a batch of RtcEvents.
+template <typename E>
+std::vector<absl::string_view> ExtractRtcEventMember(
+ rtc::ArrayView<const RtcEvent*> batch,
+ const std::string E::*member) {
+ std::vector<absl::string_view> values;
+ values.reserve(batch.size());
+ for (const RtcEvent* event : batch) {
+ RTC_CHECK_EQ(event->GetType(), E::kType);
+ absl::string_view str = static_cast<const E*>(event)->*member;
+ values.push_back(str);
+ }
+ return values;
+}
+
+} // namespace webrtc
+#endif // LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_FIELD_ENCODING_H_
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_field_encoding_parser.cc b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_field_encoding_parser.cc
new file mode 100644
index 0000000000..a9b0c08307
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_field_encoding_parser.cc
@@ -0,0 +1,398 @@
+
+/*
+ * Copyright (c) 2021 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_field_encoding_parser.h"
+
+#include "absl/strings/string_view.h"
+#include "absl/types/optional.h"
+#include "logging/rtc_event_log/encoder/var_int.h"
+#include "logging/rtc_event_log/events/rtc_event_field_encoding.h"
+#include "rtc_base/bitstream_reader.h"
+#include "rtc_base/checks.h"
+
+namespace {
+absl::optional<webrtc::FieldType> ConvertFieldType(uint64_t value) {
+ switch (value) {
+ case static_cast<uint64_t>(webrtc::FieldType::kFixed8):
+ return webrtc::FieldType::kFixed8;
+ case static_cast<uint64_t>(webrtc::FieldType::kFixed32):
+ return webrtc::FieldType::kFixed32;
+ case static_cast<uint64_t>(webrtc::FieldType::kFixed64):
+ return webrtc::FieldType::kFixed64;
+ case static_cast<uint64_t>(webrtc::FieldType::kVarInt):
+ return webrtc::FieldType::kVarInt;
+ case static_cast<uint64_t>(webrtc::FieldType::kString):
+ return webrtc::FieldType::kString;
+ default:
+ return absl::nullopt;
+ }
+}
+} // namespace
+
+namespace webrtc {
+
+uint64_t EventParser::ReadLittleEndian(uint8_t bytes) {
+ RTC_DCHECK_LE(bytes, sizeof(uint64_t));
+ RTC_DCHECK_GE(bytes, 1);
+
+ uint64_t value = 0;
+
+ if (bytes > pending_data_.length()) {
+ SetError();
+ return value;
+ }
+
+ const uint8_t* p = reinterpret_cast<const uint8_t*>(pending_data_.data());
+ unsigned int shift = 0;
+ uint8_t remaining = bytes;
+ while (remaining > 0) {
+ value += (static_cast<uint64_t>(*p) << shift);
+ shift += 8;
+ ++p;
+ --remaining;
+ }
+
+ pending_data_ = pending_data_.substr(bytes);
+ return value;
+}
+
+uint64_t EventParser::ReadVarInt() {
+ uint64_t output = 0;
+ bool success;
+ std::tie(success, pending_data_) = DecodeVarInt(pending_data_, &output);
+ if (!success) {
+ SetError();
+ }
+ return output;
+}
+
+uint64_t EventParser::ReadOptionalValuePositions() {
+ RTC_DCHECK(positions_.empty());
+ size_t bits_to_read = NumEventsInBatch();
+ positions_.reserve(bits_to_read);
+ if (pending_data_.size() * 8 < bits_to_read) {
+ SetError();
+ return 0;
+ }
+
+ BitstreamReader reader(pending_data_);
+ for (size_t i = 0; i < bits_to_read; i++) {
+ positions_.push_back(reader.ReadBit());
+ }
+ if (!reader.Ok()) {
+ SetError();
+ return 0;
+ }
+
+ size_t num_existing_values =
+ std::count(positions_.begin(), positions_.end(), 1);
+ pending_data_ = pending_data_.substr((bits_to_read + 7) / 8);
+ return num_existing_values;
+}
+
+uint64_t EventParser::ReadSingleValue(FieldType field_type) {
+ switch (field_type) {
+ case FieldType::kFixed8:
+ return ReadLittleEndian(/*bytes=*/1);
+ case FieldType::kFixed32:
+ return ReadLittleEndian(/*bytes=*/4);
+ case FieldType::kFixed64:
+ return ReadLittleEndian(/*bytes=*/8);
+ case FieldType::kVarInt:
+ return ReadVarInt();
+ case FieldType::kString:
+ RTC_DCHECK_NOTREACHED();
+ SetError();
+ return 0;
+ }
+ RTC_DCHECK_NOTREACHED();
+ SetError();
+ return 0;
+}
+
+void EventParser::ReadDeltasAndPopulateValues(
+ FixedLengthEncodingParametersV3 params,
+ uint64_t num_deltas,
+ uint64_t base) {
+ RTC_DCHECK(values_.empty());
+ values_.reserve(num_deltas + 1);
+ values_.push_back(base);
+
+ if (pending_data_.size() * 8 < num_deltas * params.delta_bit_width()) {
+ SetError();
+ return;
+ }
+
+ BitstreamReader reader(pending_data_);
+ const uint64_t top_bit = static_cast<uint64_t>(1)
+ << (params.delta_bit_width() - 1);
+
+ uint64_t value = base;
+ for (uint64_t i = 0; i < num_deltas; ++i) {
+ uint64_t delta = reader.ReadBits(params.delta_bit_width());
+ RTC_DCHECK_LE(value, webrtc_event_logging::MaxUnsignedValueOfBitWidth(
+ params.value_bit_width()));
+ RTC_DCHECK_LE(delta, webrtc_event_logging::MaxUnsignedValueOfBitWidth(
+ params.delta_bit_width()));
+ bool negative_delta = params.signed_deltas() && ((delta & top_bit) != 0);
+ if (negative_delta) {
+ uint64_t delta_abs = (~delta & params.delta_mask()) + 1;
+ value = (value - delta_abs) & params.value_mask();
+ } else {
+ value = (value + delta) & params.value_mask();
+ }
+ values_.push_back(value);
+ }
+
+ if (!reader.Ok()) {
+ SetError();
+ return;
+ }
+
+ pending_data_ =
+ pending_data_.substr((num_deltas * params.delta_bit_width() + 7) / 8);
+}
+
+RtcEventLogParseStatus EventParser::Initialize(absl::string_view s,
+ bool batched) {
+ pending_data_ = s;
+ num_events_ = 1;
+
+ if (batched) {
+ num_events_ = ReadVarInt();
+ if (!Ok()) {
+ return RtcEventLogParseStatus::Error(
+ "Failed to read number of events in batch.", __FILE__, __LINE__);
+ }
+ }
+ return RtcEventLogParseStatus::Success();
+}
+
+RtcEventLogParseStatus EventParser::ParseNumericFieldInternal(
+ uint64_t value_bit_width,
+ FieldType field_type) {
+ RTC_DCHECK(values_.empty());
+ RTC_DCHECK(positions_.empty());
+
+ if (num_events_ == 1) {
+ // Just a single value in the batch.
+ uint64_t base = ReadSingleValue(field_type);
+ if (!Ok()) {
+ return RtcEventLogParseStatus::Error("Failed to read value", __FILE__,
+ __LINE__);
+ }
+ positions_.push_back(true);
+ values_.push_back(base);
+ } else {
+ // Delta compressed batch.
+ // Read delta header.
+ uint64_t header_value = ReadVarInt();
+ if (!Ok())
+ return RtcEventLogParseStatus::Error("Failed to read delta header",
+ __FILE__, __LINE__);
+ // NB: value_bit_width may be incorrect for the field, if this isn't the
+ // field we are looking for.
+ absl::optional<FixedLengthEncodingParametersV3> delta_header =
+ FixedLengthEncodingParametersV3::ParseDeltaHeader(header_value,
+ value_bit_width);
+ if (!delta_header.has_value()) {
+ return RtcEventLogParseStatus::Error("Failed to parse delta header",
+ __FILE__, __LINE__);
+ }
+
+ uint64_t num_existing_deltas = NumEventsInBatch() - 1;
+ if (delta_header->values_optional()) {
+ size_t num_nonempty_values = ReadOptionalValuePositions();
+ if (!Ok()) {
+ return RtcEventLogParseStatus::Error(
+ "Failed to read positions of optional values", __FILE__, __LINE__);
+ }
+ if (num_nonempty_values < 1 || NumEventsInBatch() < num_nonempty_values) {
+ return RtcEventLogParseStatus::Error(
+ "Expected at least one non_empty value", __FILE__, __LINE__);
+ }
+ num_existing_deltas = num_nonempty_values - 1;
+ } else {
+ // All elements in the batch have values.
+ positions_.assign(NumEventsInBatch(), 1u);
+ }
+
+ // Read base.
+ uint64_t base = ReadSingleValue(field_type);
+ if (!Ok()) {
+ return RtcEventLogParseStatus::Error("Failed to read value", __FILE__,
+ __LINE__);
+ }
+
+ if (delta_header->values_equal()) {
+ // Duplicate the base value num_existing_deltas times.
+ values_.assign(num_existing_deltas + 1, base);
+ } else {
+ // Read deltas; ceil(num_existing_deltas*delta_width/8) bits
+ ReadDeltasAndPopulateValues(delta_header.value(), num_existing_deltas,
+ base);
+ if (!Ok()) {
+ return RtcEventLogParseStatus::Error("Failed to decode deltas",
+ __FILE__, __LINE__);
+ }
+ }
+ }
+ return RtcEventLogParseStatus::Success();
+}
+
+RtcEventLogParseStatus EventParser::ParseStringFieldInternal() {
+ RTC_DCHECK(strings_.empty());
+ if (num_events_ > 1) {
+ // String encoding params reserved for future use.
+ uint64_t encoding_params = ReadVarInt();
+ if (!Ok()) {
+ return RtcEventLogParseStatus::Error("Failed to read string encoding",
+ __FILE__, __LINE__);
+ }
+ if (encoding_params != 0) {
+ return RtcEventLogParseStatus::Error(
+ "Unrecognized string encoding parameters", __FILE__, __LINE__);
+ }
+ }
+ strings_.reserve(num_events_);
+ for (uint64_t i = 0; i < num_events_; ++i) {
+ // Just a single value in the batch.
+ uint64_t size = ReadVarInt();
+ if (!Ok()) {
+ return RtcEventLogParseStatus::Error("Failed to read string size",
+ __FILE__, __LINE__);
+ }
+ if (size > pending_data_.size()) {
+ return RtcEventLogParseStatus::Error("String size exceeds remaining data",
+ __FILE__, __LINE__);
+ }
+ strings_.push_back(pending_data_.substr(0, size));
+ pending_data_ = pending_data_.substr(size);
+ }
+ return RtcEventLogParseStatus::Success();
+}
+
+RtcEventLogParseStatus EventParser::ParseField(const FieldParameters& params) {
+ // Verify that the event parses fields in increasing order.
+ if (params.field_id == FieldParameters::kTimestampField) {
+ RTC_DCHECK_EQ(last_field_id_, FieldParameters::kTimestampField);
+ } else {
+ RTC_DCHECK_GT(params.field_id, last_field_id_);
+ }
+ last_field_id_ = params.field_id;
+
+ // Initialization for positional fields that don't encode field ID and type.
+ uint64_t field_id = params.field_id;
+ FieldType field_type = params.field_type;
+
+ // Fields are encoded in increasing field_id order.
+ // Skip unknown fields with field_id < params.field_id until we either
+ // find params.field_id or a field with higher id, in which case we know that
+ // params.field_id doesn't exist.
+ while (!pending_data_.empty()) {
+ absl::string_view field_start = pending_data_;
+ ClearTemporaries();
+
+ // Read tag for non-positional fields.
+ if (params.field_id != FieldParameters::kTimestampField) {
+ uint64_t field_tag = ReadVarInt();
+ if (!Ok())
+ return RtcEventLogParseStatus::Error("Failed to read field tag",
+ __FILE__, __LINE__);
+ // Split tag into field ID and field type.
+ field_id = field_tag >> 3;
+ absl::optional<FieldType> conversion = ConvertFieldType(field_tag & 7u);
+ if (!conversion.has_value())
+ return RtcEventLogParseStatus::Error("Failed to parse field type",
+ __FILE__, __LINE__);
+ field_type = conversion.value();
+ }
+
+ if (field_id > params.field_id) {
+ // We've passed all fields with ids less than or equal to what we are
+ // looking for. Reset pending_data_ to first field with id higher than
+ // params.field_id, since we didn't find the field we were looking for.
+ pending_data_ = field_start;
+ return RtcEventLogParseStatus::Success();
+ }
+
+ if (field_type == FieldType::kString) {
+ auto status = ParseStringFieldInternal();
+ if (!status.ok()) {
+ return status;
+ }
+ } else {
+ auto status = ParseNumericFieldInternal(params.value_width, field_type);
+ if (!status.ok()) {
+ return status;
+ }
+ }
+
+ if (field_id == params.field_id) {
+ // The field we're looking for has been found and values populated.
+ return RtcEventLogParseStatus::Success();
+ }
+ }
+
+ // Field not found because the event ended.
+ ClearTemporaries();
+ return RtcEventLogParseStatus::Success();
+}
+
+RtcEventLogParseStatusOr<rtc::ArrayView<absl::string_view>>
+EventParser::ParseStringField(const FieldParameters& params,
+ bool required_field) {
+ using StatusOr = RtcEventLogParseStatusOr<rtc::ArrayView<absl::string_view>>;
+ RTC_DCHECK_EQ(params.field_type, FieldType::kString);
+ auto status = ParseField(params);
+ if (!status.ok())
+ return StatusOr(status);
+ rtc::ArrayView<absl::string_view> strings = GetStrings();
+ if (required_field && strings.size() != NumEventsInBatch()) {
+ return StatusOr::Error("Required string field not found", __FILE__,
+ __LINE__);
+ }
+ return StatusOr(strings);
+}
+
+RtcEventLogParseStatusOr<rtc::ArrayView<uint64_t>>
+EventParser::ParseNumericField(const FieldParameters& params,
+ bool required_field) {
+ using StatusOr = RtcEventLogParseStatusOr<rtc::ArrayView<uint64_t>>;
+ RTC_DCHECK_NE(params.field_type, FieldType::kString);
+ auto status = ParseField(params);
+ if (!status.ok())
+ return StatusOr(status);
+ rtc::ArrayView<uint64_t> values = GetValues();
+ if (required_field && values.size() != NumEventsInBatch()) {
+ return StatusOr::Error("Required numerical field not found", __FILE__,
+ __LINE__);
+ }
+ return StatusOr(values);
+}
+
+RtcEventLogParseStatusOr<EventParser::ValueAndPostionView>
+EventParser::ParseOptionalNumericField(const FieldParameters& params,
+ bool required_field) {
+ using StatusOr = RtcEventLogParseStatusOr<ValueAndPostionView>;
+ RTC_DCHECK_NE(params.field_type, FieldType::kString);
+ auto status = ParseField(params);
+ if (!status.ok())
+ return StatusOr(status);
+ ValueAndPostionView view{GetValues(), GetPositions()};
+ if (required_field && view.positions.size() != NumEventsInBatch()) {
+ return StatusOr::Error("Required numerical field not found", __FILE__,
+ __LINE__);
+ }
+ return StatusOr(view);
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_field_encoding_parser.h b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_field_encoding_parser.h
new file mode 100644
index 0000000000..fc87faf611
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_field_encoding_parser.h
@@ -0,0 +1,291 @@
+/*
+ * Copyright (c) 2021 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_FIELD_ENCODING_PARSER_H_
+#define LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_FIELD_ENCODING_PARSER_H_
+
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "logging/rtc_event_log/events/rtc_event_field_encoding.h"
+
+// TODO(terelius): Compared to a generic 'Status' class, this
+// class allows us additional information about the context
+// in which the error occurred. This is currently limited to
+// the source location (file and line), but we plan on adding
+// information about the event and field name being parsed.
+// If/when we start using absl::Status in WebRTC, consider
+// whether payloads would be an appropriate alternative.
+class RtcEventLogParseStatus {
+ template <typename T>
+ friend class RtcEventLogParseStatusOr;
+
+ public:
+ static RtcEventLogParseStatus Success() { return RtcEventLogParseStatus(); }
+ static RtcEventLogParseStatus Error(absl::string_view error,
+ absl::string_view file,
+ int line) {
+ return RtcEventLogParseStatus(error, file, line);
+ }
+
+ bool ok() const { return error_.empty(); }
+ ABSL_DEPRECATED("Use ok() instead") explicit operator bool() const {
+ return ok();
+ }
+
+ std::string message() const { return error_; }
+
+ private:
+ RtcEventLogParseStatus() : error_() {}
+ RtcEventLogParseStatus(absl::string_view error,
+ absl::string_view file,
+ int line)
+ : error_(std::string(error) + " (" + std::string(file) + ": " +
+ std::to_string(line) + ")") {}
+
+ std::string error_;
+};
+
+template <typename T>
+class RtcEventLogParseStatusOr {
+ public:
+ RtcEventLogParseStatusOr(RtcEventLogParseStatus status) // NOLINT
+ : status_(status), value_() {}
+ RtcEventLogParseStatusOr(const T& value) // NOLINT
+ : status_(), value_(value) {}
+
+ bool ok() const { return status_.ok(); }
+
+ std::string message() const { return status_.message(); }
+
+ RtcEventLogParseStatus status() const { return status_; }
+
+ const T& value() const {
+ RTC_DCHECK(ok());
+ return value_;
+ }
+
+ T& value() {
+ RTC_DCHECK(ok());
+ return value_;
+ }
+
+ static RtcEventLogParseStatusOr Error(absl::string_view error,
+ absl::string_view file,
+ int line) {
+ return RtcEventLogParseStatusOr(error, file, line);
+ }
+
+ private:
+ RtcEventLogParseStatusOr() : status_() {}
+ RtcEventLogParseStatusOr(absl::string_view error,
+ absl::string_view file,
+ int line)
+ : status_(error, file, line), value_() {}
+
+ RtcEventLogParseStatus status_;
+ T value_;
+};
+
+namespace webrtc {
+
+class EventParser {
+ public:
+ struct ValueAndPostionView {
+ rtc::ArrayView<uint64_t> values;
+ rtc::ArrayView<uint8_t> positions;
+ };
+
+ EventParser() = default;
+
+ // N.B: This method stores a abls::string_view into the string to be
+ // parsed. The caller is responsible for ensuring that the actual string
+ // remains unmodified and outlives the EventParser.
+ RtcEventLogParseStatus Initialize(absl::string_view s, bool batched);
+
+ // Attempts to parse the field specified by `params`, skipping past
+ // other fields that may occur before it. If 'required_field == true',
+ // then failing to find the field is an error, otherwise the functions
+ // return success, but with an empty view of values.
+ RtcEventLogParseStatusOr<rtc::ArrayView<absl::string_view>> ParseStringField(
+ const FieldParameters& params,
+ bool required_field = true);
+ RtcEventLogParseStatusOr<rtc::ArrayView<uint64_t>> ParseNumericField(
+ const FieldParameters& params,
+ bool required_field = true);
+ RtcEventLogParseStatusOr<ValueAndPostionView> ParseOptionalNumericField(
+ const FieldParameters& params,
+ bool required_field = true);
+
+ // Number of events in a batch.
+ uint64_t NumEventsInBatch() const { return num_events_; }
+
+ // Bytes remaining in `pending_data_`. Assuming there are no unknown
+ // fields, BytesRemaining() should return 0 when all known fields
+ // in the event have been parsed.
+ size_t RemainingBytes() const { return pending_data_.size(); }
+
+ private:
+ uint64_t ReadLittleEndian(uint8_t bytes);
+ uint64_t ReadVarInt();
+ uint64_t ReadSingleValue(FieldType field_type);
+ uint64_t ReadOptionalValuePositions();
+ void ReadDeltasAndPopulateValues(FixedLengthEncodingParametersV3 params,
+ uint64_t num_deltas,
+ uint64_t base);
+ RtcEventLogParseStatus ParseNumericFieldInternal(uint64_t value_bit_width,
+ FieldType field_type);
+ RtcEventLogParseStatus ParseStringFieldInternal();
+
+ // Attempts to parse the field specified by `params`, skipping past
+ // other fields that may occur before it. Returns
+ // RtcEventLogParseStatus::Success() and populates `values_` (and
+ // `positions_`) if the field is found. Returns
+ // RtcEventLogParseStatus::Success() and clears `values_` (and `positions_`)
+ // if the field doesn't exist. Returns a RtcEventLogParseStatus::Error() if
+ // the log is incomplete, malformed or otherwise can't be parsed.
+ RtcEventLogParseStatus ParseField(const FieldParameters& params);
+
+ void SetError() { error_ = true; }
+ bool Ok() const { return !error_; }
+
+ rtc::ArrayView<uint64_t> GetValues() { return values_; }
+ rtc::ArrayView<uint8_t> GetPositions() { return positions_; }
+ rtc::ArrayView<absl::string_view> GetStrings() { return strings_; }
+
+ void ClearTemporaries() {
+ positions_.clear();
+ values_.clear();
+ strings_.clear();
+ }
+
+ // Tracks whether an error has occurred in one of the helper
+ // functions above.
+ bool error_ = false;
+
+ // Temporary storage for result.
+ std::vector<uint8_t> positions_;
+ std::vector<uint64_t> values_;
+ std::vector<absl::string_view> strings_;
+
+ // String to be consumed.
+ absl::string_view pending_data_;
+ uint64_t num_events_ = 1;
+ uint64_t last_field_id_ = FieldParameters::kTimestampField;
+};
+
+// Inverse of the ExtractRtcEventMember function used when parsing
+// a log. Uses a vector of values to populate a specific field in a
+// vector of structs.
+template <typename T,
+ typename E,
+ std::enable_if_t<std::is_integral<T>::value, bool> = true>
+ABSL_MUST_USE_RESULT RtcEventLogParseStatus
+PopulateRtcEventMember(const rtc::ArrayView<uint64_t> values,
+ T E::*member,
+ rtc::ArrayView<E> output) {
+ size_t batch_size = values.size();
+ RTC_CHECK_EQ(output.size(), batch_size);
+ for (size_t i = 0; i < batch_size; ++i) {
+ output[i].*member = DecodeFromUnsignedToType<T>(values[i]);
+ }
+ return RtcEventLogParseStatus::Success();
+}
+
+// Same as above, but for optional fields.
+template <typename T,
+ typename E,
+ std::enable_if_t<std::is_integral<T>::value, bool> = true>
+ABSL_MUST_USE_RESULT RtcEventLogParseStatus
+PopulateRtcEventMember(const rtc::ArrayView<uint8_t> positions,
+ const rtc::ArrayView<uint64_t> values,
+ absl::optional<T> E::*member,
+ rtc::ArrayView<E> output) {
+ size_t batch_size = positions.size();
+ RTC_CHECK_EQ(output.size(), batch_size);
+ RTC_CHECK_LE(values.size(), batch_size);
+ auto value_it = values.begin();
+ for (size_t i = 0; i < batch_size; ++i) {
+ if (positions[i]) {
+ RTC_CHECK(value_it != values.end());
+ output[i].*member = DecodeFromUnsignedToType<T>(value_it);
+ ++value_it;
+ } else {
+ output[i].*member = absl::nullopt;
+ }
+ }
+ RTC_CHECK(value_it == values.end());
+ return RtcEventLogParseStatus::Success();
+}
+
+// Same as above, but for enum fields.
+template <typename T,
+ typename E,
+ std::enable_if_t<std::is_enum<T>::value, bool> = true>
+ABSL_MUST_USE_RESULT RtcEventLogParseStatus
+PopulateRtcEventMember(const rtc::ArrayView<uint64_t> values,
+ T E::*member,
+ rtc::ArrayView<E> output) {
+ size_t batch_size = values.size();
+ RTC_CHECK_EQ(output.size(), batch_size);
+ for (size_t i = 0; i < batch_size; ++i) {
+ auto result = RtcEventLogEnum<T>::Decode(values[i]);
+ if (!result.ok()) {
+ return result.status();
+ }
+ output[i].*member = result.value();
+ }
+ return RtcEventLogParseStatus::Success();
+}
+
+// Same as above, but for string fields.
+template <typename E>
+ABSL_MUST_USE_RESULT RtcEventLogParseStatus
+PopulateRtcEventMember(const rtc::ArrayView<absl::string_view> values,
+ std::string E::*member,
+ rtc::ArrayView<E> output) {
+ size_t batch_size = values.size();
+ RTC_CHECK_EQ(output.size(), batch_size);
+ for (size_t i = 0; i < batch_size; ++i) {
+ output[i].*member = values[i];
+ }
+ return RtcEventLogParseStatus::Success();
+}
+
+// Same as above, but for Timestamp fields.
+// N.B. Assumes that the encoded value uses millisecond precision.
+template <typename E>
+ABSL_MUST_USE_RESULT RtcEventLogParseStatus
+PopulateRtcEventTimestamp(const rtc::ArrayView<uint64_t>& values,
+ Timestamp E::*timestamp,
+ rtc::ArrayView<E> output) {
+ size_t batch_size = values.size();
+ RTC_CHECK_EQ(batch_size, output.size());
+ for (size_t i = 0; i < batch_size; ++i) {
+ output[i].*timestamp =
+ Timestamp::Millis(DecodeFromUnsignedToType<int64_t>(values[i]));
+ }
+ return RtcEventLogParseStatus::Success();
+}
+
+template <typename E>
+rtc::ArrayView<E> ExtendLoggedBatch(std::vector<E>& output,
+ size_t new_elements) {
+ size_t old_size = output.size();
+ output.insert(output.end(), old_size + new_elements, E());
+ rtc::ArrayView<E> output_batch = output;
+ output_batch.subview(old_size);
+ RTC_DCHECK_EQ(output_batch.size(), new_elements);
+ return output_batch;
+}
+
+} // namespace webrtc
+#endif // LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_FIELD_ENCODING_PARSER_H_
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_field_encoding_unittest.cc b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_field_encoding_unittest.cc
new file mode 100644
index 0000000000..18beda1417
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_field_encoding_unittest.cc
@@ -0,0 +1,886 @@
+/* Copyright (c) 2021 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_field_encoding.h"
+
+#include <limits>
+#include <memory>
+#include <string>
+
+#include "absl/strings/string_view.h"
+#include "api/rtc_event_log/rtc_event.h"
+#include "logging/rtc_event_log/encoder/var_int.h"
+#include "logging/rtc_event_log/events/rtc_event_field_encoding_parser.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+
+namespace {
+constexpr int32_t kInt32Max = std::numeric_limits<int32_t>::max();
+constexpr int32_t kInt32Min = std::numeric_limits<int32_t>::min();
+constexpr uint32_t kUint32Max = std::numeric_limits<uint32_t>::max();
+constexpr int64_t kInt64Max = std::numeric_limits<int64_t>::max();
+constexpr int64_t kInt64Min = std::numeric_limits<int64_t>::min();
+constexpr uint64_t kUint64Max = std::numeric_limits<uint64_t>::max();
+
+template <typename T, std::enable_if_t<std::is_integral<T>::value, bool> = true>
+size_t ExpectedVarIntSize(T value) {
+ size_t bytes = 0;
+ uint64_t x = EncodeAsUnsigned(value);
+ do {
+ ++bytes;
+ x = x >> 7;
+ } while (x > 0);
+ return bytes;
+}
+
+template <typename T, std::enable_if_t<std::is_integral<T>::value, bool> = true>
+size_t ExpectedBaseValueSize(const FieldParameters& params, T value) {
+ switch (params.field_type) {
+ case FieldType::kFixed8:
+ return 1;
+ case FieldType::kFixed32:
+ return 4;
+ case FieldType::kFixed64:
+ return 8;
+ case FieldType::kVarInt:
+ return ExpectedVarIntSize(value);
+ default:
+ break;
+ }
+ RTC_DCHECK_NOTREACHED();
+ return 0;
+}
+
+template <typename T, std::enable_if_t<std::is_integral<T>::value, bool> = true>
+size_t ExpectedEncodingSize(const FieldParameters& params,
+ const std::vector<T>& v,
+ size_t expected_bits_per_delta) {
+ if (v.size() == 0)
+ return 0;
+
+ uint64_t numeric_field_type = static_cast<uint64_t>(params.field_type);
+ RTC_DCHECK_LT(numeric_field_type, 1u << 3);
+ size_t tag_size =
+ ExpectedVarIntSize((params.field_id << 3) + numeric_field_type);
+ T base = v[0];
+ size_t base_size = ExpectedBaseValueSize(params, base);
+ if (v.size() == 1)
+ return tag_size + base_size;
+
+ size_t delta_header_size = 1;
+ // Check if there is an element *not* equal to base.
+ if (std::all_of(v.begin(), v.end(), [base](T x) { return x == base; })) {
+ return tag_size + base_size + delta_header_size;
+ }
+
+ size_t delta_size = ((v.size() - 1) * expected_bits_per_delta + 7) / 8;
+ return tag_size + base_size + delta_header_size + delta_size;
+}
+
+template <typename T, std::enable_if_t<std::is_integral<T>::value, bool> = true>
+size_t ExpectedEncodingSize(const FieldParameters& params,
+ const std::vector<absl::optional<T>>& v,
+ size_t expected_bits_per_delta) {
+ size_t num_existing_values =
+ v.size() - std::count(v.begin(), v.end(), absl::nullopt);
+ auto first_existing_value = std::find_if(
+ v.begin(), v.end(), [](absl::optional<T> x) { return x.has_value(); });
+ if (num_existing_values == 0)
+ return 0;
+
+ uint64_t numeric_field_type = static_cast<uint64_t>(params.field_type);
+ RTC_DCHECK_LT(numeric_field_type, 1u << 3);
+ size_t tag_size =
+ ExpectedVarIntSize((params.field_id << 3) + numeric_field_type);
+ T base = first_existing_value->value();
+ size_t base_size = ExpectedBaseValueSize(params, base);
+ if (num_existing_values == 1 && v.size() == 1)
+ return tag_size + base_size;
+
+ size_t delta_header_size = (num_existing_values == v.size() ? 1 : 2);
+ size_t positions_size =
+ (num_existing_values == v.size() ? 0 : (v.size() + 7) / 8);
+ // Check if there is an element *not* equal to base.
+ if (std::all_of(v.begin(), v.end(),
+ [base](absl::optional<T> x) { return x == base; })) {
+ return tag_size + base_size + delta_header_size + positions_size;
+ }
+
+ size_t delta_size =
+ ((num_existing_values - 1) * expected_bits_per_delta + 7) / 8;
+ return tag_size + base_size + delta_header_size + positions_size + delta_size;
+}
+
+size_t ExpectedStringEncodingSize(const FieldParameters& params,
+ const std::vector<std::string>& values) {
+ EXPECT_EQ(params.field_type, FieldType::kString);
+ uint64_t numeric_field_type = static_cast<uint64_t>(params.field_type);
+ RTC_DCHECK_LT(numeric_field_type, 1u << 3);
+ size_t tag_size =
+ ExpectedVarIntSize((params.field_id << 3) + numeric_field_type);
+
+ size_t expected_size = tag_size;
+ if (values.size() > 1) {
+ // VarInt encoding header reserved for future use. Currently always 0.
+ expected_size += 1;
+ }
+ for (const auto& s : values) {
+ expected_size += ExpectedVarIntSize(s.size());
+ expected_size += s.size();
+ }
+ return expected_size;
+}
+
+} // namespace
+
+class RtcTestEvent final : public RtcEvent {
+ public:
+ RtcTestEvent(bool b,
+ int32_t signed32,
+ uint32_t unsigned32,
+ int64_t signed64,
+ uint64_t unsigned64)
+ : b_(b),
+ signed32_(signed32),
+ unsigned32_(unsigned32),
+ signed64_(signed64),
+ unsigned64_(unsigned64) {}
+ RtcTestEvent(bool b,
+ int32_t signed32,
+ uint32_t unsigned32,
+ int64_t signed64,
+ uint64_t unsigned64,
+ absl::optional<int32_t> optional_signed32,
+ absl::optional<int64_t> optional_signed64,
+ uint32_t wrapping21,
+ absl::string_view string)
+ : b_(b),
+ signed32_(signed32),
+ unsigned32_(unsigned32),
+ signed64_(signed64),
+ unsigned64_(unsigned64),
+ optional_signed32_(optional_signed32),
+ optional_signed64_(optional_signed64),
+ wrapping21_(wrapping21),
+ string_(string) {}
+ ~RtcTestEvent() override = default;
+
+ Type GetType() const override { return static_cast<Type>(4711); }
+ bool IsConfigEvent() const override { return false; }
+
+ static constexpr EventParameters event_params{
+ "TestEvent", static_cast<RtcEvent::Type>(4711)};
+ static constexpr FieldParameters timestamp_params{
+ "timestamp_ms", FieldParameters::kTimestampField, FieldType::kVarInt, 64};
+ static constexpr FieldParameters bool_params{"b", 2, FieldType::kFixed8, 1};
+ static constexpr FieldParameters signed32_params{"signed32", 3,
+ FieldType::kVarInt, 32};
+ static constexpr FieldParameters unsigned32_params{"unsigned32", 4,
+ FieldType::kFixed32, 32};
+ static constexpr FieldParameters signed64_params{"signed64", 5,
+ FieldType::kFixed64, 64};
+ static constexpr FieldParameters unsigned64_params{"unsigned64", 6,
+ FieldType::kVarInt, 64};
+ static constexpr FieldParameters optional32_params{"optional_signed32", 7,
+ FieldType::kFixed32, 32};
+ static constexpr FieldParameters optional64_params{"optional_signed64", 8,
+ FieldType::kVarInt, 64};
+ static constexpr FieldParameters wrapping21_params{"wrapping21", 9,
+ FieldType::kFixed32, 21};
+ static constexpr FieldParameters string_params{
+ "string", 10, FieldType::kString, /*value_width = */ 0};
+
+ static constexpr Type kType = static_cast<RtcEvent::Type>(4711);
+
+ const bool b_;
+ const int32_t signed32_;
+ const uint32_t unsigned32_;
+ const int64_t signed64_;
+ const uint64_t unsigned64_;
+ const absl::optional<int32_t> optional_signed32_ = absl::nullopt;
+ const absl::optional<int64_t> optional_signed64_ = absl::nullopt;
+ const uint32_t wrapping21_ = 0;
+ const std::string string_;
+};
+
+constexpr EventParameters RtcTestEvent::event_params;
+constexpr FieldParameters RtcTestEvent::timestamp_params;
+constexpr FieldParameters RtcTestEvent::bool_params;
+constexpr FieldParameters RtcTestEvent::signed32_params;
+constexpr FieldParameters RtcTestEvent::unsigned32_params;
+constexpr FieldParameters RtcTestEvent::signed64_params;
+constexpr FieldParameters RtcTestEvent::unsigned64_params;
+
+constexpr FieldParameters RtcTestEvent::optional32_params;
+constexpr FieldParameters RtcTestEvent::optional64_params;
+constexpr FieldParameters RtcTestEvent::wrapping21_params;
+constexpr FieldParameters RtcTestEvent::string_params;
+
+constexpr RtcEvent::Type RtcTestEvent::kType;
+
+class RtcEventFieldTest : public ::testing::Test {
+ protected:
+ void SetUp() override {}
+
+ void CreateFullEvents(
+ const std::vector<bool>& bool_values,
+ const std::vector<int32_t>& signed32_values,
+ const std::vector<uint32_t>& unsigned32_values,
+ const std::vector<int64_t>& signed64_values,
+ const std::vector<uint64_t>& unsigned64_values,
+ const std::vector<absl::optional<int32_t>>& optional32_values,
+ const std::vector<absl::optional<int64_t>>& optional64_values,
+ const std::vector<uint32_t>& wrapping21_values,
+ const std::vector<std::string>& string_values) {
+ size_t size = bool_values.size();
+ RTC_CHECK_EQ(signed32_values.size(), size);
+ RTC_CHECK_EQ(unsigned32_values.size(), size);
+ RTC_CHECK_EQ(signed64_values.size(), size);
+ RTC_CHECK_EQ(unsigned64_values.size(), size);
+ RTC_CHECK_EQ(optional32_values.size(), size);
+ RTC_CHECK_EQ(optional64_values.size(), size);
+ RTC_CHECK_EQ(wrapping21_values.size(), size);
+ RTC_CHECK_EQ(string_values.size(), size);
+
+ for (size_t i = 0; i < size; i++) {
+ batch_.push_back(new RtcTestEvent(
+ bool_values[i], signed32_values[i], unsigned32_values[i],
+ signed64_values[i], unsigned64_values[i], optional32_values[i],
+ optional64_values[i], wrapping21_values[i], string_values[i]));
+ }
+ }
+
+ void PrintBytes(absl::string_view s) {
+ for (auto c : s) {
+ fprintf(stderr, "%d ", static_cast<uint8_t>(c));
+ }
+ fprintf(stderr, "\n");
+ }
+
+ void ParseEventHeader(absl::string_view encoded_event) {
+ uint64_t event_tag;
+ bool success;
+ std::tie(success, encoded_event) = DecodeVarInt(encoded_event, &event_tag);
+ ASSERT_TRUE(success);
+ uint64_t event_id = event_tag >> 1;
+ ASSERT_EQ(event_id, static_cast<uint64_t>(RtcTestEvent::event_params.id));
+ bool batched = event_tag & 1u;
+ ASSERT_EQ(batched, batch_.size() > 1u);
+
+ uint64_t size;
+ std::tie(success, encoded_event) = DecodeVarInt(encoded_event, &size);
+ ASSERT_EQ(encoded_event.size(), size);
+
+ ASSERT_TRUE(parser_.Initialize(encoded_event, batched).ok());
+ }
+
+ void ParseAndVerifyTimestamps() {
+ auto result = parser_.ParseNumericField(RtcTestEvent::timestamp_params);
+ ASSERT_TRUE(result.ok()) << result.message().c_str();
+ ASSERT_EQ(result.value().size(), batch_.size());
+ for (size_t i = 0; i < batch_.size(); i++) {
+ EXPECT_EQ(result.value()[i],
+ static_cast<uint64_t>(batch_[i]->timestamp_ms()));
+ }
+ }
+
+ void ParseAndVerifyStringField(
+ const FieldParameters& params,
+ const std::vector<std::string>& expected_values,
+ size_t expected_skipped_bytes = 0) {
+ size_t expected_size = ExpectedStringEncodingSize(params, expected_values) +
+ expected_skipped_bytes;
+ size_t size_before = parser_.RemainingBytes();
+ auto result = parser_.ParseStringField(params);
+ ASSERT_TRUE(result.ok()) << result.message().c_str();
+ ASSERT_EQ(result.value().size(), expected_values.size());
+ for (size_t i = 0; i < expected_values.size(); i++) {
+ EXPECT_EQ(result.value()[i], expected_values[i]);
+ }
+ size_t size_after = parser_.RemainingBytes();
+ EXPECT_EQ(size_before - size_after, expected_size)
+ << " for field " << params.name;
+ }
+
+ template <typename T>
+ void ParseAndVerifyField(const FieldParameters& params,
+ const std::vector<T>& expected_values,
+ size_t expected_bits_per_delta,
+ size_t expected_skipped_bytes = 0) {
+ size_t expected_size =
+ ExpectedEncodingSize(params, expected_values, expected_bits_per_delta) +
+ expected_skipped_bytes;
+ size_t size_before = parser_.RemainingBytes();
+ auto result = parser_.ParseNumericField(params);
+ ASSERT_TRUE(result.ok()) << result.message().c_str();
+ ASSERT_EQ(result.value().size(), expected_values.size());
+ for (size_t i = 0; i < expected_values.size(); i++) {
+ EXPECT_EQ(DecodeFromUnsignedToType<T>(result.value()[i]),
+ expected_values[i]);
+ }
+ size_t size_after = parser_.RemainingBytes();
+ EXPECT_EQ(size_before - size_after, expected_size)
+ << " for field " << params.name;
+ }
+
+ template <typename T>
+ void ParseAndVerifyOptionalField(
+ const FieldParameters& params,
+ const std::vector<absl::optional<T>>& expected_values,
+ size_t expected_bits_per_delta,
+ size_t expected_skipped_bytes = 0) {
+ size_t expected_size =
+ ExpectedEncodingSize(params, expected_values, expected_bits_per_delta) +
+ expected_skipped_bytes;
+ size_t size_before = parser_.RemainingBytes();
+ auto result = parser_.ParseOptionalNumericField(params);
+ ASSERT_TRUE(result.ok()) << result.message().c_str();
+ rtc::ArrayView<uint64_t> values = result.value().values;
+ rtc::ArrayView<uint8_t> positions = result.value().positions;
+ ASSERT_EQ(positions.size(), expected_values.size());
+ auto value_it = values.begin();
+ for (size_t i = 0; i < expected_values.size(); i++) {
+ if (positions[i]) {
+ ASSERT_NE(value_it, values.end());
+ ASSERT_TRUE(expected_values[i].has_value());
+ EXPECT_EQ(DecodeFromUnsignedToType<T>(*value_it),
+ expected_values[i].value());
+ ++value_it;
+ } else {
+ EXPECT_EQ(absl::nullopt, expected_values[i]);
+ }
+ }
+ EXPECT_EQ(value_it, values.end());
+ size_t size_after = parser_.RemainingBytes();
+ EXPECT_EQ(size_before - size_after, expected_size);
+ }
+
+ void ParseAndVerifyMissingField(const FieldParameters& params) {
+ auto result = parser_.ParseNumericField(params, /*required_field=*/false);
+ ASSERT_TRUE(result.ok()) << result.message().c_str();
+ EXPECT_EQ(result.value().size(), 0u);
+ }
+
+ void ParseAndVerifyMissingOptionalField(const FieldParameters& params) {
+ auto result =
+ parser_.ParseOptionalNumericField(params, /*required_field=*/false);
+ ASSERT_TRUE(result.ok()) << result.message().c_str();
+ rtc::ArrayView<uint64_t> values = result.value().values;
+ rtc::ArrayView<uint8_t> positions = result.value().positions;
+ EXPECT_EQ(positions.size(), 0u);
+ EXPECT_EQ(values.size(), 0u);
+ }
+
+ void TearDown() override {
+ for (const RtcEvent* event : batch_) {
+ delete event;
+ }
+ }
+
+ std::vector<const RtcEvent*> batch_;
+ EventParser parser_;
+};
+
+TEST_F(RtcEventFieldTest, EmptyList) {
+ EventEncoder encoder(RtcTestEvent::event_params, batch_);
+ encoder.EncodeField(RtcTestEvent::bool_params,
+ ExtractRtcEventMember(batch_, &RtcTestEvent::b_));
+ std::string s = encoder.AsString();
+ EXPECT_TRUE(s.empty());
+}
+
+TEST_F(RtcEventFieldTest, Singleton) {
+ std::vector<bool> bool_values = {true};
+ std::vector<int32_t> signed32_values = {-2};
+ std::vector<uint32_t> unsigned32_values = {123456789};
+ std::vector<int64_t> signed64_values = {-9876543210};
+ std::vector<uint64_t> unsigned64_values = {9876543210};
+ std::vector<absl::optional<int32_t>> optional32_values = {kInt32Min};
+ std::vector<absl::optional<int64_t>> optional64_values = {kInt64Max};
+ std::vector<uint32_t> wrapping21_values = {(1 << 21) - 1};
+ std::vector<std::string> string_values = {"foo"};
+
+ CreateFullEvents(bool_values, signed32_values, unsigned32_values,
+ signed64_values, unsigned64_values, optional32_values,
+ optional64_values, wrapping21_values, string_values);
+
+ EventEncoder encoder(RtcTestEvent::event_params, batch_);
+ encoder.EncodeField(RtcTestEvent::bool_params,
+ ExtractRtcEventMember(batch_, &RtcTestEvent::b_));
+ encoder.EncodeField(RtcTestEvent::signed32_params,
+ ExtractRtcEventMember(batch_, &RtcTestEvent::signed32_));
+ encoder.EncodeField(
+ RtcTestEvent::unsigned32_params,
+ ExtractRtcEventMember(batch_, &RtcTestEvent::unsigned32_));
+ encoder.EncodeField(RtcTestEvent::signed64_params,
+ ExtractRtcEventMember(batch_, &RtcTestEvent::signed64_));
+ encoder.EncodeField(
+ RtcTestEvent::unsigned64_params,
+ ExtractRtcEventMember(batch_, &RtcTestEvent::unsigned64_));
+ encoder.EncodeField(
+ RtcTestEvent::optional32_params,
+ ExtractRtcEventMember(batch_, &RtcTestEvent::optional_signed32_));
+ encoder.EncodeField(
+ RtcTestEvent::optional64_params,
+ ExtractRtcEventMember(batch_, &RtcTestEvent::optional_signed64_));
+ encoder.EncodeField(
+ RtcTestEvent::wrapping21_params,
+ ExtractRtcEventMember(batch_, &RtcTestEvent::wrapping21_));
+ encoder.EncodeField(RtcTestEvent::string_params,
+ ExtractRtcEventMember(batch_, &RtcTestEvent::string_));
+ std::string s = encoder.AsString();
+
+ // Optional debug printing
+ // PrintBytes(s);
+
+ ParseEventHeader(s);
+ ParseAndVerifyTimestamps();
+ ParseAndVerifyField(RtcTestEvent::bool_params, bool_values,
+ /*no deltas*/ 0);
+ ParseAndVerifyField(RtcTestEvent::signed32_params, signed32_values,
+ /*no deltas*/ 0);
+ ParseAndVerifyField(RtcTestEvent::unsigned32_params, unsigned32_values,
+ /*no deltas*/ 0);
+ ParseAndVerifyField(RtcTestEvent::signed64_params, signed64_values,
+ /*no deltas*/ 0);
+ ParseAndVerifyField(RtcTestEvent::unsigned64_params, unsigned64_values,
+ /*no deltas*/ 0);
+ ParseAndVerifyOptionalField(RtcTestEvent::optional32_params,
+ optional32_values, /*no deltas*/ 0);
+ ParseAndVerifyOptionalField(RtcTestEvent::optional64_params,
+ optional64_values, /*no deltas*/ 0);
+ ParseAndVerifyField(RtcTestEvent::wrapping21_params, wrapping21_values,
+ /*no deltas*/ 0);
+ ParseAndVerifyStringField(RtcTestEvent::string_params, string_values);
+ EXPECT_EQ(parser_.RemainingBytes(), 0u);
+}
+
+TEST_F(RtcEventFieldTest, EqualElements) {
+ std::vector<bool> bool_values = {true, true, true, true};
+ std::vector<int32_t> signed32_values = {-2, -2, -2, -2};
+ std::vector<uint32_t> unsigned32_values = {123456789, 123456789, 123456789,
+ 123456789};
+ std::vector<int64_t> signed64_values = {-9876543210, -9876543210, -9876543210,
+ -9876543210};
+ std::vector<uint64_t> unsigned64_values = {9876543210, 9876543210, 9876543210,
+ 9876543210};
+ std::vector<absl::optional<int32_t>> optional32_values = {
+ kInt32Min, kInt32Min, kInt32Min, kInt32Min};
+ std::vector<absl::optional<int64_t>> optional64_values = {
+ kInt64Max, kInt64Max, kInt64Max, kInt64Max};
+ std::vector<uint32_t> wrapping21_values = {(1 << 21) - 1, (1 << 21) - 1,
+ (1 << 21) - 1, (1 << 21) - 1};
+ std::vector<std::string> string_values = {"foo", "foo", "foo", "foo"};
+
+ CreateFullEvents(bool_values, signed32_values, unsigned32_values,
+ signed64_values, unsigned64_values, optional32_values,
+ optional64_values, wrapping21_values, string_values);
+ EventEncoder encoder(RtcTestEvent::event_params, batch_);
+ encoder.EncodeField(RtcTestEvent::bool_params,
+ ExtractRtcEventMember(batch_, &RtcTestEvent::b_));
+ encoder.EncodeField(RtcTestEvent::signed32_params,
+ ExtractRtcEventMember(batch_, &RtcTestEvent::signed32_));
+ encoder.EncodeField(
+ RtcTestEvent::unsigned32_params,
+ ExtractRtcEventMember(batch_, &RtcTestEvent::unsigned32_));
+ encoder.EncodeField(RtcTestEvent::signed64_params,
+ ExtractRtcEventMember(batch_, &RtcTestEvent::signed64_));
+ encoder.EncodeField(
+ RtcTestEvent::unsigned64_params,
+ ExtractRtcEventMember(batch_, &RtcTestEvent::unsigned64_));
+ encoder.EncodeField(
+ RtcTestEvent::optional32_params,
+ ExtractRtcEventMember(batch_, &RtcTestEvent::optional_signed32_));
+ encoder.EncodeField(
+ RtcTestEvent::optional64_params,
+ ExtractRtcEventMember(batch_, &RtcTestEvent::optional_signed64_));
+ encoder.EncodeField(
+ RtcTestEvent::wrapping21_params,
+ ExtractRtcEventMember(batch_, &RtcTestEvent::wrapping21_));
+ encoder.EncodeField(RtcTestEvent::string_params,
+ ExtractRtcEventMember(batch_, &RtcTestEvent::string_));
+ std::string s = encoder.AsString();
+
+ // Optional debug printing
+ // PrintBytes(s);
+
+ ParseEventHeader(s);
+ ParseAndVerifyTimestamps();
+ ParseAndVerifyField(RtcTestEvent::bool_params, bool_values,
+ /*no deltas*/ 0);
+ ParseAndVerifyField(RtcTestEvent::signed32_params, signed32_values,
+ /*no deltas*/ 0);
+ ParseAndVerifyField(RtcTestEvent::unsigned32_params, unsigned32_values,
+ /*no deltas*/ 0);
+ ParseAndVerifyField(RtcTestEvent::signed64_params, signed64_values,
+ /*no deltas*/ 0);
+ ParseAndVerifyField(RtcTestEvent::unsigned64_params, unsigned64_values,
+ /*no deltas*/ 0);
+ ParseAndVerifyOptionalField(RtcTestEvent::optional32_params,
+ optional32_values, /*no deltas*/ 0);
+ ParseAndVerifyOptionalField(RtcTestEvent::optional64_params,
+ optional64_values, /*no deltas*/ 0);
+ ParseAndVerifyField(RtcTestEvent::wrapping21_params, wrapping21_values,
+ /*no deltas*/ 0);
+ ParseAndVerifyStringField(RtcTestEvent::string_params, string_values);
+ EXPECT_EQ(parser_.RemainingBytes(), 0u);
+}
+
+TEST_F(RtcEventFieldTest, Increasing) {
+ std::vector<bool> bool_values = {false, true, false, true};
+ std::vector<int32_t> signed32_values = {-2, -1, 0, 1};
+ std::vector<uint32_t> unsigned32_values = {kUint32Max - 1, kUint32Max, 0, 1};
+ std::vector<int64_t> signed64_values = {kInt64Max - 1, kInt64Max, kInt64Min,
+ kInt64Min + 1};
+ std::vector<uint64_t> unsigned64_values = {kUint64Max - 1, kUint64Max, 0, 1};
+ std::vector<absl::optional<int32_t>> optional32_values = {
+ kInt32Max - 1, kInt32Max, kInt32Min, kInt32Min + 1};
+ std::vector<absl::optional<int64_t>> optional64_values = {
+ kInt64Max - 1, kInt64Max, kInt64Min, kInt64Min + 1};
+ std::vector<uint32_t> wrapping21_values = {(1 << 21) - 2, (1 << 21) - 1, 0,
+ 1};
+ std::vector<std::string> string_values = {
+ "", "a", "bc", "def"}; // No special compression of strings.
+
+ CreateFullEvents(bool_values, signed32_values, unsigned32_values,
+ signed64_values, unsigned64_values, optional32_values,
+ optional64_values, wrapping21_values, string_values);
+
+ EventEncoder encoder(RtcTestEvent::event_params, batch_);
+ encoder.EncodeField(RtcTestEvent::bool_params,
+ ExtractRtcEventMember(batch_, &RtcTestEvent::b_));
+ encoder.EncodeField(RtcTestEvent::signed32_params,
+ ExtractRtcEventMember(batch_, &RtcTestEvent::signed32_));
+ encoder.EncodeField(
+ RtcTestEvent::unsigned32_params,
+ ExtractRtcEventMember(batch_, &RtcTestEvent::unsigned32_));
+ encoder.EncodeField(RtcTestEvent::signed64_params,
+ ExtractRtcEventMember(batch_, &RtcTestEvent::signed64_));
+ encoder.EncodeField(
+ RtcTestEvent::unsigned64_params,
+ ExtractRtcEventMember(batch_, &RtcTestEvent::unsigned64_));
+ encoder.EncodeField(
+ RtcTestEvent::optional32_params,
+ ExtractRtcEventMember(batch_, &RtcTestEvent::optional_signed32_));
+ encoder.EncodeField(
+ RtcTestEvent::optional64_params,
+ ExtractRtcEventMember(batch_, &RtcTestEvent::optional_signed64_));
+ encoder.EncodeField(
+ RtcTestEvent::wrapping21_params,
+ ExtractRtcEventMember(batch_, &RtcTestEvent::wrapping21_));
+ encoder.EncodeField(RtcTestEvent::string_params,
+ ExtractRtcEventMember(batch_, &RtcTestEvent::string_));
+ std::string s = encoder.AsString();
+
+ // Optional debug printing
+ // PrintBytes(s);
+
+ ParseEventHeader(s);
+ ParseAndVerifyTimestamps();
+ ParseAndVerifyField(RtcTestEvent::bool_params, bool_values,
+ /*delta bits*/ 1);
+ ParseAndVerifyField(RtcTestEvent::signed32_params, signed32_values,
+ /*delta bits*/ 1);
+ ParseAndVerifyField(RtcTestEvent::unsigned32_params, unsigned32_values,
+ /*delta bits*/ 1);
+ ParseAndVerifyField(RtcTestEvent::signed64_params, signed64_values,
+ /*delta bits*/ 1);
+ ParseAndVerifyField(RtcTestEvent::unsigned64_params, unsigned64_values,
+ /*delta bits*/ 1);
+ ParseAndVerifyOptionalField(RtcTestEvent::optional32_params,
+ optional32_values, /*delta bits*/ 1);
+ ParseAndVerifyOptionalField(RtcTestEvent::optional64_params,
+ optional64_values, /*delta bits*/ 1);
+ ParseAndVerifyField(RtcTestEvent::wrapping21_params, wrapping21_values,
+ /*delta bits*/ 1);
+ ParseAndVerifyStringField(RtcTestEvent::string_params, string_values);
+ EXPECT_EQ(parser_.RemainingBytes(), 0u);
+}
+
+TEST_F(RtcEventFieldTest, Decreasing) {
+ std::vector<bool> bool_values = {true, false, true, false};
+ std::vector<int32_t> signed32_values = {2, 1, 0, -1};
+ std::vector<uint32_t> unsigned32_values = {1, 0, kUint32Max, kUint32Max - 1};
+ std::vector<int64_t> signed64_values = {kInt64Min + 1, kInt64Min, kInt64Max,
+ kInt64Max - 1};
+ std::vector<uint64_t> unsigned64_values = {1, 0, kUint64Max, kUint64Max - 1};
+ std::vector<absl::optional<int32_t>> optional32_values = {
+ kInt32Min + 1, kInt32Min, kInt32Max, kInt32Max - 1};
+ std::vector<absl::optional<int64_t>> optional64_values = {
+ kInt64Min + 1, kInt64Min, kInt64Max, kInt64Max - 1};
+ std::vector<uint32_t> wrapping21_values = {1, 0, (1 << 21) - 1,
+ (1 << 21) - 2};
+ std::vector<std::string> string_values = {
+ "def", "bc", "a", ""}; // No special compression of strings.
+
+ CreateFullEvents(bool_values, signed32_values, unsigned32_values,
+ signed64_values, unsigned64_values, optional32_values,
+ optional64_values, wrapping21_values, string_values);
+
+ EventEncoder encoder(RtcTestEvent::event_params, batch_);
+ encoder.EncodeField(RtcTestEvent::bool_params,
+ ExtractRtcEventMember(batch_, &RtcTestEvent::b_));
+ encoder.EncodeField(RtcTestEvent::signed32_params,
+ ExtractRtcEventMember(batch_, &RtcTestEvent::signed32_));
+ encoder.EncodeField(
+ RtcTestEvent::unsigned32_params,
+ ExtractRtcEventMember(batch_, &RtcTestEvent::unsigned32_));
+ encoder.EncodeField(RtcTestEvent::signed64_params,
+ ExtractRtcEventMember(batch_, &RtcTestEvent::signed64_));
+ encoder.EncodeField(
+ RtcTestEvent::unsigned64_params,
+ ExtractRtcEventMember(batch_, &RtcTestEvent::unsigned64_));
+ encoder.EncodeField(
+ RtcTestEvent::optional32_params,
+ ExtractRtcEventMember(batch_, &RtcTestEvent::optional_signed32_));
+ encoder.EncodeField(
+ RtcTestEvent::optional64_params,
+ ExtractRtcEventMember(batch_, &RtcTestEvent::optional_signed64_));
+ encoder.EncodeField(
+ RtcTestEvent::wrapping21_params,
+ ExtractRtcEventMember(batch_, &RtcTestEvent::wrapping21_));
+ encoder.EncodeField(RtcTestEvent::string_params,
+ ExtractRtcEventMember(batch_, &RtcTestEvent::string_));
+ std::string s = encoder.AsString();
+
+ // Optional debug printing
+ // PrintBytes(s);
+
+ ParseEventHeader(s);
+ ParseAndVerifyTimestamps();
+ ParseAndVerifyField(RtcTestEvent::bool_params, bool_values,
+ /*delta bits*/ 1);
+ ParseAndVerifyField(RtcTestEvent::signed32_params, signed32_values,
+ /*delta bits*/ 1);
+ ParseAndVerifyField(RtcTestEvent::unsigned32_params, unsigned32_values,
+ /*delta bits*/ 1);
+ ParseAndVerifyField(RtcTestEvent::signed64_params, signed64_values,
+ /*delta bits*/ 1);
+ ParseAndVerifyField(RtcTestEvent::unsigned64_params, unsigned64_values,
+ /*delta bits*/ 1);
+ ParseAndVerifyOptionalField(RtcTestEvent::optional32_params,
+ optional32_values, /*delta bits*/ 1);
+ ParseAndVerifyOptionalField(RtcTestEvent::optional64_params,
+ optional64_values, /*delta bits*/ 1);
+ ParseAndVerifyField(RtcTestEvent::wrapping21_params, wrapping21_values,
+ /*delta bits*/ 1);
+ ParseAndVerifyStringField(RtcTestEvent::string_params, string_values);
+ EXPECT_EQ(parser_.RemainingBytes(), 0u);
+}
+
+TEST_F(RtcEventFieldTest, SkipsDeprecatedFields) {
+ // Expect parser to skip fields it doesn't recognize, but find subsequent
+ // fields.
+ std::vector<bool> bool_values = {true, false};
+ std::vector<int32_t> signed32_values = {kInt32Min / 2, kInt32Max / 2};
+ std::vector<uint32_t> unsigned32_values = {0, kUint32Max / 2};
+ std::vector<int64_t> signed64_values = {kInt64Min / 2, kInt64Max / 2};
+ std::vector<uint64_t> unsigned64_values = {0, kUint64Max / 2};
+ std::vector<absl::optional<int32_t>> optional32_values = {kInt32Max / 2,
+ kInt32Min / 2};
+ std::vector<absl::optional<int64_t>> optional64_values = {kInt64Min / 2,
+ kInt64Max / 2};
+ std::vector<uint32_t> wrapping21_values = {0, 1 << 20};
+ std::vector<std::string> string_values = {"foo", "bar"};
+
+ size_t signed32_encoding_size =
+ /*tag*/ 1 + /* varint base*/ 5 + /* delta_header*/ 1 + /*deltas*/ 4;
+ size_t signed64_encoding_size =
+ /*tag*/ 1 + /* fixed64 base*/ 8 + /* delta_header*/ 1 + /*deltas*/ 8;
+ size_t optional32_encoding_size =
+ /*tag*/ 1 + /* fixed32 base*/ 4 + /* delta_header*/ 1 + /*deltas*/ 4;
+
+ CreateFullEvents(bool_values, signed32_values, unsigned32_values,
+ signed64_values, unsigned64_values, optional32_values,
+ optional64_values, wrapping21_values, string_values);
+
+ EventEncoder encoder(RtcTestEvent::event_params, batch_);
+ encoder.EncodeField(RtcTestEvent::bool_params,
+ ExtractRtcEventMember(batch_, &RtcTestEvent::b_));
+ encoder.EncodeField(RtcTestEvent::signed32_params,
+ ExtractRtcEventMember(batch_, &RtcTestEvent::signed32_));
+ encoder.EncodeField(
+ RtcTestEvent::unsigned32_params,
+ ExtractRtcEventMember(batch_, &RtcTestEvent::unsigned32_));
+ encoder.EncodeField(RtcTestEvent::signed64_params,
+ ExtractRtcEventMember(batch_, &RtcTestEvent::signed64_));
+ encoder.EncodeField(
+ RtcTestEvent::unsigned64_params,
+ ExtractRtcEventMember(batch_, &RtcTestEvent::unsigned64_));
+ encoder.EncodeField(
+ RtcTestEvent::optional32_params,
+ ExtractRtcEventMember(batch_, &RtcTestEvent::optional_signed32_));
+ encoder.EncodeField(
+ RtcTestEvent::optional64_params,
+ ExtractRtcEventMember(batch_, &RtcTestEvent::optional_signed64_));
+ encoder.EncodeField(
+ RtcTestEvent::wrapping21_params,
+ ExtractRtcEventMember(batch_, &RtcTestEvent::wrapping21_));
+ encoder.EncodeField(RtcTestEvent::string_params,
+ ExtractRtcEventMember(batch_, &RtcTestEvent::string_));
+ std::string s = encoder.AsString();
+
+ // Optional debug printing
+ // PrintBytes(s);
+
+ ParseEventHeader(s);
+ ParseAndVerifyTimestamps();
+ ParseAndVerifyField(RtcTestEvent::bool_params, bool_values,
+ /*delta_bits=*/1);
+ // Skips parsing the `signed32_values`. The following unsigned fields should
+ // still be found.
+ ParseAndVerifyField(RtcTestEvent::unsigned32_params, unsigned32_values,
+ /*delta_bits=*/31,
+ /*expected_skipped_bytes=*/signed32_encoding_size);
+ // Skips parsing the `signed64_values`. The following unsigned fields should
+ // still be found.
+ ParseAndVerifyField(RtcTestEvent::unsigned64_params, unsigned64_values,
+ /*delta_bits=*/63, signed64_encoding_size);
+ // Skips parsing the `optional32_values`. The following unsigned fields should
+ // still be found.
+ ParseAndVerifyOptionalField(RtcTestEvent::optional64_params,
+ optional64_values,
+ /*delta_bits=*/63, optional32_encoding_size);
+ ParseAndVerifyField(RtcTestEvent::wrapping21_params, wrapping21_values,
+ /*delta_bits=*/20);
+ ParseAndVerifyStringField(RtcTestEvent::string_params, string_values);
+ EXPECT_EQ(parser_.RemainingBytes(), 0u);
+}
+
+TEST_F(RtcEventFieldTest, SkipsMissingFields) {
+ // Expect parsing of missing field to succeed but return an empty list.
+
+ std::vector<bool> bool_values = {true, false};
+ std::vector<int32_t> signed32_values = {kInt32Min / 2, kInt32Max / 2};
+ std::vector<uint32_t> unsigned32_values = {0, kUint32Max / 2};
+ std::vector<int64_t> signed64_values = {kInt64Min / 2, kInt64Max / 2};
+ std::vector<uint64_t> unsigned64_values = {0, kUint64Max / 2};
+ std::vector<absl::optional<int32_t>> optional32_values = {kInt32Max / 2,
+ kInt32Min / 2};
+ std::vector<absl::optional<int64_t>> optional64_values = {kInt64Min / 2,
+ kInt64Max / 2};
+ std::vector<uint32_t> wrapping21_values = {0, 1 << 20};
+ std::vector<std::string> string_values = {"foo", "foo"};
+
+ CreateFullEvents(bool_values, signed32_values, unsigned32_values,
+ signed64_values, unsigned64_values, optional32_values,
+ optional64_values, wrapping21_values, string_values);
+
+ EventEncoder encoder(RtcTestEvent::event_params, batch_);
+ // Skip encoding the `bool_values`.
+ encoder.EncodeField(RtcTestEvent::signed32_params,
+ ExtractRtcEventMember(batch_, &RtcTestEvent::signed32_));
+ // Skip encoding the `unsigned32_values`.
+ encoder.EncodeField(RtcTestEvent::signed64_params,
+ ExtractRtcEventMember(batch_, &RtcTestEvent::signed64_));
+ // Skip encoding the `unsigned64_values`.
+ encoder.EncodeField(
+ RtcTestEvent::optional32_params,
+ ExtractRtcEventMember(batch_, &RtcTestEvent::optional_signed32_));
+ // Skip encoding the `optional64_values`.
+ encoder.EncodeField(
+ RtcTestEvent::wrapping21_params,
+ ExtractRtcEventMember(batch_, &RtcTestEvent::wrapping21_));
+ encoder.EncodeField(RtcTestEvent::string_params,
+ ExtractRtcEventMember(batch_, &RtcTestEvent::string_));
+ std::string s = encoder.AsString();
+
+ // Optional debug printing
+ // PrintBytes(s);
+
+ ParseEventHeader(s);
+ ParseAndVerifyTimestamps();
+ ParseAndVerifyMissingField(RtcTestEvent::bool_params);
+ ParseAndVerifyField(RtcTestEvent::signed32_params, signed32_values,
+ /*delta_bits=*/31);
+ ParseAndVerifyMissingField(RtcTestEvent::unsigned32_params);
+ ParseAndVerifyField(RtcTestEvent::signed64_params, signed64_values,
+ /*delta_bits=*/63);
+ ParseAndVerifyMissingField(RtcTestEvent::unsigned64_params);
+ ParseAndVerifyOptionalField(RtcTestEvent::optional32_params,
+ optional32_values, /*delta_bits=*/31);
+ ParseAndVerifyMissingOptionalField(RtcTestEvent::optional64_params);
+ ParseAndVerifyField(RtcTestEvent::wrapping21_params, wrapping21_values,
+ /*delta_bits=*/20);
+ ParseAndVerifyStringField(RtcTestEvent::string_params, string_values);
+ EXPECT_EQ(parser_.RemainingBytes(), 0u);
+}
+
+TEST_F(RtcEventFieldTest, OptionalFields) {
+ std::vector<absl::optional<int32_t>> optional32_values = {
+ 2, absl::nullopt, 4, absl::nullopt, 6, absl::nullopt};
+ std::vector<absl::optional<int64_t>> optional64_values = {
+ absl::nullopt, 1024, absl::nullopt, 1025, absl::nullopt, 1026};
+ std::vector<uint32_t> wrapping21_values = {(1 << 21) - 3, 0, 2, 5, 5, 6};
+
+ for (size_t i = 0; i < optional32_values.size(); i++) {
+ batch_.push_back(new RtcTestEvent(0, 0, 0, 0, 0, optional32_values[i],
+ optional64_values[i],
+ wrapping21_values[i], ""));
+ }
+
+ EventEncoder encoder(RtcTestEvent::event_params, batch_);
+ encoder.EncodeField(
+ RtcTestEvent::optional32_params,
+ ExtractRtcEventMember(batch_, &RtcTestEvent::optional_signed32_));
+ encoder.EncodeField(
+ RtcTestEvent::optional64_params,
+ ExtractRtcEventMember(batch_, &RtcTestEvent::optional_signed64_));
+ encoder.EncodeField(
+ RtcTestEvent::wrapping21_params,
+ ExtractRtcEventMember(batch_, &RtcTestEvent::wrapping21_));
+ std::string s = encoder.AsString();
+
+ // Optional debug output
+ // PrintBytes(s);
+
+ ParseEventHeader(s);
+ ParseAndVerifyTimestamps();
+ ParseAndVerifyOptionalField(RtcTestEvent::optional32_params,
+ optional32_values, /*delta bits*/ 2);
+ ParseAndVerifyOptionalField(RtcTestEvent::optional64_params,
+ optional64_values, /*delta bits*/ 1);
+ ParseAndVerifyField(RtcTestEvent::wrapping21_params, wrapping21_values,
+ /*delta bits*/ 2);
+ EXPECT_EQ(parser_.RemainingBytes(), 0u);
+}
+
+TEST_F(RtcEventFieldTest, AllNulloptTreatedAsMissing) {
+ std::vector<absl::optional<int32_t>> optional32_values = {
+ absl::nullopt, absl::nullopt, absl::nullopt,
+ absl::nullopt, absl::nullopt, absl::nullopt};
+ std::vector<absl::optional<int64_t>> optional64_values = {
+ absl::nullopt, 1024, absl::nullopt, 1025, absl::nullopt, 1026};
+
+ for (size_t i = 0; i < optional32_values.size(); i++) {
+ batch_.push_back(new RtcTestEvent(0, 0, 0, 0, 0, optional32_values[i],
+ optional64_values[i], 0, ""));
+ }
+
+ EventEncoder encoder(RtcTestEvent::event_params, batch_);
+ encoder.EncodeField(
+ RtcTestEvent::optional32_params,
+ ExtractRtcEventMember(batch_, &RtcTestEvent::optional_signed32_));
+ encoder.EncodeField(
+ RtcTestEvent::optional64_params,
+ ExtractRtcEventMember(batch_, &RtcTestEvent::optional_signed64_));
+ std::string s = encoder.AsString();
+
+ // Optional debug output
+ // PrintBytes(s);
+
+ ParseEventHeader(s);
+ ParseAndVerifyTimestamps();
+ ParseAndVerifyMissingOptionalField(RtcTestEvent::optional32_params);
+ ParseAndVerifyOptionalField(RtcTestEvent::optional64_params,
+ optional64_values, /*delta_bits=*/1);
+ EXPECT_EQ(parser_.RemainingBytes(), 0u);
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_field_extraction.cc b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_field_extraction.cc
new file mode 100644
index 0000000000..99f0b3697c
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_field_extraction.cc
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2021 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_field_extraction.h"
+
+#include <algorithm>
+#include <limits>
+
+#include "rtc_base/checks.h"
+
+namespace webrtc_event_logging {
+
+// The bitwidth required to encode values in the range
+// [0, `max_pos_magnitude`] using an unsigned representation.
+uint8_t UnsignedBitWidth(uint64_t max_magnitude) {
+ uint8_t required_bits = 1;
+ while (max_magnitude >>= 1) {
+ ++required_bits;
+ }
+ return required_bits;
+}
+
+// The bitwidth required to encode signed values in the range
+// [-`max_neg_magnitude`, `max_pos_magnitude`] using a signed
+// 2-complement representation.
+uint8_t SignedBitWidth(uint64_t max_pos_magnitude, uint64_t max_neg_magnitude) {
+ const uint8_t bitwidth_positive =
+ max_pos_magnitude > 0 ? UnsignedBitWidth(max_pos_magnitude) : 0;
+ const uint8_t bitwidth_negative =
+ (max_neg_magnitude > 1) ? UnsignedBitWidth(max_neg_magnitude - 1) : 0;
+ return 1 + std::max(bitwidth_positive, bitwidth_negative);
+}
+
+// Return the maximum integer of a given bit width.
+uint64_t MaxUnsignedValueOfBitWidth(uint64_t bit_width) {
+ RTC_DCHECK_GE(bit_width, 1);
+ RTC_DCHECK_LE(bit_width, 64);
+ return (bit_width == 64) ? std::numeric_limits<uint64_t>::max()
+ : ((static_cast<uint64_t>(1) << bit_width) - 1);
+}
+
+// Computes the delta between `previous` and `current`, under the assumption
+// that `bit_mask` is the largest value before wrap-around occurs. The bitmask
+// must be of the form 2^x-1. (We use the wrap-around to more efficiently
+// compress counters that wrap around at different bit widths than the
+// backing C++ data type.)
+uint64_t UnsignedDelta(uint64_t previous, uint64_t current, uint64_t bit_mask) {
+ RTC_DCHECK_LE(previous, bit_mask);
+ RTC_DCHECK_LE(current, bit_mask);
+ return (current - previous) & bit_mask;
+}
+
+} // namespace webrtc_event_logging
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_field_extraction.h b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_field_extraction.h
new file mode 100644
index 0000000000..eb9d67f1c2
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_field_extraction.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2021 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_FIELD_EXTRACTION_H_
+#define LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_FIELD_EXTRACTION_H_
+
+#include <string>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "api/rtc_event_log/rtc_event.h"
+#include "api/units/timestamp.h"
+#include "logging/rtc_event_log/encoder/rtc_event_log_encoder_common.h"
+#include "rtc_base/logging.h"
+
+namespace webrtc_event_logging {
+uint8_t UnsignedBitWidth(uint64_t max_magnitude);
+uint8_t SignedBitWidth(uint64_t max_pos_magnitude, uint64_t max_neg_magnitude);
+uint64_t MaxUnsignedValueOfBitWidth(uint64_t bit_width);
+uint64_t UnsignedDelta(uint64_t previous, uint64_t current, uint64_t bit_mask);
+} // namespace webrtc_event_logging
+
+namespace webrtc {
+template <typename T, std::enable_if_t<std::is_signed<T>::value, bool> = true>
+uint64_t EncodeAsUnsigned(T value) {
+ return webrtc_event_logging::ToUnsigned(value);
+}
+
+template <typename T, std::enable_if_t<std::is_unsigned<T>::value, bool> = true>
+uint64_t EncodeAsUnsigned(T value) {
+ return static_cast<uint64_t>(value);
+}
+
+template <typename T, std::enable_if_t<std::is_signed<T>::value, bool> = true>
+T DecodeFromUnsignedToType(uint64_t value) {
+ T signed_value = 0;
+ bool success = webrtc_event_logging::ToSigned<T>(value, &signed_value);
+ if (!success) {
+ RTC_LOG(LS_ERROR) << "Failed to convert " << value << "to signed type.";
+ // TODO(terelius): Propagate error?
+ }
+ return signed_value;
+}
+
+template <typename T, std::enable_if_t<std::is_unsigned<T>::value, bool> = true>
+T DecodeFromUnsignedToType(uint64_t value) {
+ // TODO(terelius): Check range?
+ return static_cast<T>(value);
+}
+
+// RtcEventLogEnum<T> defines a mapping between an enum T
+// and the event log encodings. To log a new enum type T,
+// specialize RtcEventLogEnum<T> and add static methods
+// static uint64_t Encode(T x) {}
+// static RtcEventLogParseStatusOr<T> Decode(uint64_t x) {}
+template <typename T>
+class RtcEventLogEnum {
+ static_assert(sizeof(T) != sizeof(T),
+ "Missing specialisation of RtcEventLogEnum for type");
+};
+
+// Represents a vector<optional<uint64_t>> optional_values
+// as a bit-vector `position_mask` which identifies the positions
+// of existing values, and a (potentially shorter)
+// `vector<uint64_t> values` containing the actual values.
+// The bit vector is constructed such that position_mask[i]
+// is true iff optional_values[i] has a value, and `values.size()`
+// is equal to the number of set bits in `position_mask`.
+struct ValuesWithPositions {
+ std::vector<bool> position_mask;
+ std::vector<uint64_t> values;
+};
+
+} // namespace webrtc
+
+#endif // LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_FIELD_EXTRACTION_H_
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_field_extraction_unittest.cc b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_field_extraction_unittest.cc
new file mode 100644
index 0000000000..f9fb993af0
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_field_extraction_unittest.cc
@@ -0,0 +1,97 @@
+/* Copyright (c) 2021 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_field_extraction.h"
+
+#include "rtc_base/random.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+
+TEST(UnsignedBitWidthTest, SmallValues) {
+ EXPECT_EQ(webrtc_event_logging::UnsignedBitWidth(0), 1u);
+ EXPECT_EQ(webrtc_event_logging::UnsignedBitWidth(1), 1u);
+ EXPECT_EQ(webrtc_event_logging::UnsignedBitWidth(2), 2u);
+ EXPECT_EQ(webrtc_event_logging::UnsignedBitWidth(3), 2u);
+ EXPECT_EQ(webrtc_event_logging::UnsignedBitWidth(4), 3u);
+ EXPECT_EQ(webrtc_event_logging::UnsignedBitWidth(5), 3u);
+ EXPECT_EQ(webrtc_event_logging::UnsignedBitWidth(6), 3u);
+ EXPECT_EQ(webrtc_event_logging::UnsignedBitWidth(7), 3u);
+}
+
+TEST(UnsignedBitWidthTest, PowersOfTwo) {
+ EXPECT_EQ(webrtc_event_logging::UnsignedBitWidth(0), 1u);
+
+ for (unsigned i = 0; i < 64; i++) {
+ uint64_t x = 1;
+ x = x << i;
+ EXPECT_EQ(webrtc_event_logging::UnsignedBitWidth(x), i + 1);
+ }
+}
+
+TEST(UnsignedBitWidthTest, PowersOfTwoMinusOne) {
+ for (unsigned i = 1; i < 64; i++) {
+ uint64_t x = 1;
+ x = (x << i) - 1;
+ EXPECT_EQ(webrtc_event_logging::UnsignedBitWidth(x), i);
+ }
+
+ uint64_t x = ~static_cast<uint64_t>(0);
+ EXPECT_EQ(webrtc_event_logging::UnsignedBitWidth(x), 64u);
+}
+
+TEST(UnsignedBitWidthTest, RandomInputs) {
+ Random rand(12345);
+
+ for (unsigned i = 0; i < 64; i++) {
+ uint64_t x = 1;
+ x = x << i;
+ uint64_t high = rand.Rand<uint32_t>();
+ uint64_t low = rand.Rand<uint32_t>();
+ x += ((high << 32) + low) % x;
+ EXPECT_EQ(webrtc_event_logging::UnsignedBitWidth(x), i + 1);
+ }
+}
+
+TEST(SignedBitWidthTest, SignedBitWidth) {
+ EXPECT_EQ(webrtc_event_logging::SignedBitWidth(0, 1), 1u);
+ EXPECT_EQ(webrtc_event_logging::SignedBitWidth(1, 0), 2u);
+ EXPECT_EQ(webrtc_event_logging::SignedBitWidth(1, 2), 2u);
+ EXPECT_EQ(webrtc_event_logging::SignedBitWidth(1, 128), 8u);
+ EXPECT_EQ(webrtc_event_logging::SignedBitWidth(127, 1), 8u);
+ EXPECT_EQ(webrtc_event_logging::SignedBitWidth(127, 128), 8u);
+ EXPECT_EQ(webrtc_event_logging::SignedBitWidth(1, 129), 9u);
+ EXPECT_EQ(webrtc_event_logging::SignedBitWidth(128, 1), 9u);
+}
+
+TEST(MaxUnsignedValueOfBitWidthTest, MaxUnsignedValueOfBitWidth) {
+ EXPECT_EQ(webrtc_event_logging::MaxUnsignedValueOfBitWidth(1), 0x01u);
+ EXPECT_EQ(webrtc_event_logging::MaxUnsignedValueOfBitWidth(6), 0x3Fu);
+ EXPECT_EQ(webrtc_event_logging::MaxUnsignedValueOfBitWidth(8), 0xFFu);
+ EXPECT_EQ(webrtc_event_logging::MaxUnsignedValueOfBitWidth(32), 0xFFFFFFFFu);
+}
+
+TEST(EncodeAsUnsignedTest, NegativeValues) {
+ // Negative values are converted as if cast to unsigned type of
+ // the same bitsize using 2-complement representation.
+ int16_t x = -1;
+ EXPECT_EQ(EncodeAsUnsigned(x), static_cast<uint64_t>(0xFFFF));
+ int64_t y = -1;
+ EXPECT_EQ(EncodeAsUnsigned(y), static_cast<uint64_t>(0xFFFFFFFFFFFFFFFFull));
+}
+
+TEST(EncodeAsUnsignedTest, PositiveValues) {
+ // Postive values are unchanged.
+ int16_t x = 42;
+ EXPECT_EQ(EncodeAsUnsigned(x), static_cast<uint64_t>(42));
+ int64_t y = 42;
+ EXPECT_EQ(EncodeAsUnsigned(y), static_cast<uint64_t>(42));
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_frame_decoded.cc b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_frame_decoded.cc
new file mode 100644
index 0000000000..cde412e6c4
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_frame_decoded.cc
@@ -0,0 +1,44 @@
+/*
+ * 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_frame_decoded.h"
+
+#include "absl/memory/memory.h"
+
+namespace webrtc {
+
+RtcEventFrameDecoded::RtcEventFrameDecoded(int64_t render_time_ms,
+ uint32_t ssrc,
+ int width,
+ int height,
+ VideoCodecType codec,
+ uint8_t qp)
+ : render_time_ms_(render_time_ms),
+ ssrc_(ssrc),
+ width_(width),
+ height_(height),
+ codec_(codec),
+ qp_(qp) {}
+
+RtcEventFrameDecoded::RtcEventFrameDecoded(const RtcEventFrameDecoded& other)
+ : RtcEvent(other.timestamp_us_),
+ render_time_ms_(other.render_time_ms_),
+ ssrc_(other.ssrc_),
+ width_(other.width_),
+ height_(other.height_),
+ codec_(other.codec_),
+ qp_(other.qp_) {}
+
+std::unique_ptr<RtcEventFrameDecoded> RtcEventFrameDecoded::Copy() const {
+ return absl::WrapUnique<RtcEventFrameDecoded>(
+ new RtcEventFrameDecoded(*this));
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_frame_decoded.h b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_frame_decoded.h
new file mode 100644
index 0000000000..91190faea9
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_frame_decoded.h
@@ -0,0 +1,93 @@
+/*
+ * 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_FRAME_DECODED_H_
+#define LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_FRAME_DECODED_H_
+
+#include <stdint.h>
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/rtc_event_log/rtc_event.h"
+#include "api/units/timestamp.h"
+#include "api/video/video_codec_type.h"
+#include "logging/rtc_event_log/events/rtc_event_field_encoding_parser.h"
+
+namespace webrtc {
+
+struct LoggedFrameDecoded {
+ int64_t log_time_us() const { return timestamp.us(); }
+ int64_t log_time_ms() const { return timestamp.ms(); }
+ Timestamp log_time() const { return timestamp; }
+
+ Timestamp timestamp = Timestamp::MinusInfinity();
+ int64_t render_time_ms;
+ uint32_t ssrc;
+ int width;
+ int height;
+ VideoCodecType codec;
+ uint8_t qp;
+};
+
+class RtcEventFrameDecoded final : public RtcEvent {
+ public:
+ static constexpr Type kType = Type::FrameDecoded;
+
+ RtcEventFrameDecoded(int64_t render_time_ms,
+ uint32_t ssrc,
+ int width,
+ int height,
+ VideoCodecType codec,
+ uint8_t qp);
+ ~RtcEventFrameDecoded() override = default;
+
+ Type GetType() const override { return kType; }
+ bool IsConfigEvent() const override { return false; }
+
+ std::unique_ptr<RtcEventFrameDecoded> Copy() const;
+
+ int64_t render_time_ms() const { return render_time_ms_; }
+ uint32_t ssrc() const { return ssrc_; }
+ int width() const { return width_; }
+ int height() const { return height_; }
+ VideoCodecType codec() const { return codec_; }
+ uint8_t qp() const { return qp_; }
+
+ static std::string Encode(rtc::ArrayView<const RtcEvent*> batch) {
+ // TODO(terelius): Implement
+ return "";
+ }
+
+ static RtcEventLogParseStatus Parse(
+ absl::string_view encoded_bytes,
+ bool batched,
+ std::map<uint32_t, std::vector<LoggedFrameDecoded>>& output) {
+ // TODO(terelius): Implement
+ return RtcEventLogParseStatus::Error("Not Implemented", __FILE__, __LINE__);
+ }
+
+ private:
+ RtcEventFrameDecoded(const RtcEventFrameDecoded& other);
+
+ const int64_t render_time_ms_;
+ const uint32_t ssrc_;
+ const int width_;
+ const int height_;
+ const VideoCodecType codec_;
+ const uint8_t qp_;
+};
+
+} // namespace webrtc
+
+#endif // LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_FRAME_DECODED_H_
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_generic_ack_received.cc b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_generic_ack_received.cc
new file mode 100644
index 0000000000..ba18d50ab6
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_generic_ack_received.cc
@@ -0,0 +1,55 @@
+/*
+ * 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_generic_ack_received.h"
+
+#include <vector>
+
+#include "absl/memory/memory.h"
+#include "rtc_base/time_utils.h"
+
+namespace webrtc {
+
+std::vector<std::unique_ptr<RtcEventGenericAckReceived>>
+RtcEventGenericAckReceived::CreateLogs(
+ int64_t packet_number,
+ const std::vector<AckedPacket>& acked_packets) {
+ std::vector<std::unique_ptr<RtcEventGenericAckReceived>> result;
+ int64_t time_us = rtc::TimeMicros();
+ result.reserve(acked_packets.size());
+ for (const AckedPacket& packet : acked_packets) {
+ result.emplace_back(new RtcEventGenericAckReceived(
+ time_us, packet_number, packet.packet_number,
+ packet.receive_acked_packet_time_ms));
+ }
+ return result;
+}
+
+RtcEventGenericAckReceived::RtcEventGenericAckReceived(
+ int64_t timestamp_us,
+ int64_t packet_number,
+ int64_t acked_packet_number,
+ absl::optional<int64_t> receive_acked_packet_time_ms)
+ : RtcEvent(timestamp_us),
+ packet_number_(packet_number),
+ acked_packet_number_(acked_packet_number),
+ 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;
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_generic_ack_received.h b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_generic_ack_received.h
new file mode 100644
index 0000000000..57fd7cd9a6
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_generic_ack_received.h
@@ -0,0 +1,118 @@
+/*
+ * 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_GENERIC_ACK_RECEIVED_H_
+#define LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_GENERIC_ACK_RECEIVED_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "absl/types/optional.h"
+#include "api/rtc_event_log/rtc_event.h"
+#include "api/units/timestamp.h"
+#include "logging/rtc_event_log/events/rtc_event_field_encoding_parser.h"
+
+namespace webrtc {
+
+struct LoggedGenericAckReceived {
+ LoggedGenericAckReceived() = default;
+ LoggedGenericAckReceived(Timestamp timestamp,
+ int64_t packet_number,
+ int64_t acked_packet_number,
+ absl::optional<int64_t> receive_acked_packet_time_ms)
+ : timestamp(timestamp),
+ 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.ms(); }
+ Timestamp log_time() const { return timestamp; }
+
+ Timestamp timestamp = Timestamp::MinusInfinity();
+ int64_t packet_number;
+ int64_t acked_packet_number;
+ absl::optional<int64_t> receive_acked_packet_time_ms;
+};
+
+struct AckedPacket {
+ // The packet number that was acked.
+ int64_t packet_number;
+
+ // The time where the packet was received. Not every ACK will
+ // include the receive timestamp.
+ absl::optional<int64_t> receive_acked_packet_time_ms;
+};
+
+class RtcEventGenericAckReceived final : public RtcEvent {
+ public:
+ static constexpr Type kType = Type::GenericAckReceived;
+
+ // For a collection of acked packets, it creates a vector of logs to log with
+ // the same timestamp.
+ static std::vector<std::unique_ptr<RtcEventGenericAckReceived>> CreateLogs(
+ int64_t packet_number,
+ const std::vector<AckedPacket>& acked_packets);
+
+ ~RtcEventGenericAckReceived() override;
+
+ std::unique_ptr<RtcEventGenericAckReceived> Copy() const;
+
+ Type GetType() const override { return kType; }
+ bool IsConfigEvent() const override { return false; }
+
+ // An identifier of the packet which contained an ack.
+ int64_t packet_number() const { return packet_number_; }
+
+ // An identifier of the acked packet.
+ int64_t acked_packet_number() const { return acked_packet_number_; }
+
+ // Timestamp when the `acked_packet_number` was received by the remote side.
+ absl::optional<int64_t> receive_acked_packet_time_ms() const {
+ return receive_acked_packet_time_ms_;
+ }
+
+ static std::string Encode(rtc::ArrayView<const RtcEvent*> batch) {
+ // TODO(terelius): Implement
+ return "";
+ }
+
+ static RtcEventLogParseStatus Parse(
+ absl::string_view encoded_bytes,
+ bool batched,
+ std::vector<LoggedGenericAckReceived>& output) {
+ // TODO(terelius): Implement
+ return RtcEventLogParseStatus::Error("Not Implemented", __FILE__, __LINE__);
+ }
+
+ 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_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_acked_packet_time_ms_;
+};
+
+} // namespace webrtc
+
+#endif // LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_GENERIC_ACK_RECEIVED_H_
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_generic_packet_received.cc b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_generic_packet_received.cc
new file mode 100644
index 0000000000..0bdc4dd505
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_generic_packet_received.cc
@@ -0,0 +1,32 @@
+/*
+ * 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_generic_packet_received.h"
+
+#include "absl/memory/memory.h"
+
+namespace webrtc {
+
+RtcEventGenericPacketReceived::RtcEventGenericPacketReceived(
+ int64_t packet_number,
+ 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));
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_generic_packet_received.h b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_generic_packet_received.h
new file mode 100644
index 0000000000..a6006ca4d4
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_generic_packet_received.h
@@ -0,0 +1,84 @@
+/*
+ * 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_GENERIC_PACKET_RECEIVED_H_
+#define LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_GENERIC_PACKET_RECEIVED_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/rtc_event_log/rtc_event.h"
+#include "api/units/timestamp.h"
+#include "logging/rtc_event_log/events/rtc_event_field_encoding_parser.h"
+
+namespace webrtc {
+
+struct LoggedGenericPacketReceived {
+ LoggedGenericPacketReceived() = default;
+ LoggedGenericPacketReceived(Timestamp timestamp,
+ int64_t packet_number,
+ int packet_length)
+ : timestamp(timestamp),
+ 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.ms(); }
+ Timestamp log_time() const { return timestamp; }
+
+ Timestamp timestamp = Timestamp::MinusInfinity();
+ int64_t packet_number;
+ int packet_length;
+};
+
+class RtcEventGenericPacketReceived final : public RtcEvent {
+ public:
+ static constexpr Type kType = Type::GenericPacketReceived;
+
+ RtcEventGenericPacketReceived(int64_t packet_number, size_t packet_length);
+ ~RtcEventGenericPacketReceived() override;
+
+ std::unique_ptr<RtcEventGenericPacketReceived> Copy() const;
+
+ Type GetType() const override { return kType; }
+ bool IsConfigEvent() const override { return false; }
+
+ // An identifier of the packet.
+ int64_t packet_number() const { return packet_number_; }
+
+ // Total packet length, including all packetization overheads, but not
+ // including ICE/TURN/IP overheads.
+ size_t packet_length() const { return packet_length_; }
+
+ static std::string Encode(rtc::ArrayView<const RtcEvent*> batch) {
+ // TODO(terelius): Implement
+ return "";
+ }
+
+ static RtcEventLogParseStatus Parse(
+ absl::string_view encoded_bytes,
+ bool batched,
+ std::vector<LoggedGenericPacketReceived>& output) {
+ // TODO(terelius): Implement
+ return RtcEventLogParseStatus::Error("Not Implemented", __FILE__, __LINE__);
+ }
+
+ private:
+ RtcEventGenericPacketReceived(const RtcEventGenericPacketReceived& packet);
+
+ const int64_t packet_number_;
+ const size_t packet_length_;
+};
+
+} // namespace webrtc
+
+#endif // LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_GENERIC_PACKET_RECEIVED_H_
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_generic_packet_sent.cc b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_generic_packet_sent.cc
new file mode 100644
index 0000000000..e8335624b1
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_generic_packet_sent.cc
@@ -0,0 +1,36 @@
+/*
+ * 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_generic_packet_sent.h"
+
+#include "absl/memory/memory.h"
+
+namespace webrtc {
+
+RtcEventGenericPacketSent::RtcEventGenericPacketSent(int64_t packet_number,
+ size_t overhead_length,
+ size_t payload_length,
+ size_t padding_length)
+ : packet_number_(packet_number),
+ overhead_length_(overhead_length),
+ 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));
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_generic_packet_sent.h b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_generic_packet_sent.h
new file mode 100644
index 0000000000..903950a398
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_generic_packet_sent.h
@@ -0,0 +1,110 @@
+/*
+ * 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_GENERIC_PACKET_SENT_H_
+#define LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_GENERIC_PACKET_SENT_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/rtc_event_log/rtc_event.h"
+#include "api/units/timestamp.h"
+#include "logging/rtc_event_log/events/rtc_event_field_encoding_parser.h"
+
+namespace webrtc {
+
+struct LoggedGenericPacketSent {
+ LoggedGenericPacketSent() = default;
+ LoggedGenericPacketSent(Timestamp timestamp,
+ int64_t packet_number,
+ size_t overhead_length,
+ size_t payload_length,
+ size_t padding_length)
+ : timestamp(timestamp),
+ 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.ms(); }
+ Timestamp log_time() const { return timestamp; }
+
+ size_t packet_length() const {
+ return payload_length + padding_length + overhead_length;
+ }
+ Timestamp timestamp = Timestamp::MinusInfinity();
+ int64_t packet_number;
+ size_t overhead_length;
+ size_t payload_length;
+ size_t padding_length;
+};
+
+class RtcEventGenericPacketSent final : public RtcEvent {
+ public:
+ static constexpr Type kType = Type::GenericPacketSent;
+
+ RtcEventGenericPacketSent(int64_t packet_number,
+ size_t overhead_length,
+ size_t payload_length,
+ size_t padding_length);
+ ~RtcEventGenericPacketSent() override;
+
+ std::unique_ptr<RtcEventGenericPacketSent> Copy() const;
+
+ Type GetType() const override { return kType; }
+ bool IsConfigEvent() const override { return false; }
+
+ // An identifier of the packet.
+ int64_t packet_number() const { return packet_number_; }
+
+ // Total packet length, including all packetization overheads, but not
+ // including ICE/TURN/IP overheads.
+ size_t packet_length() const {
+ return overhead_length_ + payload_length_ + padding_length_;
+ }
+
+ // The number of bytes in overhead, including framing overheads, acks if
+ // present, etc.
+ size_t overhead_length() const { return overhead_length_; }
+
+ // Length of payload sent (size of raw audio/video/data), without
+ // packetization overheads. This may still include serialization overheads.
+ size_t payload_length() const { return payload_length_; }
+
+ size_t padding_length() const { return padding_length_; }
+
+ static std::string Encode(rtc::ArrayView<const RtcEvent*> batch) {
+ // TODO(terelius): Implement
+ return "";
+ }
+
+ static RtcEventLogParseStatus Parse(
+ absl::string_view encoded_bytes,
+ bool batched,
+ std::vector<LoggedGenericPacketSent>& output) {
+ // TODO(terelius): Implement
+ return RtcEventLogParseStatus::Error("Not Implemented", __FILE__, __LINE__);
+ }
+
+ private:
+ RtcEventGenericPacketSent(const RtcEventGenericPacketSent& packet);
+
+ const int64_t packet_number_;
+ const size_t overhead_length_;
+ const size_t payload_length_;
+ const size_t padding_length_;
+};
+
+} // namespace webrtc
+
+#endif // LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_GENERIC_PACKET_SENT_H_
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_ice_candidate_pair.cc b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_ice_candidate_pair.cc
new file mode 100644
index 0000000000..2b4b5ba762
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_ice_candidate_pair.cc
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2017 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_ice_candidate_pair.h"
+
+#include "absl/memory/memory.h"
+
+namespace webrtc {
+
+RtcEventIceCandidatePair::RtcEventIceCandidatePair(
+ IceCandidatePairEventType type,
+ uint32_t candidate_pair_id,
+ uint32_t transaction_id)
+ : type_(type),
+ candidate_pair_id_(candidate_pair_id),
+ transaction_id_(transaction_id) {}
+
+RtcEventIceCandidatePair::RtcEventIceCandidatePair(
+ const RtcEventIceCandidatePair& other)
+ : RtcEvent(other.timestamp_us_),
+ type_(other.type_),
+ candidate_pair_id_(other.candidate_pair_id_),
+ transaction_id_(other.transaction_id_) {}
+
+RtcEventIceCandidatePair::~RtcEventIceCandidatePair() = default;
+
+std::unique_ptr<RtcEventIceCandidatePair> RtcEventIceCandidatePair::Copy()
+ const {
+ return absl::WrapUnique<RtcEventIceCandidatePair>(
+ new RtcEventIceCandidatePair(*this));
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_ice_candidate_pair.h b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_ice_candidate_pair.h
new file mode 100644
index 0000000000..bdacf15a59
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_ice_candidate_pair.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2017 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_ICE_CANDIDATE_PAIR_H_
+#define LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_ICE_CANDIDATE_PAIR_H_
+
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/rtc_event_log/rtc_event.h"
+#include "api/units/timestamp.h"
+#include "logging/rtc_event_log/events/rtc_event_field_encoding_parser.h"
+
+namespace webrtc {
+
+enum class IceCandidatePairEventType {
+ kCheckSent,
+ kCheckReceived,
+ kCheckResponseSent,
+ kCheckResponseReceived,
+ kNumValues,
+};
+
+struct LoggedIceCandidatePairEvent {
+ LoggedIceCandidatePairEvent() = default;
+ LoggedIceCandidatePairEvent(Timestamp timestamp,
+ IceCandidatePairEventType type,
+ uint32_t candidate_pair_id,
+ uint32_t transaction_id)
+ : timestamp(timestamp),
+ type(type),
+ candidate_pair_id(candidate_pair_id),
+ transaction_id(transaction_id) {}
+
+ int64_t log_time_us() const { return timestamp.us(); }
+ int64_t log_time_ms() const { return timestamp.ms(); }
+ Timestamp log_time() const { return timestamp; }
+
+ Timestamp timestamp = Timestamp::MinusInfinity();
+ IceCandidatePairEventType type;
+ uint32_t candidate_pair_id;
+ uint32_t transaction_id;
+};
+
+class RtcEventIceCandidatePair final : public RtcEvent {
+ public:
+ static constexpr Type kType = Type::IceCandidatePairEvent;
+
+ RtcEventIceCandidatePair(IceCandidatePairEventType type,
+ uint32_t candidate_pair_id,
+ uint32_t transaction_id);
+
+ ~RtcEventIceCandidatePair() override;
+
+ Type GetType() const override { return kType; }
+ bool IsConfigEvent() const override { return false; }
+
+ std::unique_ptr<RtcEventIceCandidatePair> Copy() const;
+
+ IceCandidatePairEventType type() const { return type_; }
+ uint32_t candidate_pair_id() const { return candidate_pair_id_; }
+ uint32_t transaction_id() const { return transaction_id_; }
+
+ static std::string Encode(rtc::ArrayView<const RtcEvent*> batch) {
+ // TODO(terelius): Implement
+ return "";
+ }
+
+ static RtcEventLogParseStatus Parse(
+ absl::string_view encoded_bytes,
+ bool batched,
+ std::vector<LoggedIceCandidatePairEvent>& output) {
+ // TODO(terelius): Implement
+ return RtcEventLogParseStatus::Error("Not Implemented", __FILE__, __LINE__);
+ }
+
+ private:
+ RtcEventIceCandidatePair(const RtcEventIceCandidatePair& other);
+
+ const IceCandidatePairEventType type_;
+ const uint32_t candidate_pair_id_;
+ const uint32_t transaction_id_;
+};
+
+} // namespace webrtc
+
+#endif // LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_ICE_CANDIDATE_PAIR_H_
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_ice_candidate_pair_config.cc b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_ice_candidate_pair_config.cc
new file mode 100644
index 0000000000..eb458c4640
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_ice_candidate_pair_config.cc
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2017 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_ice_candidate_pair_config.h"
+
+#include "absl/memory/memory.h"
+
+namespace webrtc {
+
+IceCandidatePairDescription::IceCandidatePairDescription() {
+ local_candidate_type = IceCandidateType::kUnknown;
+ local_relay_protocol = IceCandidatePairProtocol::kUnknown;
+ local_network_type = IceCandidateNetworkType::kUnknown;
+ local_address_family = IceCandidatePairAddressFamily::kUnknown;
+ remote_candidate_type = IceCandidateType::kUnknown;
+ remote_address_family = IceCandidatePairAddressFamily::kUnknown;
+ candidate_pair_protocol = IceCandidatePairProtocol::kUnknown;
+}
+
+IceCandidatePairDescription::IceCandidatePairDescription(
+ const IceCandidatePairDescription& other) {
+ local_candidate_type = other.local_candidate_type;
+ local_relay_protocol = other.local_relay_protocol;
+ local_network_type = other.local_network_type;
+ local_address_family = other.local_address_family;
+ remote_candidate_type = other.remote_candidate_type;
+ remote_address_family = other.remote_address_family;
+ candidate_pair_protocol = other.candidate_pair_protocol;
+}
+
+IceCandidatePairDescription::~IceCandidatePairDescription() {}
+
+RtcEventIceCandidatePairConfig::RtcEventIceCandidatePairConfig(
+ IceCandidatePairConfigType type,
+ uint32_t candidate_pair_id,
+ const IceCandidatePairDescription& candidate_pair_desc)
+ : type_(type),
+ candidate_pair_id_(candidate_pair_id),
+ candidate_pair_desc_(candidate_pair_desc) {}
+
+RtcEventIceCandidatePairConfig::RtcEventIceCandidatePairConfig(
+ const RtcEventIceCandidatePairConfig& other)
+ : RtcEvent(other.timestamp_us_),
+ type_(other.type_),
+ candidate_pair_id_(other.candidate_pair_id_),
+ candidate_pair_desc_(other.candidate_pair_desc_) {}
+
+RtcEventIceCandidatePairConfig::~RtcEventIceCandidatePairConfig() = default;
+
+std::unique_ptr<RtcEventIceCandidatePairConfig>
+RtcEventIceCandidatePairConfig::Copy() const {
+ return absl::WrapUnique<RtcEventIceCandidatePairConfig>(
+ new RtcEventIceCandidatePairConfig(*this));
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_ice_candidate_pair_config.h b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_ice_candidate_pair_config.h
new file mode 100644
index 0000000000..e72d999cff
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_ice_candidate_pair_config.h
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2017 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_ICE_CANDIDATE_PAIR_CONFIG_H_
+#define LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_ICE_CANDIDATE_PAIR_CONFIG_H_
+
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/rtc_event_log/rtc_event.h"
+#include "api/units/timestamp.h"
+#include "logging/rtc_event_log/events/rtc_event_field_encoding_parser.h"
+
+namespace webrtc {
+
+enum class IceCandidatePairConfigType {
+ kAdded,
+ kUpdated,
+ kDestroyed,
+ kSelected,
+ kNumValues,
+};
+
+// TODO(qingsi): Change the names of candidate types to "host", "srflx", "prflx"
+// and "relay" after the naming is spec-compliant in the signaling part
+enum class IceCandidateType {
+ kUnknown,
+ kLocal,
+ kStun,
+ kPrflx,
+ kRelay,
+ kNumValues,
+};
+
+enum class IceCandidatePairProtocol {
+ kUnknown,
+ kUdp,
+ kTcp,
+ kSsltcp,
+ kTls,
+ kNumValues,
+};
+
+enum class IceCandidatePairAddressFamily {
+ kUnknown,
+ kIpv4,
+ kIpv6,
+ kNumValues,
+};
+
+enum class IceCandidateNetworkType {
+ kUnknown,
+ kEthernet,
+ kLoopback,
+ kWifi,
+ kVpn,
+ kCellular,
+ kNumValues,
+};
+
+struct LoggedIceCandidatePairConfig {
+ int64_t log_time_us() const { return timestamp.us(); }
+ int64_t log_time_ms() const { return timestamp.ms(); }
+ Timestamp log_time() const { return timestamp; }
+
+ Timestamp timestamp = Timestamp::MinusInfinity();
+ IceCandidatePairConfigType type;
+ uint32_t candidate_pair_id;
+ IceCandidateType local_candidate_type;
+ IceCandidatePairProtocol local_relay_protocol;
+ IceCandidateNetworkType local_network_type;
+ IceCandidatePairAddressFamily local_address_family;
+ IceCandidateType remote_candidate_type;
+ IceCandidatePairAddressFamily remote_address_family;
+ IceCandidatePairProtocol candidate_pair_protocol;
+};
+
+class IceCandidatePairDescription {
+ public:
+ IceCandidatePairDescription();
+ explicit IceCandidatePairDescription(
+ const IceCandidatePairDescription& other);
+
+ ~IceCandidatePairDescription();
+
+ IceCandidateType local_candidate_type;
+ IceCandidatePairProtocol local_relay_protocol;
+ IceCandidateNetworkType local_network_type;
+ IceCandidatePairAddressFamily local_address_family;
+ IceCandidateType remote_candidate_type;
+ IceCandidatePairAddressFamily remote_address_family;
+ IceCandidatePairProtocol candidate_pair_protocol;
+};
+
+class RtcEventIceCandidatePairConfig final : public RtcEvent {
+ public:
+ static constexpr Type kType = Type::IceCandidatePairConfig;
+
+ RtcEventIceCandidatePairConfig(
+ IceCandidatePairConfigType type,
+ uint32_t candidate_pair_id,
+ const IceCandidatePairDescription& candidate_pair_desc);
+
+ ~RtcEventIceCandidatePairConfig() override;
+
+ Type GetType() const override { return kType; }
+ // N.B. An ICE config event is not considered an RtcEventLog config event.
+ bool IsConfigEvent() const override { return false; }
+
+ std::unique_ptr<RtcEventIceCandidatePairConfig> Copy() const;
+
+ IceCandidatePairConfigType type() const { return type_; }
+ uint32_t candidate_pair_id() const { return candidate_pair_id_; }
+ const IceCandidatePairDescription& candidate_pair_desc() const {
+ return candidate_pair_desc_;
+ }
+
+ static std::string Encode(rtc::ArrayView<const RtcEvent*> batch) {
+ // TODO(terelius): Implement
+ return "";
+ }
+
+ static RtcEventLogParseStatus Parse(
+ absl::string_view encoded_bytes,
+ bool batched,
+ std::vector<LoggedIceCandidatePairConfig>& output) {
+ // TODO(terelius): Implement
+ return RtcEventLogParseStatus::Error("Not Implemented", __FILE__, __LINE__);
+ }
+
+ private:
+ RtcEventIceCandidatePairConfig(const RtcEventIceCandidatePairConfig& other);
+
+ const IceCandidatePairConfigType type_;
+ const uint32_t candidate_pair_id_;
+ const IceCandidatePairDescription candidate_pair_desc_;
+};
+
+} // namespace webrtc
+
+#endif // LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_ICE_CANDIDATE_PAIR_CONFIG_H_
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_neteq_set_minimum_delay.cc b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_neteq_set_minimum_delay.cc
new file mode 100644
index 0000000000..7b958c181b
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_neteq_set_minimum_delay.cc
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2022 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_neteq_set_minimum_delay.h"
+
+#include <stdint.h>
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "api/rtc_event_log/rtc_event.h"
+#include "api/units/timestamp.h"
+#include "logging/rtc_event_log/events/rtc_event_definition.h"
+
+namespace webrtc {
+
+RtcEventNetEqSetMinimumDelay::RtcEventNetEqSetMinimumDelay(uint32_t remote_ssrc,
+ int delay_ms)
+ : remote_ssrc_(remote_ssrc), minimum_delay_ms_(delay_ms) {}
+RtcEventNetEqSetMinimumDelay::~RtcEventNetEqSetMinimumDelay() {}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_neteq_set_minimum_delay.h b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_neteq_set_minimum_delay.h
new file mode 100644
index 0000000000..2e49adb36e
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_neteq_set_minimum_delay.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2022 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_NETEQ_SET_MINIMUM_DELAY_H_
+#define LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_NETEQ_SET_MINIMUM_DELAY_H_
+
+#include <stdint.h>
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "absl/memory/memory.h"
+#include "absl/strings/string_view.h"
+#include "api/rtc_event_log/rtc_event.h"
+#include "api/units/timestamp.h"
+#include "logging/rtc_event_log/events/rtc_event_definition.h"
+
+namespace webrtc {
+
+struct LoggedNetEqSetMinimumDelayEvent {
+ LoggedNetEqSetMinimumDelayEvent() = default;
+ LoggedNetEqSetMinimumDelayEvent(Timestamp timestamp,
+ uint32_t remote_ssrc,
+ int minimum_delay_ms)
+ : timestamp(timestamp),
+ remote_ssrc(remote_ssrc),
+ minimum_delay_ms(minimum_delay_ms) {}
+
+ int64_t log_time_us() const { return timestamp.us(); }
+ int64_t log_time_ms() const { return timestamp.ms(); }
+ Timestamp log_time() const { return timestamp; }
+
+ Timestamp timestamp = Timestamp::MinusInfinity();
+ uint32_t remote_ssrc;
+ int minimum_delay_ms;
+};
+
+class RtcEventNetEqSetMinimumDelay final : public RtcEvent {
+ public:
+ static constexpr Type kType = Type::NetEqSetMinimumDelay;
+
+ explicit RtcEventNetEqSetMinimumDelay(uint32_t remote_ssrc, int delay_ms);
+ ~RtcEventNetEqSetMinimumDelay() override;
+
+ Type GetType() const override { return kType; }
+ bool IsConfigEvent() const override { return false; }
+ uint32_t remote_ssrc() const { return remote_ssrc_; }
+ int minimum_delay_ms() const { return minimum_delay_ms_; }
+
+ std::unique_ptr<RtcEventNetEqSetMinimumDelay> Copy() const {
+ return absl::WrapUnique<RtcEventNetEqSetMinimumDelay>(
+ new RtcEventNetEqSetMinimumDelay(*this));
+ }
+
+ private:
+ uint32_t remote_ssrc_;
+ int minimum_delay_ms_;
+};
+
+} // namespace webrtc
+#endif // LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_NETEQ_SET_MINIMUM_DELAY_H_
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_probe_cluster_created.cc b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_probe_cluster_created.cc
new file mode 100644
index 0000000000..c3d9e59b47
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_probe_cluster_created.cc
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2017 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_probe_cluster_created.h"
+
+#include "absl/memory/memory.h"
+
+namespace webrtc {
+
+RtcEventProbeClusterCreated::RtcEventProbeClusterCreated(int32_t id,
+ int32_t bitrate_bps,
+ uint32_t min_probes,
+ uint32_t min_bytes)
+ : id_(id),
+ bitrate_bps_(bitrate_bps),
+ min_probes_(min_probes),
+ min_bytes_(min_bytes) {}
+
+RtcEventProbeClusterCreated::RtcEventProbeClusterCreated(
+ const RtcEventProbeClusterCreated& other)
+ : RtcEvent(other.timestamp_us_),
+ id_(other.id_),
+ bitrate_bps_(other.bitrate_bps_),
+ min_probes_(other.min_probes_),
+ min_bytes_(other.min_bytes_) {}
+
+std::unique_ptr<RtcEventProbeClusterCreated> RtcEventProbeClusterCreated::Copy()
+ const {
+ return absl::WrapUnique<RtcEventProbeClusterCreated>(
+ new RtcEventProbeClusterCreated(*this));
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_probe_cluster_created.h b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_probe_cluster_created.h
new file mode 100644
index 0000000000..ae6810c39d
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_probe_cluster_created.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2017 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_PROBE_CLUSTER_CREATED_H_
+#define LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_PROBE_CLUSTER_CREATED_H_
+
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/rtc_event_log/rtc_event.h"
+#include "api/units/timestamp.h"
+#include "logging/rtc_event_log/events/rtc_event_field_encoding_parser.h"
+
+namespace webrtc {
+
+struct LoggedBweProbeClusterCreatedEvent {
+ LoggedBweProbeClusterCreatedEvent() = default;
+ LoggedBweProbeClusterCreatedEvent(Timestamp timestamp,
+ int32_t id,
+ int32_t bitrate_bps,
+ uint32_t min_packets,
+ uint32_t min_bytes)
+ : timestamp(timestamp),
+ id(id),
+ bitrate_bps(bitrate_bps),
+ min_packets(min_packets),
+ min_bytes(min_bytes) {}
+
+ int64_t log_time_us() const { return timestamp.us(); }
+ int64_t log_time_ms() const { return timestamp.ms(); }
+ Timestamp log_time() const { return timestamp; }
+
+ Timestamp timestamp = Timestamp::MinusInfinity();
+ int32_t id;
+ int32_t bitrate_bps;
+ uint32_t min_packets;
+ uint32_t min_bytes;
+};
+
+class RtcEventProbeClusterCreated final : public RtcEvent {
+ public:
+ static constexpr Type kType = Type::ProbeClusterCreated;
+
+ RtcEventProbeClusterCreated(int32_t id,
+ int32_t bitrate_bps,
+ uint32_t min_probes,
+ uint32_t min_bytes);
+ ~RtcEventProbeClusterCreated() override = default;
+
+ Type GetType() const override { return kType; }
+ bool IsConfigEvent() const override { return false; }
+
+ std::unique_ptr<RtcEventProbeClusterCreated> Copy() const;
+
+ int32_t id() const { return id_; }
+ int32_t bitrate_bps() const { return bitrate_bps_; }
+ uint32_t min_probes() const { return min_probes_; }
+ uint32_t min_bytes() const { return min_bytes_; }
+
+ static std::string Encode(rtc::ArrayView<const RtcEvent*> batch) {
+ // TODO(terelius): Implement
+ return "";
+ }
+
+ static RtcEventLogParseStatus Parse(
+ absl::string_view encoded_bytes,
+ bool batched,
+ std::vector<LoggedBweProbeClusterCreatedEvent>& output) {
+ // TODO(terelius): Implement
+ return RtcEventLogParseStatus::Error("Not Implemented", __FILE__, __LINE__);
+ }
+
+ private:
+ RtcEventProbeClusterCreated(const RtcEventProbeClusterCreated& other);
+
+ const int32_t id_;
+ const int32_t bitrate_bps_;
+ const uint32_t min_probes_;
+ const uint32_t min_bytes_;
+};
+
+} // namespace webrtc
+
+#endif // LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_PROBE_CLUSTER_CREATED_H_
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_probe_result_failure.cc b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_probe_result_failure.cc
new file mode 100644
index 0000000000..a79b0c173d
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_probe_result_failure.cc
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2017 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_probe_result_failure.h"
+
+#include "absl/memory/memory.h"
+
+namespace webrtc {
+
+RtcEventProbeResultFailure::RtcEventProbeResultFailure(
+ int32_t id,
+ ProbeFailureReason failure_reason)
+ : id_(id), failure_reason_(failure_reason) {}
+
+RtcEventProbeResultFailure::RtcEventProbeResultFailure(
+ const RtcEventProbeResultFailure& other)
+ : RtcEvent(other.timestamp_us_),
+ id_(other.id_),
+ failure_reason_(other.failure_reason_) {}
+
+std::unique_ptr<RtcEventProbeResultFailure> RtcEventProbeResultFailure::Copy()
+ const {
+ return absl::WrapUnique<RtcEventProbeResultFailure>(
+ new RtcEventProbeResultFailure(*this));
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_probe_result_failure.h b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_probe_result_failure.h
new file mode 100644
index 0000000000..1aa6e75cb7
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_probe_result_failure.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2017 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_PROBE_RESULT_FAILURE_H_
+#define LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_PROBE_RESULT_FAILURE_H_
+
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/rtc_event_log/rtc_event.h"
+#include "api/units/timestamp.h"
+#include "logging/rtc_event_log/events/rtc_event_field_encoding_parser.h"
+
+namespace webrtc {
+
+enum class ProbeFailureReason {
+ kInvalidSendReceiveInterval = 0,
+ kInvalidSendReceiveRatio,
+ kTimeout,
+ kLast
+};
+
+struct LoggedBweProbeFailureEvent {
+ LoggedBweProbeFailureEvent() = default;
+ LoggedBweProbeFailureEvent(Timestamp timestamp,
+ int32_t id,
+ ProbeFailureReason failure_reason)
+ : timestamp(timestamp), id(id), failure_reason(failure_reason) {}
+
+ int64_t log_time_us() const { return timestamp.us(); }
+ int64_t log_time_ms() const { return timestamp.ms(); }
+ Timestamp log_time() const { return timestamp; }
+
+ Timestamp timestamp = Timestamp::MinusInfinity();
+ int32_t id;
+ ProbeFailureReason failure_reason;
+};
+
+class RtcEventProbeResultFailure final : public RtcEvent {
+ public:
+ static constexpr Type kType = Type::ProbeResultFailure;
+
+ RtcEventProbeResultFailure(int32_t id, ProbeFailureReason failure_reason);
+ ~RtcEventProbeResultFailure() override = default;
+
+ Type GetType() const override { return kType; }
+ bool IsConfigEvent() const override { return false; }
+
+ std::unique_ptr<RtcEventProbeResultFailure> Copy() const;
+
+ int32_t id() const { return id_; }
+ ProbeFailureReason failure_reason() const { return failure_reason_; }
+
+ static std::string Encode(rtc::ArrayView<const RtcEvent*> batch) {
+ // TODO(terelius): Implement
+ return "";
+ }
+
+ static RtcEventLogParseStatus Parse(
+ absl::string_view encoded_bytes,
+ bool batched,
+ std::vector<LoggedBweProbeFailureEvent>& output) {
+ // TODO(terelius): Implement
+ return RtcEventLogParseStatus::Error("Not Implemented", __FILE__, __LINE__);
+ }
+
+ private:
+ RtcEventProbeResultFailure(const RtcEventProbeResultFailure& other);
+
+ const int32_t id_;
+ const ProbeFailureReason failure_reason_;
+};
+
+} // namespace webrtc
+
+#endif // LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_PROBE_RESULT_FAILURE_H_
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_probe_result_success.cc b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_probe_result_success.cc
new file mode 100644
index 0000000000..e7bc7c25da
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_probe_result_success.cc
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2017 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_probe_result_success.h"
+
+#include "absl/memory/memory.h"
+
+namespace webrtc {
+
+RtcEventProbeResultSuccess::RtcEventProbeResultSuccess(int32_t id,
+ int32_t bitrate_bps)
+ : id_(id), bitrate_bps_(bitrate_bps) {}
+
+RtcEventProbeResultSuccess::RtcEventProbeResultSuccess(
+ const RtcEventProbeResultSuccess& other)
+ : RtcEvent(other.timestamp_us_),
+ id_(other.id_),
+ bitrate_bps_(other.bitrate_bps_) {}
+
+std::unique_ptr<RtcEventProbeResultSuccess> RtcEventProbeResultSuccess::Copy()
+ const {
+ return absl::WrapUnique<RtcEventProbeResultSuccess>(
+ new RtcEventProbeResultSuccess(*this));
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_probe_result_success.h b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_probe_result_success.h
new file mode 100644
index 0000000000..49d1abec5a
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_probe_result_success.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2017 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_PROBE_RESULT_SUCCESS_H_
+#define LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_PROBE_RESULT_SUCCESS_H_
+
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/rtc_event_log/rtc_event.h"
+#include "api/units/timestamp.h"
+#include "logging/rtc_event_log/events/rtc_event_field_encoding_parser.h"
+
+namespace webrtc {
+
+struct LoggedBweProbeSuccessEvent {
+ LoggedBweProbeSuccessEvent() = default;
+ LoggedBweProbeSuccessEvent(Timestamp timestamp,
+ int32_t id,
+ int32_t bitrate_bps)
+ : timestamp(timestamp), id(id), bitrate_bps(bitrate_bps) {}
+
+ int64_t log_time_us() const { return timestamp.us(); }
+ int64_t log_time_ms() const { return timestamp.ms(); }
+ Timestamp log_time() const { return timestamp; }
+
+ Timestamp timestamp = Timestamp::MinusInfinity();
+ int32_t id;
+ int32_t bitrate_bps;
+};
+
+class RtcEventProbeResultSuccess final : public RtcEvent {
+ public:
+ static constexpr Type kType = Type::ProbeResultSuccess;
+
+ RtcEventProbeResultSuccess(int32_t id, int32_t bitrate_bps);
+ ~RtcEventProbeResultSuccess() override = default;
+
+ Type GetType() const override { return kType; }
+ bool IsConfigEvent() const override { return false; }
+
+ std::unique_ptr<RtcEventProbeResultSuccess> Copy() const;
+
+ int32_t id() const { return id_; }
+ int32_t bitrate_bps() const { return bitrate_bps_; }
+
+ static std::string Encode(rtc::ArrayView<const RtcEvent*> batch) {
+ // TODO(terelius): Implement
+ return "";
+ }
+
+ static RtcEventLogParseStatus Parse(
+ absl::string_view encoded_bytes,
+ bool batched,
+ std::vector<LoggedBweProbeSuccessEvent>& output) {
+ // TODO(terelius): Implement
+ return RtcEventLogParseStatus::Error("Not Implemented", __FILE__, __LINE__);
+ }
+
+ private:
+ RtcEventProbeResultSuccess(const RtcEventProbeResultSuccess& other);
+
+ const int32_t id_;
+ const int32_t bitrate_bps_;
+};
+
+} // namespace webrtc
+
+#endif // LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_PROBE_RESULT_SUCCESS_H_
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_remote_estimate.h b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_remote_estimate.h
new file mode 100644
index 0000000000..4a39ecc597
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_remote_estimate.h
@@ -0,0 +1,68 @@
+/*
+ * 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_REMOTE_ESTIMATE_H_
+#define LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_REMOTE_ESTIMATE_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "absl/types/optional.h"
+#include "api/rtc_event_log/rtc_event.h"
+#include "api/units/data_rate.h"
+#include "api/units/timestamp.h"
+#include "logging/rtc_event_log/events/rtc_event_field_encoding_parser.h"
+
+namespace webrtc {
+
+struct LoggedRemoteEstimateEvent {
+ LoggedRemoteEstimateEvent() = default;
+
+ int64_t log_time_us() const { return timestamp.us(); }
+ int64_t log_time_ms() const { return timestamp.ms(); }
+ Timestamp log_time() const { return timestamp; }
+
+ Timestamp timestamp = Timestamp::MinusInfinity();
+ absl::optional<DataRate> link_capacity_lower;
+ absl::optional<DataRate> link_capacity_upper;
+};
+
+class RtcEventRemoteEstimate final : public RtcEvent {
+ public:
+ static constexpr Type kType = Type::RemoteEstimateEvent;
+
+ RtcEventRemoteEstimate(DataRate link_capacity_lower,
+ DataRate link_capacity_upper)
+ : link_capacity_lower_(link_capacity_lower),
+ link_capacity_upper_(link_capacity_upper) {}
+
+ Type GetType() const override { return kType; }
+ bool IsConfigEvent() const override { return false; }
+
+ static std::string Encode(rtc::ArrayView<const RtcEvent*> batch) {
+ // TODO(terelius): Implement
+ return "";
+ }
+
+ static RtcEventLogParseStatus Parse(
+ absl::string_view encoded_bytes,
+ bool batched,
+ std::vector<LoggedRemoteEstimateEvent>& output) {
+ // TODO(terelius): Implement
+ return RtcEventLogParseStatus::Error("Not Implemented", __FILE__, __LINE__);
+ }
+
+ const DataRate link_capacity_lower_;
+ const DataRate link_capacity_upper_;
+};
+
+} // namespace webrtc
+#endif // LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_REMOTE_ESTIMATE_H_
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_route_change.cc b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_route_change.cc
new file mode 100644
index 0000000000..71bd78b346
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_route_change.cc
@@ -0,0 +1,31 @@
+/*
+ * 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;
+
+std::unique_ptr<RtcEventRouteChange> RtcEventRouteChange::Copy() const {
+ return absl::WrapUnique<RtcEventRouteChange>(new RtcEventRouteChange(*this));
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_route_change.h b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_route_change.h
new file mode 100644
index 0000000000..bc1461d7bb
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_route_change.h
@@ -0,0 +1,75 @@
+/*
+ * 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 <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/rtc_event_log/rtc_event.h"
+#include "api/units/timestamp.h"
+#include "logging/rtc_event_log/events/rtc_event_field_encoding_parser.h"
+
+namespace webrtc {
+
+struct LoggedRouteChangeEvent {
+ LoggedRouteChangeEvent() = default;
+ LoggedRouteChangeEvent(Timestamp timestamp, bool connected, uint32_t overhead)
+ : timestamp(timestamp), connected(connected), overhead(overhead) {}
+
+ int64_t log_time_us() const { return timestamp.us(); }
+ int64_t log_time_ms() const { return timestamp.ms(); }
+ Timestamp log_time() const { return timestamp; }
+
+ Timestamp timestamp = Timestamp::MinusInfinity();
+ bool connected;
+ uint32_t overhead;
+};
+
+class RtcEventRouteChange final : public RtcEvent {
+ public:
+ static constexpr Type kType = Type::RouteChangeEvent;
+
+ RtcEventRouteChange(bool connected, uint32_t overhead);
+ ~RtcEventRouteChange() override;
+
+ Type GetType() const override { return kType; }
+ bool IsConfigEvent() const override { return false; }
+
+ std::unique_ptr<RtcEventRouteChange> Copy() const;
+
+ bool connected() const { return connected_; }
+ uint32_t overhead() const { return overhead_; }
+
+ static std::string Encode(rtc::ArrayView<const RtcEvent*> batch) {
+ // TODO(terelius): Implement
+ return "";
+ }
+
+ static RtcEventLogParseStatus Parse(
+ absl::string_view encoded_bytes,
+ bool batched,
+ std::vector<LoggedRouteChangeEvent>& output) {
+ // TODO(terelius): Implement
+ return RtcEventLogParseStatus::Error("Not Implemented", __FILE__, __LINE__);
+ }
+
+ 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/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_rtcp_packet_incoming.cc b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_rtcp_packet_incoming.cc
new file mode 100644
index 0000000000..0ea700a024
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_rtcp_packet_incoming.cc
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2017 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_rtcp_packet_incoming.h"
+
+#include "absl/memory/memory.h"
+
+namespace webrtc {
+
+RtcEventRtcpPacketIncoming::RtcEventRtcpPacketIncoming(
+ rtc::ArrayView<const uint8_t> packet)
+ : packet_(packet.data(), packet.size()) {}
+
+RtcEventRtcpPacketIncoming::RtcEventRtcpPacketIncoming(
+ const RtcEventRtcpPacketIncoming& other)
+ : RtcEvent(other.timestamp_us_),
+ packet_(other.packet_.data(), other.packet_.size()) {}
+
+RtcEventRtcpPacketIncoming::~RtcEventRtcpPacketIncoming() = default;
+
+std::unique_ptr<RtcEventRtcpPacketIncoming> RtcEventRtcpPacketIncoming::Copy()
+ const {
+ return absl::WrapUnique<RtcEventRtcpPacketIncoming>(
+ new RtcEventRtcpPacketIncoming(*this));
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_rtcp_packet_incoming.h b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_rtcp_packet_incoming.h
new file mode 100644
index 0000000000..84fe398e08
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_rtcp_packet_incoming.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2017 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_RTCP_PACKET_INCOMING_H_
+#define LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_RTCP_PACKET_INCOMING_H_
+
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/array_view.h"
+#include "api/rtc_event_log/rtc_event.h"
+#include "logging/rtc_event_log/events/logged_rtp_rtcp.h"
+#include "logging/rtc_event_log/events/rtc_event_field_encoding_parser.h"
+#include "rtc_base/buffer.h"
+
+namespace webrtc {
+
+class RtcEventRtcpPacketIncoming final : public RtcEvent {
+ public:
+ static constexpr Type kType = Type::RtcpPacketIncoming;
+
+ explicit RtcEventRtcpPacketIncoming(rtc::ArrayView<const uint8_t> packet);
+ ~RtcEventRtcpPacketIncoming() override;
+
+ Type GetType() const override { return kType; }
+ bool IsConfigEvent() const override { return false; }
+
+ std::unique_ptr<RtcEventRtcpPacketIncoming> Copy() const;
+
+ const rtc::Buffer& packet() const { return packet_; }
+
+ static std::string Encode(rtc::ArrayView<const RtcEvent*> batch) {
+ // TODO(terelius): Implement
+ return "";
+ }
+
+ static RtcEventLogParseStatus Parse(
+ absl::string_view encoded_bytes,
+ bool batched,
+ std::vector<LoggedRtcpPacketIncoming>& output) {
+ // TODO(terelius): Implement
+ return RtcEventLogParseStatus::Error("Not Implemented", __FILE__, __LINE__);
+ }
+
+ private:
+ RtcEventRtcpPacketIncoming(const RtcEventRtcpPacketIncoming& other);
+
+ rtc::Buffer packet_;
+};
+
+} // namespace webrtc
+
+#endif // LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_RTCP_PACKET_INCOMING_H_
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_rtcp_packet_outgoing.cc b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_rtcp_packet_outgoing.cc
new file mode 100644
index 0000000000..b6a41ac034
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_rtcp_packet_outgoing.cc
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2017 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_rtcp_packet_outgoing.h"
+
+#include "absl/memory/memory.h"
+
+namespace webrtc {
+
+RtcEventRtcpPacketOutgoing::RtcEventRtcpPacketOutgoing(
+ rtc::ArrayView<const uint8_t> packet)
+ : packet_(packet.data(), packet.size()) {}
+
+RtcEventRtcpPacketOutgoing::RtcEventRtcpPacketOutgoing(
+ const RtcEventRtcpPacketOutgoing& other)
+ : RtcEvent(other.timestamp_us_),
+ packet_(other.packet_.data(), other.packet_.size()) {}
+
+RtcEventRtcpPacketOutgoing::~RtcEventRtcpPacketOutgoing() = default;
+
+std::unique_ptr<RtcEventRtcpPacketOutgoing> RtcEventRtcpPacketOutgoing::Copy()
+ const {
+ return absl::WrapUnique<RtcEventRtcpPacketOutgoing>(
+ new RtcEventRtcpPacketOutgoing(*this));
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_rtcp_packet_outgoing.h b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_rtcp_packet_outgoing.h
new file mode 100644
index 0000000000..687bd319b4
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_rtcp_packet_outgoing.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2017 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_RTCP_PACKET_OUTGOING_H_
+#define LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_RTCP_PACKET_OUTGOING_H_
+
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/array_view.h"
+#include "api/rtc_event_log/rtc_event.h"
+#include "logging/rtc_event_log/events/logged_rtp_rtcp.h"
+#include "logging/rtc_event_log/events/rtc_event_field_encoding_parser.h"
+#include "rtc_base/buffer.h"
+
+namespace webrtc {
+
+class RtcEventRtcpPacketOutgoing final : public RtcEvent {
+ public:
+ static constexpr Type kType = Type::RtcpPacketOutgoing;
+
+ explicit RtcEventRtcpPacketOutgoing(rtc::ArrayView<const uint8_t> packet);
+ ~RtcEventRtcpPacketOutgoing() override;
+
+ Type GetType() const override { return kType; }
+ bool IsConfigEvent() const override { return false; }
+
+ std::unique_ptr<RtcEventRtcpPacketOutgoing> Copy() const;
+
+ const rtc::Buffer& packet() const { return packet_; }
+
+ static std::string Encode(rtc::ArrayView<const RtcEvent*> batch) {
+ // TODO(terelius): Implement
+ return "";
+ }
+
+ static RtcEventLogParseStatus Parse(
+ absl::string_view encoded_bytes,
+ bool batched,
+ std::vector<LoggedRtcpPacketOutgoing>& output) {
+ // TODO(terelius): Implement
+ return RtcEventLogParseStatus::Error("Not Implemented", __FILE__, __LINE__);
+ }
+
+ private:
+ RtcEventRtcpPacketOutgoing(const RtcEventRtcpPacketOutgoing& other);
+
+ rtc::Buffer packet_;
+};
+
+} // namespace webrtc
+
+#endif // LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_RTCP_PACKET_OUTGOING_H_
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_rtp_packet_incoming.cc b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_rtp_packet_incoming.cc
new file mode 100644
index 0000000000..4cf33a238f
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_rtp_packet_incoming.cc
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2017 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_rtp_packet_incoming.h"
+
+#include "absl/memory/memory.h"
+#include "modules/rtp_rtcp/source/rtp_packet_received.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+RtcEventRtpPacketIncoming::RtcEventRtpPacketIncoming(
+ const RtpPacketReceived& packet)
+ : packet_(packet) {}
+
+RtcEventRtpPacketIncoming::RtcEventRtpPacketIncoming(
+ const RtcEventRtpPacketIncoming& other)
+ : RtcEvent(other.timestamp_us_), packet_(other.packet_) {}
+
+RtcEventRtpPacketIncoming::~RtcEventRtpPacketIncoming() = default;
+
+std::unique_ptr<RtcEventRtpPacketIncoming> RtcEventRtpPacketIncoming::Copy()
+ const {
+ return absl::WrapUnique<RtcEventRtpPacketIncoming>(
+ new RtcEventRtpPacketIncoming(*this));
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_rtp_packet_incoming.h b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_rtp_packet_incoming.h
new file mode 100644
index 0000000000..926ddddff5
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_rtp_packet_incoming.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2017 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_RTP_PACKET_INCOMING_H_
+#define LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_RTP_PACKET_INCOMING_H_
+
+#include <cstddef>
+#include <cstdint>
+#include <map>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/array_view.h"
+#include "api/rtc_event_log/rtc_event.h"
+#include "logging/rtc_event_log/events/logged_rtp_rtcp.h"
+#include "logging/rtc_event_log/events/rtc_event_field_encoding_parser.h"
+#include "modules/rtp_rtcp/source/rtp_packet.h"
+
+namespace webrtc {
+
+class RtpPacketReceived;
+
+class RtcEventRtpPacketIncoming final : public RtcEvent {
+ public:
+ static constexpr Type kType = Type::RtpPacketIncoming;
+
+ explicit RtcEventRtpPacketIncoming(const RtpPacketReceived& packet);
+ ~RtcEventRtpPacketIncoming() override;
+
+ Type GetType() const override { return kType; }
+ bool IsConfigEvent() const override { return false; }
+
+ std::unique_ptr<RtcEventRtpPacketIncoming> Copy() const;
+
+ size_t packet_length() const { return packet_.size(); }
+
+ rtc::ArrayView<const uint8_t> RawHeader() const {
+ return rtc::MakeArrayView(packet_.data(), header_length());
+ }
+ uint32_t Ssrc() const { return packet_.Ssrc(); }
+ uint32_t Timestamp() const { return packet_.Timestamp(); }
+ uint16_t SequenceNumber() const { return packet_.SequenceNumber(); }
+ uint8_t PayloadType() const { return packet_.PayloadType(); }
+ bool Marker() const { return packet_.Marker(); }
+ template <typename ExtensionTrait, typename... Args>
+ bool GetExtension(Args&&... args) const {
+ return packet_.GetExtension<ExtensionTrait>(std::forward<Args>(args)...);
+ }
+ template <typename ExtensionTrait>
+ bool HasExtension() const {
+ return packet_.HasExtension<ExtensionTrait>();
+ }
+
+ size_t payload_length() const { return packet_.payload_size(); }
+ size_t header_length() const { return packet_.headers_size(); }
+ size_t padding_length() const { return packet_.padding_size(); }
+
+ static std::string Encode(rtc::ArrayView<const RtcEvent*> batch) {
+ // TODO(terelius): Implement
+ return "";
+ }
+
+ static RtcEventLogParseStatus Parse(
+ absl::string_view encoded_bytes,
+ bool batched,
+ std::map<uint32_t, std::vector<LoggedRtpPacketIncoming>>& output) {
+ // TODO(terelius): Implement
+ return RtcEventLogParseStatus::Error("Not Implemented", __FILE__, __LINE__);
+ }
+
+ private:
+ RtcEventRtpPacketIncoming(const RtcEventRtpPacketIncoming& other);
+
+ const RtpPacket packet_;
+};
+
+} // namespace webrtc
+
+#endif // LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_RTP_PACKET_INCOMING_H_
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_rtp_packet_outgoing.cc b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_rtp_packet_outgoing.cc
new file mode 100644
index 0000000000..a6a4d99702
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_rtp_packet_outgoing.cc
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2017 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_rtp_packet_outgoing.h"
+
+#include "absl/memory/memory.h"
+#include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+RtcEventRtpPacketOutgoing::RtcEventRtpPacketOutgoing(
+ const RtpPacketToSend& packet,
+ int probe_cluster_id)
+ : packet_(packet), probe_cluster_id_(probe_cluster_id) {}
+
+RtcEventRtpPacketOutgoing::RtcEventRtpPacketOutgoing(
+ const RtcEventRtpPacketOutgoing& other)
+ : RtcEvent(other.timestamp_us_),
+ packet_(other.packet_),
+ probe_cluster_id_(other.probe_cluster_id_) {}
+
+RtcEventRtpPacketOutgoing::~RtcEventRtpPacketOutgoing() = default;
+
+std::unique_ptr<RtcEventRtpPacketOutgoing> RtcEventRtpPacketOutgoing::Copy()
+ const {
+ return absl::WrapUnique<RtcEventRtpPacketOutgoing>(
+ new RtcEventRtpPacketOutgoing(*this));
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_rtp_packet_outgoing.h b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_rtp_packet_outgoing.h
new file mode 100644
index 0000000000..c7b7a09718
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_rtp_packet_outgoing.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2017 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_RTP_PACKET_OUTGOING_H_
+#define LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_RTP_PACKET_OUTGOING_H_
+
+#include <cstddef>
+#include <cstdint>
+#include <map>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/array_view.h"
+#include "api/rtc_event_log/rtc_event.h"
+#include "logging/rtc_event_log/events/logged_rtp_rtcp.h"
+#include "logging/rtc_event_log/events/rtc_event_field_encoding_parser.h"
+#include "modules/rtp_rtcp/source/rtp_packet.h"
+
+namespace webrtc {
+
+class RtpPacketToSend;
+
+class RtcEventRtpPacketOutgoing final : public RtcEvent {
+ public:
+ static constexpr Type kType = Type::RtpPacketOutgoing;
+
+ RtcEventRtpPacketOutgoing(const RtpPacketToSend& packet,
+ int probe_cluster_id);
+ ~RtcEventRtpPacketOutgoing() override;
+
+ Type GetType() const override { return kType; }
+ bool IsConfigEvent() const override { return false; }
+
+ std::unique_ptr<RtcEventRtpPacketOutgoing> Copy() const;
+
+ size_t packet_length() const { return packet_.size(); }
+
+ rtc::ArrayView<const uint8_t> RawHeader() const {
+ return rtc::MakeArrayView(packet_.data(), header_length());
+ }
+ uint32_t Ssrc() const { return packet_.Ssrc(); }
+ uint32_t Timestamp() const { return packet_.Timestamp(); }
+ uint16_t SequenceNumber() const { return packet_.SequenceNumber(); }
+ uint8_t PayloadType() const { return packet_.PayloadType(); }
+ bool Marker() const { return packet_.Marker(); }
+ template <typename ExtensionTrait, typename... Args>
+ bool GetExtension(Args&&... args) const {
+ return packet_.GetExtension<ExtensionTrait>(std::forward<Args>(args)...);
+ }
+ template <typename ExtensionTrait>
+ bool HasExtension() const {
+ return packet_.HasExtension<ExtensionTrait>();
+ }
+
+ size_t payload_length() const { return packet_.payload_size(); }
+ size_t header_length() const { return packet_.headers_size(); }
+ size_t padding_length() const { return packet_.padding_size(); }
+ int probe_cluster_id() const { return probe_cluster_id_; }
+
+ static std::string Encode(rtc::ArrayView<const RtcEvent*> batch) {
+ // TODO(terelius): Implement
+ return "";
+ }
+
+ static RtcEventLogParseStatus Parse(
+ absl::string_view encoded_bytes,
+ bool batched,
+ std::map<uint32_t, std::vector<LoggedRtpPacketOutgoing>>& output) {
+ // TODO(terelius): Implement
+ return RtcEventLogParseStatus::Error("Not Implemented", __FILE__, __LINE__);
+ }
+
+ private:
+ RtcEventRtpPacketOutgoing(const RtcEventRtpPacketOutgoing& other);
+
+ const RtpPacket packet_;
+ // TODO(eladalon): Delete `probe_cluster_id_` along with legacy encoding.
+ const int probe_cluster_id_;
+};
+
+} // namespace webrtc
+
+#endif // LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_RTP_PACKET_OUTGOING_H_
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_video_receive_stream_config.cc b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_video_receive_stream_config.cc
new file mode 100644
index 0000000000..90ab8185a3
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_video_receive_stream_config.cc
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2017 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_video_receive_stream_config.h"
+
+#include <utility>
+
+#include "absl/memory/memory.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+RtcEventVideoReceiveStreamConfig::RtcEventVideoReceiveStreamConfig(
+ std::unique_ptr<rtclog::StreamConfig> config)
+ : config_(std::move(config)) {
+ RTC_DCHECK(config_);
+}
+
+RtcEventVideoReceiveStreamConfig::RtcEventVideoReceiveStreamConfig(
+ const RtcEventVideoReceiveStreamConfig& other)
+ : RtcEvent(other.timestamp_us_),
+ config_(std::make_unique<rtclog::StreamConfig>(*other.config_)) {}
+
+RtcEventVideoReceiveStreamConfig::~RtcEventVideoReceiveStreamConfig() = default;
+
+std::unique_ptr<RtcEventVideoReceiveStreamConfig>
+RtcEventVideoReceiveStreamConfig::Copy() const {
+ return absl::WrapUnique<RtcEventVideoReceiveStreamConfig>(
+ new RtcEventVideoReceiveStreamConfig(*this));
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_video_receive_stream_config.h b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_video_receive_stream_config.h
new file mode 100644
index 0000000000..0be56c2065
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_video_receive_stream_config.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2017 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_VIDEO_RECEIVE_STREAM_CONFIG_H_
+#define LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_VIDEO_RECEIVE_STREAM_CONFIG_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/rtc_event_log/rtc_event.h"
+#include "api/units/timestamp.h"
+#include "logging/rtc_event_log/events/rtc_event_field_encoding_parser.h"
+#include "logging/rtc_event_log/rtc_stream_config.h"
+
+namespace webrtc {
+
+struct LoggedVideoRecvConfig {
+ LoggedVideoRecvConfig() = default;
+ LoggedVideoRecvConfig(Timestamp timestamp, const rtclog::StreamConfig config)
+ : timestamp(timestamp), config(config) {}
+
+ int64_t log_time_us() const { return timestamp.us(); }
+ int64_t log_time_ms() const { return timestamp.ms(); }
+ Timestamp log_time() const { return timestamp; }
+
+ Timestamp timestamp = Timestamp::MinusInfinity();
+ rtclog::StreamConfig config;
+};
+
+class RtcEventVideoReceiveStreamConfig final : public RtcEvent {
+ public:
+ static constexpr Type kType = Type::VideoReceiveStreamConfig;
+
+ explicit RtcEventVideoReceiveStreamConfig(
+ std::unique_ptr<rtclog::StreamConfig> config);
+ ~RtcEventVideoReceiveStreamConfig() override;
+
+ Type GetType() const override { return kType; }
+ bool IsConfigEvent() const override { return true; }
+
+ std::unique_ptr<RtcEventVideoReceiveStreamConfig> Copy() const;
+
+ const rtclog::StreamConfig& config() const { return *config_; }
+
+ static std::string Encode(rtc::ArrayView<const RtcEvent*> batch) {
+ // TODO(terelius): Implement
+ return "";
+ }
+
+ static RtcEventLogParseStatus Parse(
+ absl::string_view encoded_bytes,
+ bool batched,
+ std::vector<LoggedVideoRecvConfig>& output) {
+ // TODO(terelius): Implement
+ return RtcEventLogParseStatus::Error("Not Implemented", __FILE__, __LINE__);
+ }
+
+ private:
+ RtcEventVideoReceiveStreamConfig(
+ const RtcEventVideoReceiveStreamConfig& other);
+
+ const std::unique_ptr<const rtclog::StreamConfig> config_;
+};
+
+} // namespace webrtc
+
+#endif // LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_VIDEO_RECEIVE_STREAM_CONFIG_H_
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_video_send_stream_config.cc b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_video_send_stream_config.cc
new file mode 100644
index 0000000000..c28a476d01
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_video_send_stream_config.cc
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2017 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_video_send_stream_config.h"
+
+#include <utility>
+
+#include "absl/memory/memory.h"
+
+namespace webrtc {
+
+RtcEventVideoSendStreamConfig::RtcEventVideoSendStreamConfig(
+ std::unique_ptr<rtclog::StreamConfig> config)
+ : config_(std::move(config)) {}
+
+RtcEventVideoSendStreamConfig::RtcEventVideoSendStreamConfig(
+ const RtcEventVideoSendStreamConfig& other)
+ : RtcEvent(other.timestamp_us_),
+ config_(std::make_unique<rtclog::StreamConfig>(*other.config_)) {}
+
+RtcEventVideoSendStreamConfig::~RtcEventVideoSendStreamConfig() = default;
+
+std::unique_ptr<RtcEventVideoSendStreamConfig>
+RtcEventVideoSendStreamConfig::Copy() const {
+ return absl::WrapUnique<RtcEventVideoSendStreamConfig>(
+ new RtcEventVideoSendStreamConfig(*this));
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_video_send_stream_config.h b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_video_send_stream_config.h
new file mode 100644
index 0000000000..f1717b19ea
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_video_send_stream_config.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2017 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_VIDEO_SEND_STREAM_CONFIG_H_
+#define LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_VIDEO_SEND_STREAM_CONFIG_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/rtc_event_log/rtc_event.h"
+#include "api/units/timestamp.h"
+#include "logging/rtc_event_log/events/rtc_event_field_encoding_parser.h"
+#include "logging/rtc_event_log/rtc_stream_config.h"
+
+namespace webrtc {
+
+struct LoggedVideoSendConfig {
+ LoggedVideoSendConfig() = default;
+ LoggedVideoSendConfig(Timestamp timestamp, const rtclog::StreamConfig config)
+ : timestamp(timestamp), config(config) {}
+
+ int64_t log_time_us() const { return timestamp.us(); }
+ int64_t log_time_ms() const { return timestamp.ms(); }
+ Timestamp log_time() const { return timestamp; }
+
+ Timestamp timestamp = Timestamp::MinusInfinity();
+ rtclog::StreamConfig config;
+};
+
+class RtcEventVideoSendStreamConfig final : public RtcEvent {
+ public:
+ static constexpr Type kType = Type::VideoSendStreamConfig;
+
+ explicit RtcEventVideoSendStreamConfig(
+ std::unique_ptr<rtclog::StreamConfig> config);
+ ~RtcEventVideoSendStreamConfig() override;
+
+ Type GetType() const override { return kType; }
+ bool IsConfigEvent() const override { return true; }
+
+ std::unique_ptr<RtcEventVideoSendStreamConfig> Copy() const;
+
+ const rtclog::StreamConfig& config() const { return *config_; }
+
+ static std::string Encode(rtc::ArrayView<const RtcEvent*> batch) {
+ // TODO(terelius): Implement
+ return "";
+ }
+
+ static RtcEventLogParseStatus Parse(
+ absl::string_view encoded_bytes,
+ bool batched,
+ std::vector<LoggedVideoSendConfig>& output) {
+ // TODO(terelius): Implement
+ return RtcEventLogParseStatus::Error("Not Implemented", __FILE__, __LINE__);
+ }
+
+ private:
+ RtcEventVideoSendStreamConfig(const RtcEventVideoSendStreamConfig& other);
+
+ const std::unique_ptr<const rtclog::StreamConfig> config_;
+};
+
+} // namespace webrtc
+
+#endif // LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_VIDEO_SEND_STREAM_CONFIG_H_
diff --git a/third_party/libwebrtc/logging/rtc_event_log/fake_rtc_event_log.cc b/third_party/libwebrtc/logging/rtc_event_log/fake_rtc_event_log.cc
new file mode 100644
index 0000000000..5a44b00694
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/fake_rtc_event_log.cc
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2018 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/fake_rtc_event_log.h"
+
+#include <map>
+#include <memory>
+
+#include "api/rtc_event_log/rtc_event_log.h"
+#include "rtc_base/synchronization/mutex.h"
+
+namespace webrtc {
+
+bool FakeRtcEventLog::StartLogging(std::unique_ptr<RtcEventLogOutput> output,
+ int64_t output_period_ms) {
+ return true;
+}
+
+void FakeRtcEventLog::StopLogging() {}
+
+void FakeRtcEventLog::Log(std::unique_ptr<RtcEvent> event) {
+ MutexLock lock(&mu_);
+ ++count_[event->GetType()];
+}
+
+int FakeRtcEventLog::GetEventCount(RtcEvent::Type event_type) {
+ MutexLock lock(&mu_);
+ return count_[event_type];
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/logging/rtc_event_log/fake_rtc_event_log.h b/third_party/libwebrtc/logging/rtc_event_log/fake_rtc_event_log.h
new file mode 100644
index 0000000000..effa7507f1
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/fake_rtc_event_log.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2018 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_FAKE_RTC_EVENT_LOG_H_
+#define LOGGING_RTC_EVENT_LOG_FAKE_RTC_EVENT_LOG_H_
+
+#include <map>
+#include <memory>
+
+#include "api/rtc_event_log/rtc_event.h"
+#include "api/rtc_event_log/rtc_event_log.h"
+#include "rtc_base/synchronization/mutex.h"
+#include "rtc_base/thread_annotations.h"
+
+namespace webrtc {
+
+class FakeRtcEventLog : public RtcEventLog {
+ public:
+ FakeRtcEventLog() = default;
+ ~FakeRtcEventLog() override = default;
+
+ bool StartLogging(std::unique_ptr<RtcEventLogOutput> output,
+ int64_t output_period_ms) override;
+ void StopLogging() override;
+ void Log(std::unique_ptr<RtcEvent> event) override;
+ int GetEventCount(RtcEvent::Type event_type);
+
+ private:
+ Mutex mu_;
+ std::map<RtcEvent::Type, int> count_ RTC_GUARDED_BY(mu_);
+};
+
+} // namespace webrtc
+
+#endif // LOGGING_RTC_EVENT_LOG_FAKE_RTC_EVENT_LOG_H_
diff --git a/third_party/libwebrtc/logging/rtc_event_log/fake_rtc_event_log_factory.cc b/third_party/libwebrtc/logging/rtc_event_log/fake_rtc_event_log_factory.cc
new file mode 100644
index 0000000000..47db40c9f4
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/fake_rtc_event_log_factory.cc
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2018 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/fake_rtc_event_log_factory.h"
+
+#include <memory>
+
+#include "api/rtc_event_log/rtc_event_log.h"
+#include "logging/rtc_event_log/fake_rtc_event_log.h"
+
+namespace webrtc {
+
+std::unique_ptr<RtcEventLog> FakeRtcEventLogFactory::Create(
+ RtcEventLog::EncodingType /*encoding_type*/) const {
+ auto fake_event_log = std::make_unique<FakeRtcEventLog>();
+ const_cast<FakeRtcEventLogFactory*>(this)->last_log_created_ =
+ fake_event_log.get();
+ return fake_event_log;
+}
+
+std::unique_ptr<RtcEventLog> FakeRtcEventLogFactory::CreateRtcEventLog(
+ RtcEventLog::EncodingType encoding_type) {
+ return Create(encoding_type);
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/logging/rtc_event_log/fake_rtc_event_log_factory.h b/third_party/libwebrtc/logging/rtc_event_log/fake_rtc_event_log_factory.h
new file mode 100644
index 0000000000..c7ff33dee4
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/fake_rtc_event_log_factory.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2018 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_FAKE_RTC_EVENT_LOG_FACTORY_H_
+#define LOGGING_RTC_EVENT_LOG_FAKE_RTC_EVENT_LOG_FACTORY_H_
+
+#include <memory>
+
+#include "api/rtc_event_log/rtc_event_log_factory_interface.h"
+#include "logging/rtc_event_log/fake_rtc_event_log.h"
+
+namespace webrtc {
+
+class FakeRtcEventLogFactory : public RtcEventLogFactoryInterface {
+ public:
+ FakeRtcEventLogFactory() = default;
+ ~FakeRtcEventLogFactory() override = default;
+
+ std::unique_ptr<RtcEventLog> Create(
+ RtcEventLog::EncodingType encoding_type) const override;
+
+ std::unique_ptr<RtcEventLog> CreateRtcEventLog(
+ RtcEventLog::EncodingType encoding_type) override;
+
+ webrtc::FakeRtcEventLog* last_log_created() { return last_log_created_; }
+
+ private:
+ webrtc::FakeRtcEventLog* last_log_created_;
+};
+
+} // namespace webrtc
+
+#endif // LOGGING_RTC_EVENT_LOG_FAKE_RTC_EVENT_LOG_FACTORY_H_
diff --git a/third_party/libwebrtc/logging/rtc_event_log/ice_logger.cc b/third_party/libwebrtc/logging/rtc_event_log/ice_logger.cc
new file mode 100644
index 0000000000..390deda953
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/ice_logger.cc
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2017 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/ice_logger.h"
+
+#include <memory>
+
+#include "api/rtc_event_log/rtc_event_log.h"
+
+namespace webrtc {
+
+IceEventLog::IceEventLog() {}
+IceEventLog::~IceEventLog() {}
+
+void IceEventLog::LogCandidatePairConfig(
+ IceCandidatePairConfigType type,
+ uint32_t candidate_pair_id,
+ const IceCandidatePairDescription& candidate_pair_desc) {
+ if (event_log_ == nullptr) {
+ return;
+ }
+ candidate_pair_desc_by_id_[candidate_pair_id] = candidate_pair_desc;
+ event_log_->Log(std::make_unique<RtcEventIceCandidatePairConfig>(
+ type, candidate_pair_id, candidate_pair_desc));
+}
+
+void IceEventLog::LogCandidatePairEvent(IceCandidatePairEventType type,
+ uint32_t candidate_pair_id,
+ uint32_t transaction_id) {
+ if (event_log_ == nullptr) {
+ return;
+ }
+ event_log_->Log(std::make_unique<RtcEventIceCandidatePair>(
+ type, candidate_pair_id, transaction_id));
+}
+
+void IceEventLog::DumpCandidatePairDescriptionToMemoryAsConfigEvents() const {
+ for (const auto& desc_id_pair : candidate_pair_desc_by_id_) {
+ event_log_->Log(std::make_unique<RtcEventIceCandidatePairConfig>(
+ IceCandidatePairConfigType::kUpdated, desc_id_pair.first,
+ desc_id_pair.second));
+ }
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/logging/rtc_event_log/ice_logger.h b/third_party/libwebrtc/logging/rtc_event_log/ice_logger.h
new file mode 100644
index 0000000000..0dea43bf9d
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/ice_logger.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2017 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_ICE_LOGGER_H_
+#define LOGGING_RTC_EVENT_LOG_ICE_LOGGER_H_
+
+#include <unordered_map>
+
+#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"
+
+namespace webrtc {
+
+class RtcEventLog;
+
+// IceEventLog wraps RtcEventLog and provides structural logging of ICE-specific
+// events. The logged events are serialized with other RtcEvent's if protobuf is
+// enabled in the build.
+class IceEventLog {
+ public:
+ IceEventLog();
+ ~IceEventLog();
+
+ void set_event_log(RtcEventLog* event_log) { event_log_ = event_log; }
+
+ void LogCandidatePairConfig(
+ IceCandidatePairConfigType type,
+ uint32_t candidate_pair_id,
+ const IceCandidatePairDescription& candidate_pair_desc);
+
+ void LogCandidatePairEvent(IceCandidatePairEventType type,
+ uint32_t candidate_pair_id,
+ uint32_t transaction_id);
+
+ // This method constructs a config event for each candidate pair with their
+ // description and logs these config events. It is intended to be called when
+ // logging starts to ensure that we have at least one config for each
+ // candidate pair id.
+ void DumpCandidatePairDescriptionToMemoryAsConfigEvents() const;
+
+ private:
+ RtcEventLog* event_log_ = nullptr;
+ std::unordered_map<uint32_t, IceCandidatePairDescription>
+ candidate_pair_desc_by_id_;
+};
+
+} // namespace webrtc
+
+#endif // LOGGING_RTC_EVENT_LOG_ICE_LOGGER_H_
diff --git a/third_party/libwebrtc/logging/rtc_event_log/logged_events.h b/third_party/libwebrtc/logging/rtc_event_log/logged_events.h
new file mode 100644
index 0000000000..d6b3cc607e
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/logged_events.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright 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_LOGGED_EVENTS_H_
+#define LOGGING_RTC_EVENT_LOG_LOGGED_EVENTS_H_
+
+// TODO(terelius): Delete this forwarding header when downstream
+// projects have been updated.
+#include "logging/rtc_event_log/events/logged_rtp_rtcp.h"
+
+#endif // LOGGING_RTC_EVENT_LOG_LOGGED_EVENTS_H_
diff --git a/third_party/libwebrtc/logging/rtc_event_log/mock/mock_rtc_event_log.cc b/third_party/libwebrtc/logging/rtc_event_log/mock/mock_rtc_event_log.cc
new file mode 100644
index 0000000000..240a4f6693
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/mock/mock_rtc_event_log.cc
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2018 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/mock/mock_rtc_event_log.h"
+
+namespace webrtc {
+
+MockRtcEventLog::MockRtcEventLog() = default;
+MockRtcEventLog::~MockRtcEventLog() = default;
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/logging/rtc_event_log/mock/mock_rtc_event_log.h b/third_party/libwebrtc/logging/rtc_event_log/mock/mock_rtc_event_log.h
new file mode 100644
index 0000000000..646831de27
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/mock/mock_rtc_event_log.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2016 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_MOCK_MOCK_RTC_EVENT_LOG_H_
+#define LOGGING_RTC_EVENT_LOG_MOCK_MOCK_RTC_EVENT_LOG_H_
+
+#include <memory>
+
+#include "api/rtc_event_log/rtc_event_log.h"
+#include "test/gmock.h"
+
+namespace webrtc {
+
+class MockRtcEventLog : public RtcEventLog {
+ public:
+ MockRtcEventLog();
+ ~MockRtcEventLog() override;
+
+ MOCK_METHOD(bool,
+ StartLogging,
+ (std::unique_ptr<RtcEventLogOutput> output,
+ int64_t output_period_ms),
+ (override));
+
+ MOCK_METHOD(void, StopLogging, (), (override));
+
+ void Log(std::unique_ptr<RtcEvent> event) override {
+ return LogProxy(event.get());
+ }
+ MOCK_METHOD(void, LogProxy, (RtcEvent*));
+};
+
+} // namespace webrtc
+
+#endif // LOGGING_RTC_EVENT_LOG_MOCK_MOCK_RTC_EVENT_LOG_H_
diff --git a/third_party/libwebrtc/logging/rtc_event_log/output/rtc_event_log_output_file.h b/third_party/libwebrtc/logging/rtc_event_log/output/rtc_event_log_output_file.h
new file mode 100644
index 0000000000..86be01d884
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/output/rtc_event_log_output_file.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2017 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_OUTPUT_RTC_EVENT_LOG_OUTPUT_FILE_H_
+#define LOGGING_RTC_EVENT_LOG_OUTPUT_RTC_EVENT_LOG_OUTPUT_FILE_H_
+
+// TODO(bugs.webrtc.org/6463): For backwards compatibility; delete as soon as
+// downstream dependencies are updated.
+
+#include "api/rtc_event_log_output_file.h"
+
+#endif // LOGGING_RTC_EVENT_LOG_OUTPUT_RTC_EVENT_LOG_OUTPUT_FILE_H_
diff --git a/third_party/libwebrtc/logging/rtc_event_log/rtc_event_log.proto b/third_party/libwebrtc/logging/rtc_event_log/rtc_event_log.proto
new file mode 100644
index 0000000000..12baa493bd
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/rtc_event_log.proto
@@ -0,0 +1,427 @@
+syntax = "proto2";
+option optimize_for = LITE_RUNTIME;
+package webrtc.rtclog;
+
+enum MediaType {
+ ANY = 0;
+ AUDIO = 1;
+ VIDEO = 2;
+ DATA = 3;
+}
+
+// This is the main message to dump to a file, it can contain multiple event
+// messages, but it is possible to append multiple EventStreams (each with a
+// single event) to a file.
+// This has the benefit that there's no need to keep all data in memory.
+message EventStream {
+ repeated Event stream = 1;
+}
+
+message Event {
+ // required - Elapsed wallclock time in us since the start of the log.
+ optional int64 timestamp_us = 1;
+
+ // The different types of events that can occur, the UNKNOWN_EVENT entry
+ // is added in case future EventTypes are added, in that case old code will
+ // receive the new events as UNKNOWN_EVENT.
+ enum EventType {
+ UNKNOWN_EVENT = 0;
+ LOG_START = 1;
+ LOG_END = 2;
+ RTP_EVENT = 3;
+ RTCP_EVENT = 4;
+ AUDIO_PLAYOUT_EVENT = 5;
+ LOSS_BASED_BWE_UPDATE = 6;
+ DELAY_BASED_BWE_UPDATE = 7;
+ VIDEO_RECEIVER_CONFIG_EVENT = 8;
+ VIDEO_SENDER_CONFIG_EVENT = 9;
+ AUDIO_RECEIVER_CONFIG_EVENT = 10;
+ AUDIO_SENDER_CONFIG_EVENT = 11;
+ AUDIO_NETWORK_ADAPTATION_EVENT = 16;
+ BWE_PROBE_CLUSTER_CREATED_EVENT = 17;
+ BWE_PROBE_RESULT_EVENT = 18;
+ ALR_STATE_EVENT = 19;
+ ICE_CANDIDATE_PAIR_CONFIG = 20;
+ ICE_CANDIDATE_PAIR_EVENT = 21;
+ REMOTE_ESTIMATE = 22;
+ }
+
+ // required - Indicates the type of this event
+ optional EventType type = 2;
+
+ oneof subtype {
+ // required if type == RTP_EVENT
+ RtpPacket rtp_packet = 3;
+
+ // required if type == RTCP_EVENT
+ RtcpPacket rtcp_packet = 4;
+
+ // required if type == AUDIO_PLAYOUT_EVENT
+ AudioPlayoutEvent audio_playout_event = 5;
+
+ // required if type == LOSS_BASED_BWE_UPDATE
+ LossBasedBweUpdate loss_based_bwe_update = 6;
+
+ // required if type == DELAY_BASED_BWE_UPDATE
+ DelayBasedBweUpdate delay_based_bwe_update = 7;
+
+ // required if type == VIDEO_RECEIVER_CONFIG_EVENT
+ VideoReceiveConfig video_receiver_config = 8;
+
+ // required if type == VIDEO_SENDER_CONFIG_EVENT
+ VideoSendConfig video_sender_config = 9;
+
+ // required if type == AUDIO_RECEIVER_CONFIG_EVENT
+ AudioReceiveConfig audio_receiver_config = 10;
+
+ // required if type == AUDIO_SENDER_CONFIG_EVENT
+ AudioSendConfig audio_sender_config = 11;
+
+ // required if type == AUDIO_NETWORK_ADAPTATION_EVENT
+ AudioNetworkAdaptation audio_network_adaptation = 16;
+
+ // required if type == BWE_PROBE_CLUSTER_CREATED_EVENT
+ BweProbeCluster probe_cluster = 17;
+
+ // required if type == BWE_PROBE_RESULT_EVENT
+ BweProbeResult probe_result = 18;
+
+ // required if type == ALR_STATE_EVENT
+ AlrState alr_state = 19;
+
+ // required if type == ICE_CANDIDATE_PAIR_CONFIG
+ IceCandidatePairConfig ice_candidate_pair_config = 20;
+
+ // required if type == ICE_CANDIDATE_PAIR_EVENT
+ IceCandidatePairEvent ice_candidate_pair_event = 21;
+
+ // required if type == REMOTE_ESTIMATE
+ RemoteEstimate remote_estimate = 22;
+ }
+}
+
+message RtpPacket {
+ // required - True if the packet is incoming w.r.t. the user logging the data
+ optional bool incoming = 1;
+
+ optional MediaType type = 2 [deprecated = true];
+
+ // required - The size of the packet including both payload and header.
+ optional uint32 packet_length = 3;
+
+ // required - The RTP header only.
+ optional bytes header = 4;
+
+ // optional - The probe cluster id.
+ optional int32 probe_cluster_id = 5;
+
+ // Do not add code to log user payload data without a privacy review!
+}
+
+message RtcpPacket {
+ // required - True if the packet is incoming w.r.t. the user logging the data
+ optional bool incoming = 1;
+
+ optional MediaType type = 2 [deprecated = true];
+
+ // required - The whole packet including both payload and header.
+ optional bytes packet_data = 3;
+}
+
+message AudioPlayoutEvent {
+ // TODO(ivoc): Rename, we currently use the "remote" ssrc, i.e. identifying
+ // the receive stream, while local_ssrc identifies the send stream, if any.
+ // required - The SSRC of the audio stream associated with the playout event.
+ optional uint32 local_ssrc = 2;
+}
+
+message LossBasedBweUpdate {
+ // required - Bandwidth estimate (in bps) after the update.
+ optional int32 bitrate_bps = 1;
+
+ // required - Fraction of lost packets since last receiver report
+ // computed as floor( 256 * (#lost_packets / #total_packets) ).
+ // The possible values range from 0 to 255.
+ optional uint32 fraction_loss = 2;
+
+ // TODO(terelius): Is this really needed? Remove or make optional?
+ // required - Total number of packets that the BWE update is based on.
+ optional int32 total_packets = 3;
+}
+
+message DelayBasedBweUpdate {
+ enum DetectorState {
+ BWE_NORMAL = 0;
+ BWE_UNDERUSING = 1;
+ BWE_OVERUSING = 2;
+ }
+
+ // required - Bandwidth estimate (in bps) after the update.
+ optional int32 bitrate_bps = 1;
+
+ // required - The state of the overuse detector.
+ optional DetectorState detector_state = 2;
+}
+
+// TODO(terelius): Video and audio streams could in principle share SSRC,
+// so identifying a stream based only on SSRC might not work.
+// It might be better to use a combination of SSRC and media type
+// or SSRC and port number, but for now we will rely on SSRC only.
+message VideoReceiveConfig {
+ // required - Synchronization source (stream identifier) to be received.
+ optional uint32 remote_ssrc = 1;
+ // required - Sender SSRC used for sending RTCP (such as receiver reports).
+ optional uint32 local_ssrc = 2;
+
+ // Compound mode is described by RFC 4585 and reduced-size
+ // RTCP mode is described by RFC 5506.
+ enum RtcpMode {
+ RTCP_COMPOUND = 1;
+ RTCP_REDUCEDSIZE = 2;
+ }
+ // required - RTCP mode to use.
+ optional RtcpMode rtcp_mode = 3;
+
+ // required - Receiver estimated maximum bandwidth.
+ optional bool remb = 4;
+
+ // Map from video RTP payload type -> RTX config.
+ repeated RtxMap rtx_map = 5;
+
+ // RTP header extensions used for the received stream.
+ repeated RtpHeaderExtension header_extensions = 6;
+
+ // List of decoders associated with the stream.
+ repeated DecoderConfig decoders = 7;
+}
+
+// Maps decoder names to payload types.
+message DecoderConfig {
+ // required
+ optional string name = 1;
+
+ // required
+ optional int32 payload_type = 2;
+}
+
+// Maps RTP header extension names to numerical IDs.
+message RtpHeaderExtension {
+ // required
+ optional string name = 1;
+
+ // required
+ optional int32 id = 2;
+}
+
+// RTX settings for incoming video payloads that may be received.
+// RTX is disabled if there's no config present.
+message RtxConfig {
+ // required - SSRC to use for the RTX stream.
+ optional uint32 rtx_ssrc = 1;
+
+ // required - Payload type to use for the RTX stream.
+ optional int32 rtx_payload_type = 2;
+}
+
+message RtxMap {
+ // required
+ optional int32 payload_type = 1;
+
+ // required
+ optional RtxConfig config = 2;
+}
+
+message VideoSendConfig {
+ // Synchronization source (stream identifier) for outgoing stream.
+ // One stream can have several ssrcs for e.g. simulcast.
+ // At least one ssrc is required.
+ repeated uint32 ssrcs = 1;
+
+ // RTP header extensions used for the outgoing stream.
+ repeated RtpHeaderExtension header_extensions = 2;
+
+ // List of SSRCs for retransmitted packets.
+ repeated uint32 rtx_ssrcs = 3;
+
+ // required if rtx_ssrcs is used - Payload type for retransmitted packets.
+ optional int32 rtx_payload_type = 4;
+
+ // required - Encoder associated with the stream.
+ optional EncoderConfig encoder = 5;
+}
+
+// Maps encoder names to payload types.
+message EncoderConfig {
+ // required
+ optional string name = 1;
+
+ // required
+ optional int32 payload_type = 2;
+}
+
+message AudioReceiveConfig {
+ // required - Synchronization source (stream identifier) to be received.
+ optional uint32 remote_ssrc = 1;
+
+ // required - Sender SSRC used for sending RTCP (such as receiver reports).
+ optional uint32 local_ssrc = 2;
+
+ // RTP header extensions used for the received audio stream.
+ repeated RtpHeaderExtension header_extensions = 3;
+}
+
+message AudioSendConfig {
+ // required - Synchronization source (stream identifier) for outgoing stream.
+ optional uint32 ssrc = 1;
+
+ // RTP header extensions used for the outgoing audio stream.
+ repeated RtpHeaderExtension header_extensions = 2;
+}
+
+message AudioNetworkAdaptation {
+ // Bit rate that the audio encoder is operating at.
+ optional int32 bitrate_bps = 1;
+
+ // Frame length that each encoded audio packet consists of.
+ optional int32 frame_length_ms = 2;
+
+ // Packet loss fraction that the encoder's forward error correction (FEC) is
+ // optimized for.
+ optional float uplink_packet_loss_fraction = 3;
+
+ // Whether forward error correction (FEC) is turned on or off.
+ optional bool enable_fec = 4;
+
+ // Whether discontinuous transmission (DTX) is turned on or off.
+ optional bool enable_dtx = 5;
+
+ // Number of audio channels that each encoded packet consists of.
+ optional uint32 num_channels = 6;
+}
+
+message BweProbeCluster {
+ // required - The id of this probe cluster.
+ optional int32 id = 1;
+
+ // required - The bitrate in bps that this probe cluster is meant to probe.
+ optional int32 bitrate_bps = 2;
+
+ // required - The minimum number of packets used to probe the given bitrate.
+ optional uint32 min_packets = 3;
+
+ // required - The minimum number of bytes used to probe the given bitrate.
+ optional uint32 min_bytes = 4;
+}
+
+message BweProbeResult {
+ // required - The id of this probe cluster.
+ optional int32 id = 1;
+
+ enum ResultType {
+ SUCCESS = 0;
+ INVALID_SEND_RECEIVE_INTERVAL = 1;
+ INVALID_SEND_RECEIVE_RATIO = 2;
+ TIMEOUT = 3;
+ }
+
+ // required - The result of this probing attempt.
+ optional ResultType result = 2;
+
+ // optional - but required if result == SUCCESS. The resulting bitrate in bps.
+ optional int32 bitrate_bps = 3;
+}
+
+message RemoteEstimate {
+ // optional - Lower estimate of link capacity.
+ optional uint32 link_capacity_lower_kbps = 1;
+
+ // optional - Upper estimate of link capacity.
+ optional uint32 link_capacity_upper_kbps = 2;
+}
+
+message AlrState {
+ // required - If we are in ALR or not.
+ optional bool in_alr = 1;
+}
+
+message IceCandidatePairConfig {
+ enum IceCandidatePairConfigType {
+ ADDED = 0;
+ UPDATED = 1;
+ DESTROYED = 2;
+ SELECTED = 3;
+ }
+
+ enum IceCandidateType {
+ LOCAL = 0;
+ STUN = 1;
+ PRFLX = 2;
+ RELAY = 3;
+ UNKNOWN_CANDIDATE_TYPE = 4;
+ }
+
+ enum Protocol {
+ UDP = 0;
+ TCP = 1;
+ SSLTCP = 2;
+ TLS = 3;
+ UNKNOWN_PROTOCOL = 4;
+ }
+
+ enum AddressFamily {
+ IPV4 = 0;
+ IPV6 = 1;
+ UNKNOWN_ADDRESS_FAMILY = 2;
+ }
+
+ enum NetworkType {
+ ETHERNET = 0;
+ LOOPBACK = 1;
+ WIFI = 2;
+ VPN = 3;
+ CELLULAR = 4;
+ UNKNOWN_NETWORK_TYPE = 5;
+ }
+
+ // required
+ optional IceCandidatePairConfigType config_type = 1;
+
+ // required
+ optional uint32 candidate_pair_id = 2;
+
+ // required
+ optional IceCandidateType local_candidate_type = 3;
+
+ // required
+ optional Protocol local_relay_protocol = 4;
+
+ // required
+ optional NetworkType local_network_type = 5;
+
+ // required
+ optional AddressFamily local_address_family = 6;
+
+ // required
+ optional IceCandidateType remote_candidate_type = 7;
+
+ // required
+ optional AddressFamily remote_address_family = 8;
+
+ // required
+ optional Protocol candidate_pair_protocol = 9;
+}
+
+message IceCandidatePairEvent {
+ enum IceCandidatePairEventType {
+ CHECK_SENT = 0;
+ CHECK_RECEIVED = 1;
+ CHECK_RESPONSE_SENT = 2;
+ CHECK_RESPONSE_RECEIVED = 3;
+ }
+
+ // required
+ optional IceCandidatePairEventType event_type = 1;
+
+ // required
+ optional uint32 candidate_pair_id = 2;
+}
diff --git a/third_party/libwebrtc/logging/rtc_event_log/rtc_event_log2.proto b/third_party/libwebrtc/logging/rtc_event_log/rtc_event_log2.proto
new file mode 100644
index 0000000000..2545be87e5
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/rtc_event_log2.proto
@@ -0,0 +1,750 @@
+// THIS FILE IS EXPERIMENTAL. BREAKING CHANGES MAY BE MADE AT ANY TIME
+// WITHOUT PRIOR WARNING. THIS FILE SHOULD NOT BE USED IN PRODUCTION CODE.
+
+syntax = "proto2";
+option optimize_for = LITE_RUNTIME;
+package webrtc.rtclog2;
+
+// At the top level, a WebRTC event log is just an EventStream object. Note that
+// concatenating multiple EventStreams in the same file is equivalent to a
+// single EventStream object containing the same events. Hence, it is not
+// necessary to wait for the entire log to be complete before beginning to
+// write it to a file.
+// Note: For all X_deltas fields, we rely on the default value being an
+// empty string.
+message EventStream {
+ // Deprecated - Maintained for compatibility with the old event log.
+ repeated Event stream = 1 [deprecated = true];
+ repeated IncomingRtpPackets incoming_rtp_packets = 2;
+ repeated OutgoingRtpPackets outgoing_rtp_packets = 3;
+ repeated IncomingRtcpPackets incoming_rtcp_packets = 4;
+ repeated OutgoingRtcpPackets outgoing_rtcp_packets = 5;
+ repeated AudioPlayoutEvents audio_playout_events = 6;
+ repeated FrameDecodedEvents frame_decoded_events = 7;
+ // The field tags 8-15 are reserved for the most common events.
+ repeated BeginLogEvent begin_log_events = 16;
+ repeated EndLogEvent end_log_events = 17;
+ repeated LossBasedBweUpdates loss_based_bwe_updates = 18;
+ repeated DelayBasedBweUpdates delay_based_bwe_updates = 19;
+ repeated AudioNetworkAdaptations audio_network_adaptations = 20;
+ repeated BweProbeCluster probe_clusters = 21;
+ repeated BweProbeResultSuccess probe_success = 22;
+ repeated BweProbeResultFailure probe_failure = 23;
+ repeated AlrState alr_states = 24;
+ repeated IceCandidatePairConfig ice_candidate_configs = 25;
+ 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 RouteChange route_changes = 32;
+ repeated RemoteEstimates remote_estimates = 33;
+ repeated NetEqSetMinimumDelay neteq_set_minimum_delay = 34;
+
+ repeated AudioRecvStreamConfig audio_recv_stream_configs = 101;
+ repeated AudioSendStreamConfig audio_send_stream_configs = 102;
+ repeated VideoRecvStreamConfig video_recv_stream_configs = 103;
+ repeated VideoSendStreamConfig video_send_stream_configs = 104;
+}
+
+// DEPRECATED.
+message Event {
+ // 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;
+
+ // required - RTP marker bit, used to label boundaries between video frames.
+ optional bool marker = 2;
+
+ // required - RTP payload type.
+ optional uint32 payload_type = 3;
+
+ // required - RTP sequence number.
+ optional uint32 sequence_number = 4;
+
+ // required - RTP monotonic clock timestamp (not actual time).
+ optional fixed32 rtp_timestamp = 5;
+
+ // required - Synchronization source of this packet's RTP stream.
+ optional fixed32 ssrc = 6;
+
+ // TODO(terelius/dinor): Add CSRCs. Field number 7 reserved for this purpose.
+
+ // required - The size (in bytes) of the media payload, not including
+ // RTP header or padding. The packet size is the sum of payload, header and
+ // padding.
+ optional uint32 payload_size = 8;
+
+ // required - The size (in bytes) of the RTP header.
+ optional uint32 header_size = 9;
+
+ // required - The size (in bytes) of the padding.
+ optional uint32 padding_size = 10;
+
+ // optional - required if the batch contains delta encoded events.
+ optional uint32 number_of_deltas = 11;
+
+ // Field numbers 12-14 reserved for future use.
+
+ // Optional header extensions.
+ optional uint32 transport_sequence_number = 15;
+ optional int32 transmission_time_offset = 16;
+ optional uint32 absolute_send_time = 17;
+ optional uint32 video_rotation = 18;
+ // `audio_level` and `voice_activity` are always used in conjunction.
+ optional uint32 audio_level = 19;
+ optional bool voice_activity = 20;
+ // TODO(terelius): Add other header extensions like playout delay?
+
+ // Delta encodings.
+ optional bytes timestamp_ms_deltas = 101;
+ optional bytes marker_deltas = 102;
+ optional bytes payload_type_deltas = 103;
+ optional bytes sequence_number_deltas = 104;
+ optional bytes rtp_timestamp_deltas = 105;
+ // Field number 107 reserved for CSRC.
+ optional bytes ssrc_deltas = 106;
+ optional bytes payload_size_deltas = 108;
+ optional bytes header_size_deltas = 109;
+ optional bytes padding_size_deltas = 110;
+ // Field number 111-114 reserved for future use.
+ optional bytes transport_sequence_number_deltas = 115;
+ optional bytes transmission_time_offset_deltas = 116;
+ optional bytes absolute_send_time_deltas = 117;
+ optional bytes video_rotation_deltas = 118;
+ // `audio_level` and `voice_activity` are always used in conjunction.
+ optional bytes audio_level_deltas = 119;
+ optional bytes voice_activity_deltas = 120;
+}
+
+message OutgoingRtpPackets {
+ // required
+ optional int64 timestamp_ms = 1;
+
+ // required - RTP marker bit, used to label boundaries between video frames.
+ optional bool marker = 2;
+
+ // required - RTP payload type.
+ optional uint32 payload_type = 3;
+
+ // required - RTP sequence number.
+ optional uint32 sequence_number = 4;
+
+ // required - RTP monotonic clock timestamp (not actual time).
+ optional fixed32 rtp_timestamp = 5;
+
+ // required - Synchronization source of this packet's RTP stream.
+ optional fixed32 ssrc = 6;
+
+ // TODO(terelius/dinor): Add CSRCs. Field number 7 reserved for this purpose.
+
+ // required - The size (in bytes) of the media payload, not including
+ // RTP header or padding. The packet size is the sum of payload, header and
+ // padding.
+ optional uint32 payload_size = 8;
+
+ // required - The size (in bytes) of the RTP header.
+ optional uint32 header_size = 9;
+
+ // required - The size (in bytes) of the padding.
+ optional uint32 padding_size = 10;
+
+ // optional - required if the batch contains delta encoded events.
+ optional uint32 number_of_deltas = 11;
+
+ // Field numbers 12-14 reserved for future use.
+
+ // Optional header extensions.
+ optional uint32 transport_sequence_number = 15;
+ optional int32 transmission_time_offset = 16;
+ optional uint32 absolute_send_time = 17;
+ optional uint32 video_rotation = 18;
+ // `audio_level` and `voice_activity` are always used in conjunction.
+ optional uint32 audio_level = 19;
+ optional bool voice_activity = 20;
+ // TODO(terelius): Add other header extensions like playout delay?
+
+ // Delta encodings.
+ optional bytes timestamp_ms_deltas = 101;
+ optional bytes marker_deltas = 102;
+ optional bytes payload_type_deltas = 103;
+ optional bytes sequence_number_deltas = 104;
+ optional bytes rtp_timestamp_deltas = 105;
+ optional bytes ssrc_deltas = 106;
+ // Field number 107 reserved for CSRC.
+ optional bytes payload_size_deltas = 108;
+ optional bytes header_size_deltas = 109;
+ optional bytes padding_size_deltas = 110;
+ // Field number 111-114 reserved for future use.
+ optional bytes transport_sequence_number_deltas = 115;
+ optional bytes transmission_time_offset_deltas = 116;
+ optional bytes absolute_send_time_deltas = 117;
+ optional bytes video_rotation_deltas = 118;
+ // `audio_level` and `voice_activity` are always used in conjunction.
+ optional bytes audio_level_deltas = 119;
+ optional bytes voice_activity_deltas = 120;
+}
+
+message IncomingRtcpPackets {
+ // required
+ optional int64 timestamp_ms = 1;
+
+ // required - The whole packet including both payload and header.
+ optional bytes raw_packet = 2;
+ // TODO(terelius): Feasible to log parsed RTCP instead?
+
+ // optional - required if the batch contains delta encoded events.
+ optional uint32 number_of_deltas = 3;
+
+ // Delta/blob encodings.
+ optional bytes timestamp_ms_deltas = 101;
+ optional bytes raw_packet_blobs = 102;
+}
+
+message OutgoingRtcpPackets {
+ // required
+ optional int64 timestamp_ms = 1;
+
+ // required - The whole packet including both payload and header.
+ optional bytes raw_packet = 2;
+ // TODO(terelius): Feasible to log parsed RTCP instead?
+
+ // optional - required if the batch contains delta encoded events.
+ optional uint32 number_of_deltas = 3;
+
+ // Delta/blob encodings.
+ optional bytes timestamp_ms_deltas = 101;
+ optional bytes raw_packet_blobs = 102;
+}
+
+message AudioPlayoutEvents {
+ // required
+ optional int64 timestamp_ms = 1;
+
+ // required - The SSRC of the audio stream associated with the playout event.
+ optional uint32 local_ssrc = 2;
+
+ // optional - required if the batch contains delta encoded events.
+ optional uint32 number_of_deltas = 3;
+
+ // Delta encodings.
+ optional bytes timestamp_ms_deltas = 101;
+ optional bytes local_ssrc_deltas = 102;
+}
+
+message NetEqSetMinimumDelay {
+ // required
+ optional int64 timestamp_ms = 1;
+
+ // required - The SSRC of the remote stream associated with the MinimumDelay
+ // event.
+ optional fixed32 remote_ssrc = 2;
+
+ // required - minimum delay passed to SetBaseMinimumDelay.
+ optional int32 minimum_delay_ms = 3;
+
+ // optional - required if the batch contains delta encoded events.
+ optional uint32 number_of_deltas = 4;
+
+ // Delta encodings.
+ optional bytes timestamp_ms_deltas = 101;
+ optional bytes remote_ssrc_deltas = 102;
+ optional bytes minimum_delay_ms_deltas = 103;
+}
+
+message FrameDecodedEvents {
+ enum Codec {
+ CODEC_UNKNOWN = 0;
+ CODEC_GENERIC = 1;
+ CODEC_VP8 = 2;
+ CODEC_VP9 = 3;
+ CODEC_AV1 = 4;
+ CODEC_H264 = 5;
+ }
+
+ // required
+ optional int64 timestamp_ms = 1;
+
+ // required - The SSRC of the video stream that the frame belongs to.
+ optional fixed32 ssrc = 2;
+
+ // required - The predicted render time of the frame.
+ optional int64 render_time_ms = 3;
+
+ // required - The width (in pixels) of the frame.
+ optional int32 width = 4;
+
+ // required - The height (in pixels) of the frame.
+ optional int32 height = 5;
+
+ // required - The codec type of the frame.
+ optional Codec codec = 6;
+
+ // required - The QP (quantization parameter) of the frame. Range [0,255].
+ optional uint32 qp = 7;
+
+ // optional - required if the batch contains delta encoded events.
+ optional uint32 number_of_deltas = 15;
+
+ // Delta encodings.
+ optional bytes timestamp_ms_deltas = 101;
+ optional bytes ssrc_deltas = 102;
+ optional bytes render_time_ms_deltas = 103;
+ optional bytes width_deltas = 104;
+ optional bytes height_deltas = 105;
+ optional bytes codec_deltas = 106;
+ optional bytes qp_deltas = 107;
+}
+
+message BeginLogEvent {
+ // required
+ optional int64 timestamp_ms = 1;
+
+ // required
+ optional uint32 version = 2;
+
+ // required
+ optional int64 utc_time_ms = 3;
+}
+
+message EndLogEvent {
+ // required
+ optional int64 timestamp_ms = 1;
+}
+
+message LossBasedBweUpdates {
+ // required
+ optional int64 timestamp_ms = 1;
+
+ // TODO(terelius): Update log interface to unsigned.
+ // required - Bandwidth estimate (in bps) after the update.
+ optional uint32 bitrate_bps = 2;
+
+ // required - Fraction of lost packets since last receiver report
+ // computed as floor( 256 * (#lost_packets / #total_packets) ).
+ // The possible values range from 0 to 255.
+ optional uint32 fraction_loss = 3;
+
+ // TODO(terelius): Is this really needed? Remove or make optional?
+ // TODO(terelius): Update log interface to unsigned.
+ // required - Total number of packets that the BWE update is based on.
+ optional uint32 total_packets = 4;
+
+ // optional - required if the batch contains delta encoded events.
+ optional uint32 number_of_deltas = 5;
+
+ // Delta encodings.
+ optional bytes timestamp_ms_deltas = 101;
+ optional bytes bitrate_bps_deltas = 102;
+ optional bytes fraction_loss_deltas = 103;
+ optional bytes total_packets_deltas = 104;
+}
+
+message DelayBasedBweUpdates {
+ // required
+ optional int64 timestamp_ms = 1;
+
+ // required - Bandwidth estimate (in bps) after the update.
+ optional uint32 bitrate_bps = 2;
+
+ enum DetectorState {
+ BWE_UNKNOWN_STATE = 0;
+ BWE_NORMAL = 1;
+ BWE_UNDERUSING = 2;
+ BWE_OVERUSING = 3;
+ }
+ optional DetectorState detector_state = 3;
+
+ // optional - required if the batch contains delta encoded events.
+ optional uint32 number_of_deltas = 4;
+
+ // Delta encodings.
+ optional bytes timestamp_ms_deltas = 101;
+ optional bytes bitrate_bps_deltas = 102;
+ optional bytes detector_state_deltas = 103;
+}
+
+// Maps RTP header extension names to numerical IDs.
+message RtpHeaderExtensionConfig {
+ // Optional IDs for the header extensions. Each ID is a 4-bit number that is
+ // only set if that extension is configured.
+ // TODO: Can we skip audio level?
+ optional int32 transmission_time_offset_id = 1;
+ optional int32 absolute_send_time_id = 2;
+ optional int32 transport_sequence_number_id = 3;
+ optional int32 video_rotation_id = 4;
+ optional int32 audio_level_id = 5;
+ // TODO(terelius): Add other header extensions like playout delay?
+}
+
+message VideoRecvStreamConfig {
+ // required
+ optional int64 timestamp_ms = 1;
+
+ // required - Synchronization source (stream identifier) to be received.
+ optional uint32 remote_ssrc = 2;
+
+ // required - Sender SSRC used for sending RTCP (such as receiver reports).
+ optional uint32 local_ssrc = 3;
+
+ // optional - required if RTX is configured. SSRC for the RTX stream.
+ optional uint32 rtx_ssrc = 4;
+
+ // IDs for the header extension we care about. Only required if there are
+ // header extensions configured.
+ optional RtpHeaderExtensionConfig header_extensions = 5;
+
+ // TODO(terelius): Do we need codec-payload mapping? If so and rtx_ssrc is
+ // used, we also need a map between RTP payload type and RTX payload type.
+}
+
+message VideoSendStreamConfig {
+ // required
+ optional int64 timestamp_ms = 1;
+
+ // required - Synchronization source (stream identifier) for outgoing stream.
+ // When using simulcast, a separate config should be logged for each stream.
+ optional uint32 ssrc = 2;
+
+ // optional - required if RTX is configured. SSRC for the RTX stream.
+ optional uint32 rtx_ssrc = 3;
+
+ // IDs for the header extension we care about. Only required if there are
+ // header extensions configured.
+ optional RtpHeaderExtensionConfig header_extensions = 4;
+
+ // TODO(terelius): Do we need codec-payload mapping? If so and rtx_ssrc is
+ // used, we also need a map between RTP payload type and RTX payload type.
+}
+
+message AudioRecvStreamConfig {
+ // required
+ optional int64 timestamp_ms = 1;
+
+ // required - Synchronization source (stream identifier) to be received.
+ optional uint32 remote_ssrc = 2;
+
+ // required - Sender SSRC used for sending RTCP (such as receiver reports).
+ optional uint32 local_ssrc = 3;
+
+ // Field number 4 reserved for RTX SSRC.
+
+ // IDs for the header extension we care about. Only required if there are
+ // header extensions configured.
+ optional RtpHeaderExtensionConfig header_extensions = 5;
+
+ // TODO(terelius): Do we need codec-payload mapping? If so and rtx_ssrc is
+ // used, we also need a map between RTP payload type and RTX payload type.
+}
+
+message AudioSendStreamConfig {
+ // required
+ optional int64 timestamp_ms = 1;
+
+ // required - Synchronization source (stream identifier) for outgoing stream.
+ optional uint32 ssrc = 2;
+
+ // Field number 3 reserved for RTX SSRC.
+
+ // IDs for the header extension we care about. Only required if there are
+ // header extensions configured.
+ optional RtpHeaderExtensionConfig header_extensions = 4;
+
+ // TODO(terelius): Do we need codec-payload mapping? If so and rtx_ssrc is
+ // used, we also need a map between RTP payload type and RTX payload type.
+}
+
+message AudioNetworkAdaptations {
+ // required
+ optional int64 timestamp_ms = 1;
+
+ // Bit rate that the audio encoder is operating at.
+ // TODO(terelius): Signed vs unsigned?
+ optional int32 bitrate_bps = 2;
+
+ // Frame length that each encoded audio packet consists of.
+ // TODO(terelius): Signed vs unsigned?
+ optional int32 frame_length_ms = 3;
+
+ // Packet loss fraction that the encoder's forward error correction (FEC) is
+ // optimized for.
+ // Instead of encoding a float, we encode a value between 0 and 16383, which
+ // if divided by 16383, will give a value close to the original float.
+ // The value 16383 (2^14 - 1) was chosen so that it would give good precision
+ // on the one hand, and would be encodable with two bytes in varint form
+ // on the other hand.
+ optional uint32 uplink_packet_loss_fraction = 4;
+
+ // Whether forward error correction (FEC) is turned on or off.
+ optional bool enable_fec = 5;
+
+ // Whether discontinuous transmission (DTX) is turned on or off.
+ optional bool enable_dtx = 6;
+
+ // Number of audio channels that each encoded packet consists of.
+ optional uint32 num_channels = 7;
+
+ // optional - required if the batch contains delta encoded events.
+ optional uint32 number_of_deltas = 8;
+
+ // Delta encodings.
+ optional bytes timestamp_ms_deltas = 101;
+ optional bytes bitrate_bps_deltas = 102;
+ optional bytes frame_length_ms_deltas = 103;
+ optional bytes uplink_packet_loss_fraction_deltas = 104;
+ optional bytes enable_fec_deltas = 105;
+ optional bytes enable_dtx_deltas = 106;
+ optional bytes num_channels_deltas = 107;
+}
+
+message BweProbeCluster {
+ // required
+ optional int64 timestamp_ms = 1;
+
+ // required - The id of this probe cluster.
+ optional uint32 id = 2;
+
+ // required - The bitrate in bps that this probe cluster is meant to probe.
+ optional uint32 bitrate_bps = 3;
+
+ // required - The minimum number of packets used to probe the given bitrate.
+ optional uint32 min_packets = 4;
+
+ // required - The minimum number of bytes used to probe the given bitrate.
+ optional uint32 min_bytes = 5;
+}
+
+message BweProbeResultSuccess {
+ // required
+ optional int64 timestamp_ms = 1;
+
+ // required - The id of this probe cluster.
+ optional uint32 id = 2;
+
+ // required - The resulting bitrate in bps.
+ optional uint32 bitrate_bps = 3;
+}
+
+message BweProbeResultFailure {
+ // required
+ optional int64 timestamp_ms = 1;
+
+ // required - The id of this probe cluster.
+ optional uint32 id = 2;
+
+ enum FailureReason {
+ UNKNOWN = 0;
+ INVALID_SEND_RECEIVE_INTERVAL = 1;
+ INVALID_SEND_RECEIVE_RATIO = 2;
+ TIMEOUT = 3;
+ }
+
+ // required
+ optional FailureReason failure = 3;
+}
+
+message AlrState {
+ // required
+ optional int64 timestamp_ms = 1;
+
+ // required - True if the send rate is application limited.
+ optional bool in_alr = 2;
+}
+
+message IceCandidatePairConfig {
+ enum IceCandidatePairConfigType {
+ UNKNOWN_CONFIG_TYPE = 0;
+ ADDED = 1;
+ UPDATED = 2;
+ DESTROYED = 3;
+ SELECTED = 4;
+ }
+
+ enum IceCandidateType {
+ UNKNOWN_CANDIDATE_TYPE = 0;
+ LOCAL = 1;
+ STUN = 2;
+ PRFLX = 3;
+ RELAY = 4;
+ }
+
+ enum Protocol {
+ UNKNOWN_PROTOCOL = 0;
+ UDP = 1;
+ TCP = 2;
+ SSLTCP = 3;
+ TLS = 4;
+ }
+
+ enum AddressFamily {
+ UNKNOWN_ADDRESS_FAMILY = 0;
+ IPV4 = 1;
+ IPV6 = 2;
+ }
+
+ enum NetworkType {
+ UNKNOWN_NETWORK_TYPE = 0;
+ ETHERNET = 1;
+ WIFI = 2;
+ CELLULAR = 3;
+ VPN = 4;
+ LOOPBACK = 5;
+ }
+
+ // required
+ optional int64 timestamp_ms = 1;
+
+ // required
+ optional IceCandidatePairConfigType config_type = 2;
+
+ // required
+ optional uint32 candidate_pair_id = 3;
+
+ // required
+ optional IceCandidateType local_candidate_type = 4;
+
+ // required
+ optional Protocol local_relay_protocol = 5;
+
+ // required
+ optional NetworkType local_network_type = 6;
+
+ // required
+ optional AddressFamily local_address_family = 7;
+
+ // required
+ optional IceCandidateType remote_candidate_type = 8;
+
+ // required
+ optional AddressFamily remote_address_family = 9;
+
+ // required
+ optional Protocol candidate_pair_protocol = 10;
+}
+
+message IceCandidatePairEvent {
+ enum IceCandidatePairEventType {
+ UNKNOWN_CHECK_TYPE = 0;
+ CHECK_SENT = 1;
+ CHECK_RECEIVED = 2;
+ CHECK_RESPONSE_SENT = 3;
+ CHECK_RESPONSE_RECEIVED = 4;
+ }
+
+ // required
+ optional int64 timestamp_ms = 1;
+
+ // required
+ optional IceCandidatePairEventType event_type = 2;
+
+ // required
+ optional uint32 candidate_pair_id = 3;
+
+ // required
+ optional uint32 transaction_id = 4;
+}
+
+message DtlsTransportStateEvent {
+ enum DtlsTransportState {
+ UNKNOWN_DTLS_TRANSPORT_STATE = 0;
+ DTLS_TRANSPORT_NEW = 1;
+ DTLS_TRANSPORT_CONNECTING = 2;
+ DTLS_TRANSPORT_CONNECTED = 3;
+ DTLS_TRANSPORT_CLOSED = 4;
+ DTLS_TRANSPORT_FAILED = 5;
+ }
+
+ // required
+ optional int64 timestamp_ms = 1;
+
+ // required
+ optional DtlsTransportState dtls_transport_state = 2;
+}
+
+message DtlsWritableState {
+ // required
+ optional int64 timestamp_ms = 1;
+
+ // 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;
+}
+
+message RemoteEstimates {
+ // required
+ optional int64 timestamp_ms = 1;
+ // optional - value used as a safe measure of available capacity.
+ optional uint32 link_capacity_lower_kbps = 2;
+ // optional - value used as limit for increasing bitrate.
+ optional uint32 link_capacity_upper_kbps = 3;
+
+ // optional - required if the batch contains delta encoded events.
+ optional uint32 number_of_deltas = 4;
+
+ // Delta encodings.
+ optional bytes timestamp_ms_deltas = 101;
+ optional bytes link_capacity_lower_kbps_deltas = 102;
+ optional bytes link_capacity_upper_kbps_deltas = 103;
+}
diff --git a/third_party/libwebrtc/logging/rtc_event_log/rtc_event_log2rtp_dump.cc b/third_party/libwebrtc/logging/rtc_event_log/rtc_event_log2rtp_dump.cc
new file mode 100644
index 0000000000..a0514259aa
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/rtc_event_log2rtp_dump.cc
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2015 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 <stdint.h>
+#include <string.h>
+
+#include <iostream>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/flags/flag.h"
+#include "absl/flags/parse.h"
+#include "absl/flags/usage.h"
+#include "absl/memory/memory.h"
+#include "absl/strings/string_view.h"
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "api/rtc_event_log/rtc_event_log.h"
+#include "api/rtp_headers.h"
+#include "logging/rtc_event_log/rtc_event_log_parser.h"
+#include "logging/rtc_event_log/rtc_event_processor.h"
+#include "modules/rtp_rtcp/include/rtp_header_extension_map.h"
+#include "modules/rtp_rtcp/source/rtp_header_extensions.h"
+#include "modules/rtp_rtcp/source/rtp_packet.h"
+#include "rtc_base/checks.h"
+#include "test/rtp_file_reader.h"
+#include "test/rtp_file_writer.h"
+
+ABSL_FLAG(
+ bool,
+ audio,
+ true,
+ "Use --noaudio to exclude audio packets from the converted RTPdump file.");
+ABSL_FLAG(
+ bool,
+ video,
+ true,
+ "Use --novideo to exclude video packets from the converted RTPdump file.");
+ABSL_FLAG(
+ bool,
+ data,
+ true,
+ "Use --nodata to exclude data packets from the converted RTPdump file.");
+ABSL_FLAG(
+ bool,
+ rtp,
+ true,
+ "Use --nortp to exclude RTP packets from the converted RTPdump file.");
+ABSL_FLAG(
+ bool,
+ rtcp,
+ true,
+ "Use --nortcp to exclude RTCP packets from the converted RTPdump file.");
+ABSL_FLAG(std::string,
+ ssrc,
+ "",
+ "Store only packets with this SSRC (decimal or hex, the latter "
+ "starting with 0x).");
+
+namespace {
+
+using MediaType = webrtc::ParsedRtcEventLog::MediaType;
+
+// Parses the input string for a valid SSRC. If a valid SSRC is found, it is
+// written to the output variable `ssrc`, and true is returned. Otherwise,
+// false is returned.
+// The empty string must be validated as true, because it is the default value
+// of the command-line flag. In this case, no value is written to the output
+// variable.
+absl::optional<uint32_t> ParseSsrc(absl::string_view str) {
+ // If the input string starts with 0x or 0X it indicates a hexadecimal number.
+ uint32_t ssrc;
+ auto read_mode = std::dec;
+ if (str.size() > 2 &&
+ (str.substr(0, 2) == "0x" || str.substr(0, 2) == "0X")) {
+ read_mode = std::hex;
+ str = str.substr(2);
+ }
+ std::stringstream ss(std::string{str});
+ ss >> read_mode >> ssrc;
+ if (str.empty() || (!ss.fail() && ss.eof()))
+ return ssrc;
+ return absl::nullopt;
+}
+
+bool ShouldSkipStream(MediaType media_type,
+ uint32_t ssrc,
+ absl::optional<uint32_t> ssrc_filter) {
+ if (!absl::GetFlag(FLAGS_audio) && media_type == MediaType::AUDIO)
+ return true;
+ if (!absl::GetFlag(FLAGS_video) && media_type == MediaType::VIDEO)
+ return true;
+ if (!absl::GetFlag(FLAGS_data) && media_type == MediaType::DATA)
+ return true;
+ if (ssrc_filter.has_value() && ssrc != *ssrc_filter)
+ return true;
+ return false;
+}
+
+// Convert a LoggedRtpPacketIncoming to a test::RtpPacket. Header extension IDs
+// are allocated according to the provided extension map. This might not match
+// the extension map used in the actual call.
+void ConvertRtpPacket(
+ const webrtc::LoggedRtpPacketIncoming& incoming,
+ const webrtc::RtpHeaderExtensionMap& default_extension_map,
+ webrtc::test::RtpPacket* packet) {
+ webrtc::RtpPacket reconstructed_packet(&default_extension_map);
+
+ reconstructed_packet.SetMarker(incoming.rtp.header.markerBit);
+ reconstructed_packet.SetPayloadType(incoming.rtp.header.payloadType);
+ reconstructed_packet.SetSequenceNumber(incoming.rtp.header.sequenceNumber);
+ reconstructed_packet.SetTimestamp(incoming.rtp.header.timestamp);
+ reconstructed_packet.SetSsrc(incoming.rtp.header.ssrc);
+ if (incoming.rtp.header.numCSRCs > 0) {
+ reconstructed_packet.SetCsrcs(rtc::ArrayView<const uint32_t>(
+ incoming.rtp.header.arrOfCSRCs, incoming.rtp.header.numCSRCs));
+ }
+
+ // Set extensions.
+ if (incoming.rtp.header.extension.hasTransmissionTimeOffset)
+ reconstructed_packet.SetExtension<webrtc::TransmissionOffset>(
+ incoming.rtp.header.extension.transmissionTimeOffset);
+ if (incoming.rtp.header.extension.hasAbsoluteSendTime)
+ reconstructed_packet.SetExtension<webrtc::AbsoluteSendTime>(
+ incoming.rtp.header.extension.absoluteSendTime);
+ if (incoming.rtp.header.extension.hasTransportSequenceNumber)
+ reconstructed_packet.SetExtension<webrtc::TransportSequenceNumber>(
+ incoming.rtp.header.extension.transportSequenceNumber);
+ if (incoming.rtp.header.extension.hasAudioLevel)
+ reconstructed_packet.SetExtension<webrtc::AudioLevel>(
+ incoming.rtp.header.extension.voiceActivity,
+ incoming.rtp.header.extension.audioLevel);
+ if (incoming.rtp.header.extension.hasVideoRotation)
+ reconstructed_packet.SetExtension<webrtc::VideoOrientation>(
+ incoming.rtp.header.extension.videoRotation);
+ if (incoming.rtp.header.extension.hasVideoContentType)
+ reconstructed_packet.SetExtension<webrtc::VideoContentTypeExtension>(
+ incoming.rtp.header.extension.videoContentType);
+ if (incoming.rtp.header.extension.has_video_timing)
+ reconstructed_packet.SetExtension<webrtc::VideoTimingExtension>(
+ incoming.rtp.header.extension.video_timing);
+
+ RTC_DCHECK_EQ(reconstructed_packet.size(), incoming.rtp.header_length);
+ RTC_DCHECK_EQ(reconstructed_packet.headers_size(),
+ incoming.rtp.header_length);
+ memcpy(packet->data, reconstructed_packet.data(),
+ reconstructed_packet.headers_size());
+ packet->length = reconstructed_packet.headers_size();
+ packet->original_length = incoming.rtp.total_length;
+ packet->time_ms = incoming.log_time_ms();
+ // Set padding bit.
+ if (incoming.rtp.header.paddingLength > 0)
+ packet->data[0] = packet->data[0] | 0x20;
+}
+
+} // namespace
+
+// This utility will convert a stored event log to the rtpdump format.
+int main(int argc, char* argv[]) {
+ absl::SetProgramUsageMessage(
+ "Tool for converting an RtcEventLog file to an "
+ "RTP dump file.\n"
+ "Example usage:\n"
+ "./rtc_event_log2rtp_dump input.rel output.rtp\n");
+ std::vector<char*> args = absl::ParseCommandLine(argc, argv);
+ if (args.size() != 3) {
+ std::cout << absl::ProgramUsageMessage();
+ return 1;
+ }
+
+ std::string input_file = args[1];
+ std::string output_file = args[2];
+
+ absl::optional<uint32_t> ssrc_filter;
+ if (!absl::GetFlag(FLAGS_ssrc).empty()) {
+ ssrc_filter = ParseSsrc(absl::GetFlag(FLAGS_ssrc));
+ RTC_CHECK(ssrc_filter.has_value()) << "Failed to read SSRC filter flag.";
+ }
+
+ webrtc::ParsedRtcEventLog parsed_stream;
+ auto status = parsed_stream.ParseFile(input_file);
+ if (!status.ok()) {
+ std::cerr << "Failed to parse event log " << input_file << ": "
+ << status.message() << std::endl;
+ return -1;
+ }
+
+ std::unique_ptr<webrtc::test::RtpFileWriter> rtp_writer(
+ webrtc::test::RtpFileWriter::Create(
+ webrtc::test::RtpFileWriter::FileFormat::kRtpDump, output_file));
+
+ if (!rtp_writer) {
+ std::cerr << "Error while opening output file: " << output_file
+ << std::endl;
+ return -1;
+ }
+
+ int rtp_counter = 0, rtcp_counter = 0;
+ bool header_only = false;
+
+ webrtc::RtpHeaderExtensionMap default_extension_map =
+ webrtc::ParsedRtcEventLog::GetDefaultHeaderExtensionMap();
+ auto handle_rtp = [&default_extension_map, &rtp_writer, &rtp_counter](
+ const webrtc::LoggedRtpPacketIncoming& incoming) {
+ webrtc::test::RtpPacket packet;
+ ConvertRtpPacket(incoming, default_extension_map, &packet);
+
+ rtp_writer->WritePacket(&packet);
+ rtp_counter++;
+ };
+
+ auto handle_rtcp = [&rtp_writer, &rtcp_counter](
+ const webrtc::LoggedRtcpPacketIncoming& incoming) {
+ webrtc::test::RtpPacket packet;
+ memcpy(packet.data, incoming.rtcp.raw_data.data(),
+ incoming.rtcp.raw_data.size());
+ packet.length = incoming.rtcp.raw_data.size();
+ // For RTCP packets the original_length should be set to 0 in the
+ // RTPdump format.
+ packet.original_length = 0;
+ packet.time_ms = incoming.log_time_ms();
+
+ rtp_writer->WritePacket(&packet);
+ rtcp_counter++;
+ };
+
+ webrtc::RtcEventProcessor event_processor;
+ for (const auto& stream : parsed_stream.incoming_rtp_packets_by_ssrc()) {
+ MediaType media_type =
+ parsed_stream.GetMediaType(stream.ssrc, webrtc::kIncomingPacket);
+ if (ShouldSkipStream(media_type, stream.ssrc, ssrc_filter))
+ continue;
+ event_processor.AddEvents(stream.incoming_packets, handle_rtp);
+ }
+ // Note that `packet_ssrc` is the sender SSRC. An RTCP message may contain
+ // report blocks for many streams, thus several SSRCs and they don't
+ // necessarily have to be of the same media type. We therefore don't
+ // support filtering of RTCP based on SSRC and media type.
+ event_processor.AddEvents(parsed_stream.incoming_rtcp_packets(), handle_rtcp);
+
+ event_processor.ProcessEventsInOrder();
+
+ std::cout << "Wrote " << rtp_counter << (header_only ? " header-only" : "")
+ << " RTP packets and " << rtcp_counter
+ << " RTCP packets to the "
+ "output file."
+ << std::endl;
+ return 0;
+}
diff --git a/third_party/libwebrtc/logging/rtc_event_log/rtc_event_log_impl.cc b/third_party/libwebrtc/logging/rtc_event_log/rtc_event_log_impl.cc
new file mode 100644
index 0000000000..6d855f5e05
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/rtc_event_log_impl.cc
@@ -0,0 +1,276 @@
+/*
+ * Copyright (c) 2015 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/rtc_event_log_impl.h"
+
+#include <functional>
+#include <limits>
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "absl/types/optional.h"
+#include "api/task_queue/task_queue_base.h"
+#include "api/units/time_delta.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 "rtc_base/checks.h"
+#include "rtc_base/event.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/numerics/safe_conversions.h"
+#include "rtc_base/numerics/safe_minmax.h"
+#include "rtc_base/time_utils.h"
+
+namespace webrtc {
+
+std::unique_ptr<RtcEventLogEncoder> RtcEventLogImpl::CreateEncoder(
+ RtcEventLog::EncodingType type) {
+ switch (type) {
+ case RtcEventLog::EncodingType::Legacy:
+ RTC_DLOG(LS_INFO) << "Creating legacy encoder for RTC event log.";
+ return std::make_unique<RtcEventLogEncoderLegacy>();
+ case RtcEventLog::EncodingType::NewFormat:
+ RTC_DLOG(LS_INFO) << "Creating new format encoder for RTC event log.";
+ return std::make_unique<RtcEventLogEncoderNewFormat>();
+ default:
+ RTC_LOG(LS_ERROR) << "Unknown RtcEventLog encoder type (" << int(type)
+ << ")";
+ RTC_DCHECK_NOTREACHED();
+ return std::unique_ptr<RtcEventLogEncoder>(nullptr);
+ }
+}
+
+RtcEventLogImpl::RtcEventLogImpl(std::unique_ptr<RtcEventLogEncoder> encoder,
+ TaskQueueFactory* task_queue_factory,
+ size_t max_events_in_history,
+ size_t max_config_events_in_history)
+ : max_events_in_history_(max_events_in_history),
+ max_config_events_in_history_(max_config_events_in_history),
+ event_encoder_(std::move(encoder)),
+ num_config_events_written_(0),
+ last_output_ms_(rtc::TimeMillis()),
+ output_scheduled_(false),
+ logging_state_started_(false),
+ task_queue_(
+ std::make_unique<rtc::TaskQueue>(task_queue_factory->CreateTaskQueue(
+ "rtc_event_log",
+ TaskQueueFactory::Priority::NORMAL))) {}
+
+RtcEventLogImpl::~RtcEventLogImpl() {
+ // If we're logging to the output, this will stop that. Blocking function.
+ if (logging_state_started_) {
+ logging_state_checker_.Detach();
+ StopLogging();
+ }
+
+ // We want to block on any executing task by invoking ~TaskQueue() before
+ // we set unique_ptr's internal pointer to null.
+ rtc::TaskQueue* tq = task_queue_.get();
+ delete tq;
+ task_queue_.release();
+}
+
+bool RtcEventLogImpl::StartLogging(std::unique_ptr<RtcEventLogOutput> output,
+ int64_t output_period_ms) {
+ RTC_DCHECK(output_period_ms == kImmediateOutput || output_period_ms > 0);
+
+ if (!output->IsActive()) {
+ // TODO(eladalon): We may want to remove the IsActive method. Otherwise
+ // we probably want to be consistent and terminate any existing output.
+ return false;
+ }
+
+ const int64_t timestamp_us = rtc::TimeMillis() * 1000;
+ const int64_t utc_time_us = rtc::TimeUTCMillis() * 1000;
+ RTC_LOG(LS_INFO) << "Starting WebRTC event log. (Timestamp, UTC) = ("
+ << timestamp_us << ", " << utc_time_us << ").";
+
+ RTC_DCHECK_RUN_ON(&logging_state_checker_);
+ logging_state_started_ = true;
+ // Binding to `this` is safe because `this` outlives the `task_queue_`.
+ task_queue_->PostTask([this, output_period_ms, timestamp_us, utc_time_us,
+ output = std::move(output)]() mutable {
+ RTC_DCHECK_RUN_ON(task_queue_.get());
+ RTC_DCHECK(output->IsActive());
+ output_period_ms_ = output_period_ms;
+ event_output_ = std::move(output);
+ num_config_events_written_ = 0;
+ WriteToOutput(event_encoder_->EncodeLogStart(timestamp_us, utc_time_us));
+ LogEventsFromMemoryToOutput();
+ });
+
+ return true;
+}
+
+void RtcEventLogImpl::StopLogging() {
+ RTC_DLOG(LS_INFO) << "Stopping WebRTC event log.";
+ // TODO(danilchap): Do not block current thread waiting on the task queue.
+ // It might work for now, for current callers, but disallows caller to share
+ // threads with the `task_queue_`.
+ rtc::Event output_stopped;
+ StopLogging([&output_stopped]() { output_stopped.Set(); });
+ output_stopped.Wait(rtc::Event::kForever);
+
+ RTC_DLOG(LS_INFO) << "WebRTC event log successfully stopped.";
+}
+
+void RtcEventLogImpl::StopLogging(std::function<void()> callback) {
+ RTC_DCHECK_RUN_ON(&logging_state_checker_);
+ logging_state_started_ = false;
+ task_queue_->PostTask([this, callback] {
+ RTC_DCHECK_RUN_ON(task_queue_.get());
+ if (event_output_) {
+ RTC_DCHECK(event_output_->IsActive());
+ LogEventsFromMemoryToOutput();
+ }
+ StopLoggingInternal();
+ callback();
+ });
+}
+
+void RtcEventLogImpl::Log(std::unique_ptr<RtcEvent> event) {
+ RTC_CHECK(event);
+
+ // Binding to `this` is safe because `this` outlives the `task_queue_`.
+ task_queue_->PostTask([this, event = std::move(event)]() mutable {
+ RTC_DCHECK_RUN_ON(task_queue_.get());
+ LogToMemory(std::move(event));
+ if (event_output_)
+ ScheduleOutput();
+ });
+}
+
+void RtcEventLogImpl::ScheduleOutput() {
+ RTC_DCHECK(event_output_ && event_output_->IsActive());
+ if (history_.size() >= max_events_in_history_) {
+ // We have to emergency drain the buffer. We can't wait for the scheduled
+ // output task because there might be other event incoming before that.
+ LogEventsFromMemoryToOutput();
+ return;
+ }
+
+ RTC_DCHECK(output_period_ms_.has_value());
+ if (*output_period_ms_ == kImmediateOutput) {
+ // We are already on the `task_queue_` so there is no reason to post a task
+ // if we want to output immediately.
+ LogEventsFromMemoryToOutput();
+ return;
+ }
+
+ if (!output_scheduled_) {
+ output_scheduled_ = true;
+ // Binding to `this` is safe because `this` outlives the `task_queue_`.
+ auto output_task = [this]() {
+ RTC_DCHECK_RUN_ON(task_queue_.get());
+ if (event_output_) {
+ RTC_DCHECK(event_output_->IsActive());
+ LogEventsFromMemoryToOutput();
+ }
+ output_scheduled_ = false;
+ };
+ const int64_t now_ms = rtc::TimeMillis();
+ const int64_t time_since_output_ms = now_ms - last_output_ms_;
+ const uint32_t delay = rtc::SafeClamp(
+ *output_period_ms_ - time_since_output_ms, 0, *output_period_ms_);
+ task_queue_->PostDelayedTask(std::move(output_task),
+ TimeDelta::Millis(delay));
+ }
+}
+
+void RtcEventLogImpl::LogToMemory(std::unique_ptr<RtcEvent> event) {
+ std::deque<std::unique_ptr<RtcEvent>>& container =
+ event->IsConfigEvent() ? config_history_ : history_;
+ const size_t container_max_size = event->IsConfigEvent()
+ ? max_config_events_in_history_
+ : max_events_in_history_;
+
+ if (container.size() >= container_max_size) {
+ RTC_DCHECK(!event_output_); // Shouldn't lose events if we have an output.
+ container.pop_front();
+ }
+ container.push_back(std::move(event));
+}
+
+void RtcEventLogImpl::LogEventsFromMemoryToOutput() {
+ RTC_DCHECK(event_output_ && event_output_->IsActive());
+ last_output_ms_ = rtc::TimeMillis();
+
+ // Serialize all stream configurations that haven't already been written to
+ // this output. `num_config_events_written_` is used to track which configs we
+ // have already written. (Note that the config may have been written to
+ // previous outputs; configs are not discarded.)
+ std::string encoded_configs;
+ RTC_DCHECK_LE(num_config_events_written_, config_history_.size());
+ if (num_config_events_written_ < config_history_.size()) {
+ const auto begin = config_history_.begin() + num_config_events_written_;
+ const auto end = config_history_.end();
+ encoded_configs = event_encoder_->EncodeBatch(begin, end);
+ num_config_events_written_ = config_history_.size();
+ }
+
+ // Serialize the events in the event queue. Note that the write may fail,
+ // for example if we are writing to a file and have reached the maximum limit.
+ // We don't get any feedback if this happens, so we still remove the events
+ // from the event log history. This is normally not a problem, but if another
+ // log is started immediately after the first one becomes full, then one
+ // cannot rely on the second log to contain everything that isn't in the first
+ // log; one batch of events might be missing.
+ std::string encoded_history =
+ event_encoder_->EncodeBatch(history_.begin(), history_.end());
+ history_.clear();
+
+ WriteConfigsAndHistoryToOutput(encoded_configs, encoded_history);
+}
+
+void RtcEventLogImpl::WriteConfigsAndHistoryToOutput(
+ absl::string_view encoded_configs,
+ absl::string_view encoded_history) {
+ // This function is used to merge the strings instead of calling the output
+ // object twice with small strings. The function also avoids copying any
+ // strings in the typical case where there are no config events.
+ if (encoded_configs.empty()) {
+ WriteToOutput(encoded_history); // Typical case.
+ } else if (encoded_history.empty()) {
+ WriteToOutput(encoded_configs); // Very unusual case.
+ } else {
+ std::string s;
+ s.reserve(encoded_configs.size() + encoded_history.size());
+ s.append(encoded_configs.data(), encoded_configs.size());
+ s.append(encoded_history.data(), encoded_history.size());
+ WriteToOutput(s);
+ }
+}
+
+void RtcEventLogImpl::StopOutput() {
+ event_output_.reset();
+}
+
+void RtcEventLogImpl::StopLoggingInternal() {
+ if (event_output_) {
+ RTC_DCHECK(event_output_->IsActive());
+ const int64_t timestamp_us = rtc::TimeMillis() * 1000;
+ event_output_->Write(event_encoder_->EncodeLogEnd(timestamp_us));
+ }
+ StopOutput();
+}
+
+void RtcEventLogImpl::WriteToOutput(absl::string_view output_string) {
+ RTC_DCHECK(event_output_ && event_output_->IsActive());
+ if (!event_output_->Write(output_string)) {
+ RTC_LOG(LS_ERROR) << "Failed to write RTC event to output.";
+ // The first failure closes the output.
+ RTC_DCHECK(!event_output_->IsActive());
+ StopOutput(); // Clean-up.
+ return;
+ }
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/logging/rtc_event_log/rtc_event_log_impl.h b/third_party/libwebrtc/logging/rtc_event_log/rtc_event_log_impl.h
new file mode 100644
index 0000000000..6ffed0ad22
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/rtc_event_log_impl.h
@@ -0,0 +1,114 @@
+/*
+ * 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_RTC_EVENT_LOG_IMPL_H_
+#define LOGGING_RTC_EVENT_LOG_RTC_EVENT_LOG_IMPL_H_
+
+#include <cstddef>
+#include <cstdint>
+#include <deque>
+#include <memory>
+#include <string>
+
+#include "absl/strings/string_view.h"
+#include "absl/types/optional.h"
+#include "api/rtc_event_log/rtc_event.h"
+#include "api/rtc_event_log/rtc_event_log.h"
+#include "api/rtc_event_log_output.h"
+#include "api/sequence_checker.h"
+#include "api/task_queue/task_queue_factory.h"
+#include "logging/rtc_event_log/encoder/rtc_event_log_encoder.h"
+#include "rtc_base/system/no_unique_address.h"
+#include "rtc_base/task_queue.h"
+#include "rtc_base/thread_annotations.h"
+
+namespace webrtc {
+
+class RtcEventLogImpl final : public RtcEventLog {
+ public:
+ // The max number of events that the history can store.
+ static constexpr size_t kMaxEventsInHistory = 10000;
+ // The max number of events that the config history can store.
+ // The config-history is supposed to be unbounded, but needs to have some
+ // bound to prevent an attack via unreasonable memory use.
+ static constexpr size_t kMaxEventsInConfigHistory = 1000;
+
+ RtcEventLogImpl(
+ std::unique_ptr<RtcEventLogEncoder> encoder,
+ TaskQueueFactory* task_queue_factory,
+ size_t max_events_in_history = kMaxEventsInHistory,
+ size_t max_config_events_in_history = kMaxEventsInConfigHistory);
+ RtcEventLogImpl(const RtcEventLogImpl&) = delete;
+ RtcEventLogImpl& operator=(const RtcEventLogImpl&) = delete;
+
+ ~RtcEventLogImpl() override;
+
+ static std::unique_ptr<RtcEventLogEncoder> CreateEncoder(
+ EncodingType encoding_type);
+
+ // TODO(eladalon): We should change these name to reflect that what we're
+ // actually starting/stopping is the output of the log, not the log itself.
+ bool StartLogging(std::unique_ptr<RtcEventLogOutput> output,
+ int64_t output_period_ms) override;
+ void StopLogging() override;
+ void StopLogging(std::function<void()> callback) override;
+
+ void Log(std::unique_ptr<RtcEvent> event) override;
+
+ private:
+ void LogToMemory(std::unique_ptr<RtcEvent> event) RTC_RUN_ON(task_queue_);
+ void LogEventsFromMemoryToOutput() RTC_RUN_ON(task_queue_);
+
+ void StopOutput() RTC_RUN_ON(task_queue_);
+
+ void WriteConfigsAndHistoryToOutput(absl::string_view encoded_configs,
+ absl::string_view encoded_history)
+ RTC_RUN_ON(task_queue_);
+ void WriteToOutput(absl::string_view output_string) RTC_RUN_ON(task_queue_);
+
+ void StopLoggingInternal() RTC_RUN_ON(task_queue_);
+
+ void ScheduleOutput() RTC_RUN_ON(task_queue_);
+
+ // Max size of event history.
+ const size_t max_events_in_history_;
+
+ // Max size of config event history.
+ const size_t max_config_events_in_history_;
+
+ // History containing all past configuration events.
+ std::deque<std::unique_ptr<RtcEvent>> config_history_
+ RTC_GUARDED_BY(*task_queue_);
+
+ // History containing the most recent (non-configuration) events (~10s).
+ std::deque<std::unique_ptr<RtcEvent>> history_ RTC_GUARDED_BY(*task_queue_);
+
+ std::unique_ptr<RtcEventLogEncoder> event_encoder_
+ RTC_GUARDED_BY(*task_queue_);
+ std::unique_ptr<RtcEventLogOutput> event_output_ RTC_GUARDED_BY(*task_queue_);
+
+ size_t num_config_events_written_ RTC_GUARDED_BY(*task_queue_);
+ absl::optional<int64_t> output_period_ms_ RTC_GUARDED_BY(*task_queue_);
+ int64_t last_output_ms_ RTC_GUARDED_BY(*task_queue_);
+ bool output_scheduled_ RTC_GUARDED_BY(*task_queue_);
+
+ RTC_NO_UNIQUE_ADDRESS SequenceChecker logging_state_checker_;
+ bool logging_state_started_ RTC_GUARDED_BY(logging_state_checker_);
+
+ // Since we are posting tasks bound to `this`, it is critical that the event
+ // log and its members outlive `task_queue_`. Keep the `task_queue_`
+ // last to ensure it destructs first, or else tasks living on the queue might
+ // access other members after they've been torn down.
+ std::unique_ptr<rtc::TaskQueue> task_queue_;
+};
+
+} // namespace webrtc
+
+#endif // LOGGING_RTC_EVENT_LOG_RTC_EVENT_LOG_IMPL_H_
diff --git a/third_party/libwebrtc/logging/rtc_event_log/rtc_event_log_impl_unittest.cc b/third_party/libwebrtc/logging/rtc_event_log/rtc_event_log_impl_unittest.cc
new file mode 100644
index 0000000000..d32af8fe23
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/rtc_event_log_impl_unittest.cc
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2023 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/rtc_event_log_impl.h"
+
+#include <utility>
+#include <vector>
+
+#include "test/gmock.h"
+#include "test/gtest.h"
+#include "test/time_controller/simulated_time_controller.h"
+
+namespace webrtc {
+namespace {
+
+using ::testing::InSequence;
+using ::testing::Mock;
+using ::testing::Property;
+using ::testing::Ref;
+using ::testing::Return;
+using ::testing::StrEq;
+
+class MockEventEncoder : public RtcEventLogEncoder {
+ public:
+ MOCK_METHOD(std::string,
+ EncodeLogStart,
+ (int64_t /*timestamp_us*/, int64_t /*utc_time_us*/),
+ (override));
+ MOCK_METHOD(std::string,
+ EncodeLogEnd,
+ (int64_t /*timestamp_us*/),
+ (override));
+ MOCK_METHOD(std::string, OnEncode, (const RtcEvent&), ());
+ std::string EncodeBatch(
+ std::deque<std::unique_ptr<RtcEvent>>::const_iterator a,
+ std::deque<std::unique_ptr<RtcEvent>>::const_iterator b) override {
+ std::string result;
+ while (a != b) {
+ result += OnEncode(**a);
+ ++a;
+ }
+ return result;
+ }
+};
+
+class FakeOutput : public RtcEventLogOutput {
+ public:
+ explicit FakeOutput(std::string& written_data)
+ : written_data_(written_data) {}
+ bool IsActive() const { return true; }
+ bool Write(absl::string_view data) override {
+ written_data_.append(std::string(data));
+ return true;
+ }
+ void Flush() override {}
+
+ private:
+ std::string& written_data_;
+};
+
+class FakeEvent : public RtcEvent {
+ public:
+ Type GetType() const override { return RtcEvent::Type::FakeEvent; }
+ bool IsConfigEvent() const override { return false; }
+};
+
+class FakeConfigEvent : public RtcEvent {
+ public:
+ Type GetType() const override { return RtcEvent::Type::FakeEvent; }
+ bool IsConfigEvent() const override { return true; }
+};
+
+class RtcEventLogImplTest : public ::testing::Test {
+ public:
+ static constexpr size_t kMaxEventsInHistory = 2;
+ static constexpr size_t kMaxEventsInConfigHistory = 3;
+ static constexpr TimeDelta kOutputPeriod = TimeDelta::Seconds(2);
+ static constexpr Timestamp kStartTime = Timestamp::Seconds(1);
+
+ GlobalSimulatedTimeController time_controller_{kStartTime};
+ std::unique_ptr<MockEventEncoder> encoder_ =
+ std::make_unique<MockEventEncoder>();
+ MockEventEncoder* encoder_ptr_ = encoder_.get();
+ std::unique_ptr<FakeOutput> output_ =
+ std::make_unique<FakeOutput>(written_data_);
+ FakeOutput* output_ptr_ = output_.get();
+ RtcEventLogImpl event_log_{std::move(encoder_),
+ time_controller_.GetTaskQueueFactory(),
+ kMaxEventsInHistory, kMaxEventsInConfigHistory};
+ std::string written_data_;
+};
+
+TEST_F(RtcEventLogImplTest, WritesHeaderAndEventsAndTrailer) {
+ EXPECT_CALL(*encoder_ptr_, EncodeLogStart(kStartTime.us(), kStartTime.us()))
+ .WillOnce(Return("start"));
+ EXPECT_CALL(*encoder_ptr_, EncodeLogEnd(kStartTime.us()))
+ .WillOnce(Return("stop"));
+ EXPECT_CALL(*encoder_ptr_, OnEncode(Property(&RtcEvent::IsConfigEvent, true)))
+ .WillOnce(Return("config"));
+ EXPECT_CALL(*encoder_ptr_,
+ OnEncode(Property(&RtcEvent::IsConfigEvent, false)))
+ .WillOnce(Return("event"));
+ event_log_.StartLogging(std::move(output_), kOutputPeriod.ms());
+ event_log_.Log(std::make_unique<FakeEvent>());
+ event_log_.Log(std::make_unique<FakeConfigEvent>());
+ event_log_.StopLogging();
+ Mock::VerifyAndClearExpectations(encoder_ptr_);
+ EXPECT_TRUE(written_data_ == "startconfigeventstop" ||
+ written_data_ == "starteventconfigstop");
+}
+
+TEST_F(RtcEventLogImplTest, KeepsMostRecentEventsOnStart) {
+ auto e2 = std::make_unique<FakeEvent>();
+ RtcEvent* e2_ptr = e2.get();
+ auto e3 = std::make_unique<FakeEvent>();
+ RtcEvent* e3_ptr = e3.get();
+ event_log_.Log(std::make_unique<FakeEvent>());
+ event_log_.Log(std::move(e2));
+ event_log_.Log(std::move(e3));
+ InSequence s;
+ EXPECT_CALL(*encoder_ptr_, OnEncode(Ref(*e2_ptr)));
+ EXPECT_CALL(*encoder_ptr_, OnEncode(Ref(*e3_ptr)));
+ event_log_.StartLogging(std::move(output_), kOutputPeriod.ms());
+ time_controller_.AdvanceTime(TimeDelta::Zero());
+ Mock::VerifyAndClearExpectations(encoder_ptr_);
+}
+
+TEST_F(RtcEventLogImplTest, EncodesEventsOnHistoryFullPostponesLastEncode) {
+ auto e1 = std::make_unique<FakeEvent>();
+ RtcEvent* e1_ptr = e1.get();
+ auto e2 = std::make_unique<FakeEvent>();
+ RtcEvent* e2_ptr = e2.get();
+ auto e3 = std::make_unique<FakeEvent>();
+ RtcEvent* e3_ptr = e3.get();
+ event_log_.StartLogging(std::move(output_), kOutputPeriod.ms());
+ time_controller_.AdvanceTime(TimeDelta::Zero());
+ event_log_.Log(std::move(e1));
+ event_log_.Log(std::move(e2));
+ // Overflows and causes immediate output, and eventual output after the output
+ // period has passed.
+ event_log_.Log(std::move(e3));
+ InSequence s;
+ EXPECT_CALL(*encoder_ptr_, OnEncode(Ref(*e1_ptr)));
+ EXPECT_CALL(*encoder_ptr_, OnEncode(Ref(*e2_ptr)));
+ time_controller_.AdvanceTime(TimeDelta::Zero());
+ EXPECT_CALL(*encoder_ptr_, OnEncode(Ref(*e3_ptr)));
+ time_controller_.AdvanceTime(kOutputPeriod);
+ Mock::VerifyAndClearExpectations(encoder_ptr_);
+}
+
+TEST_F(RtcEventLogImplTest, RewritesConfigEventsOnlyOnRestart) {
+ event_log_.StartLogging(std::make_unique<FakeOutput>(written_data_),
+ kOutputPeriod.ms());
+ event_log_.Log(std::make_unique<FakeConfigEvent>());
+ event_log_.Log(std::make_unique<FakeEvent>());
+ event_log_.StopLogging();
+ EXPECT_CALL(*encoder_ptr_,
+ OnEncode(Property(&RtcEvent::IsConfigEvent, true)));
+ EXPECT_CALL(*encoder_ptr_,
+ OnEncode(Property(&RtcEvent::IsConfigEvent, false)))
+ .Times(0);
+ event_log_.StartLogging(std::move(output_), kOutputPeriod.ms());
+ time_controller_.AdvanceTime(TimeDelta::Zero());
+ Mock::VerifyAndClearExpectations(encoder_ptr_);
+}
+
+TEST_F(RtcEventLogImplTest, SchedulesWriteAfterOutputDurationPassed) {
+ event_log_.StartLogging(std::make_unique<FakeOutput>(written_data_),
+ kOutputPeriod.ms());
+ event_log_.Log(std::make_unique<FakeConfigEvent>());
+ event_log_.Log(std::make_unique<FakeEvent>());
+ EXPECT_CALL(*encoder_ptr_,
+ OnEncode(Property(&RtcEvent::IsConfigEvent, true)));
+ EXPECT_CALL(*encoder_ptr_,
+ OnEncode(Property(&RtcEvent::IsConfigEvent, false)));
+ time_controller_.AdvanceTime(kOutputPeriod);
+ Mock::VerifyAndClearExpectations(encoder_ptr_);
+}
+
+} // namespace
+} // namespace webrtc
diff --git a/third_party/libwebrtc/logging/rtc_event_log/rtc_event_log_parser.cc b/third_party/libwebrtc/logging/rtc_event_log/rtc_event_log_parser.cc
new file mode 100644
index 0000000000..a793efb5a0
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/rtc_event_log_parser.cc
@@ -0,0 +1,3635 @@
+/*
+ * Copyright (c) 2016 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/rtc_event_log_parser.h"
+
+#include <stdint.h>
+#include <string.h>
+
+#include <algorithm>
+#include <limits>
+#include <map>
+#include <utility>
+
+#include "absl/memory/memory.h"
+#include "absl/strings/string_view.h"
+#include "absl/types/optional.h"
+#include "api/network_state_predictor.h"
+#include "api/rtc_event_log/rtc_event_log.h"
+#include "api/rtp_headers.h"
+#include "api/rtp_parameters.h"
+#include "logging/rtc_event_log/encoder/blob_encoding.h"
+#include "logging/rtc_event_log/encoder/delta_encoding.h"
+#include "logging/rtc_event_log/encoder/rtc_event_log_encoder_common.h"
+#include "logging/rtc_event_log/encoder/var_int.h"
+#include "logging/rtc_event_log/events/logged_rtp_rtcp.h"
+#include "logging/rtc_event_log/rtc_event_processor.h"
+#include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor.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"
+#include "modules/rtp_rtcp/source/rtp_packet_received.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/copy_on_write_buffer.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/numerics/safe_conversions.h"
+#include "rtc_base/numerics/sequence_number_unwrapper.h"
+#include "rtc_base/protobuf_utils.h"
+#include "rtc_base/system/file_wrapper.h"
+
+// These macros were added to convert existing code using RTC_CHECKs
+// to returning a Status object instead. Macros are necessary (over
+// e.g. helper functions) since we want to return from the current
+// function.
+#define RTC_PARSE_CHECK_OR_RETURN(X) \
+ do { \
+ if (!(X)) \
+ return ParsedRtcEventLog::ParseStatus::Error(#X, __FILE__, __LINE__); \
+ } while (0)
+
+#define RTC_PARSE_CHECK_OR_RETURN_MESSAGE(X, M) \
+ do { \
+ if (!(X)) \
+ return ParsedRtcEventLog::ParseStatus::Error((M), __FILE__, __LINE__); \
+ } while (0)
+
+#define RTC_PARSE_CHECK_OR_RETURN_OP(OP, X, Y) \
+ do { \
+ if (!((X)OP(Y))) \
+ return ParsedRtcEventLog::ParseStatus::Error(#X #OP #Y, __FILE__, \
+ __LINE__); \
+ } while (0)
+
+#define RTC_PARSE_CHECK_OR_RETURN_EQ(X, Y) \
+ RTC_PARSE_CHECK_OR_RETURN_OP(==, X, Y)
+
+#define RTC_PARSE_CHECK_OR_RETURN_NE(X, Y) \
+ RTC_PARSE_CHECK_OR_RETURN_OP(!=, X, Y)
+
+#define RTC_PARSE_CHECK_OR_RETURN_LT(X, Y) RTC_PARSE_CHECK_OR_RETURN_OP(<, X, Y)
+
+#define RTC_PARSE_CHECK_OR_RETURN_LE(X, Y) \
+ RTC_PARSE_CHECK_OR_RETURN_OP(<=, X, Y)
+
+#define RTC_PARSE_CHECK_OR_RETURN_GT(X, Y) RTC_PARSE_CHECK_OR_RETURN_OP(>, X, Y)
+
+#define RTC_PARSE_CHECK_OR_RETURN_GE(X, Y) \
+ RTC_PARSE_CHECK_OR_RETURN_OP(>=, X, Y)
+
+#define RTC_PARSE_WARN_AND_RETURN_SUCCESS_IF(X, M) \
+ do { \
+ if (X) { \
+ RTC_LOG(LS_WARNING) << (M); \
+ return ParsedRtcEventLog::ParseStatus::Success(); \
+ } \
+ } while (0)
+
+#define RTC_RETURN_IF_ERROR(X) \
+ do { \
+ const ParsedRtcEventLog::ParseStatus _rtc_parse_status(X); \
+ if (!_rtc_parse_status.ok()) { \
+ return _rtc_parse_status; \
+ } \
+ } while (0)
+
+using webrtc_event_logging::ToSigned;
+using webrtc_event_logging::ToUnsigned;
+
+namespace webrtc {
+
+namespace {
+constexpr int64_t kMaxLogSize = 250000000;
+
+constexpr size_t kIpv4Overhead = 20;
+constexpr size_t kIpv6Overhead = 40;
+constexpr size_t kUdpOverhead = 8;
+constexpr size_t kSrtpOverhead = 10;
+constexpr size_t kStunOverhead = 4;
+constexpr uint16_t kDefaultOverhead =
+ kUdpOverhead + kSrtpOverhead + kIpv4Overhead;
+
+constexpr char kIncompleteLogError[] =
+ "Could not parse the entire log. Only the beginning will be used.";
+
+struct MediaStreamInfo {
+ MediaStreamInfo() = default;
+ MediaStreamInfo(LoggedMediaType media_type, bool rtx)
+ : media_type(media_type), rtx(rtx) {}
+ LoggedMediaType media_type = LoggedMediaType::kUnknown;
+ bool rtx = false;
+ SeqNumUnwrapper<uint32_t> unwrap_capture_ticks;
+};
+
+template <typename Iterable>
+void AddRecvStreamInfos(std::map<uint32_t, MediaStreamInfo>* streams,
+ const Iterable configs,
+ LoggedMediaType media_type) {
+ for (auto& conf : configs) {
+ streams->insert({conf.config.remote_ssrc, {media_type, false}});
+ if (conf.config.rtx_ssrc != 0)
+ streams->insert({conf.config.rtx_ssrc, {media_type, true}});
+ }
+}
+template <typename Iterable>
+void AddSendStreamInfos(std::map<uint32_t, MediaStreamInfo>* streams,
+ const Iterable configs,
+ LoggedMediaType media_type) {
+ for (auto& conf : configs) {
+ streams->insert({conf.config.local_ssrc, {media_type, false}});
+ if (conf.config.rtx_ssrc != 0)
+ streams->insert({conf.config.rtx_ssrc, {media_type, true}});
+ }
+}
+struct OverheadChangeEvent {
+ Timestamp timestamp;
+ uint16_t overhead;
+};
+std::vector<OverheadChangeEvent> GetOverheadChangingEvents(
+ const std::vector<InferredRouteChangeEvent>& route_changes,
+ PacketDirection direction) {
+ std::vector<OverheadChangeEvent> overheads;
+ for (auto& event : route_changes) {
+ uint16_t new_overhead = direction == PacketDirection::kIncomingPacket
+ ? event.return_overhead
+ : event.send_overhead;
+ if (overheads.empty() || new_overhead != overheads.back().overhead) {
+ overheads.push_back({event.log_time, new_overhead});
+ }
+ }
+ return overheads;
+}
+
+bool IdenticalRtcpContents(const std::vector<uint8_t>& last_rtcp,
+ absl::string_view new_rtcp) {
+ if (last_rtcp.size() != new_rtcp.size())
+ return false;
+ return memcmp(last_rtcp.data(), new_rtcp.data(), new_rtcp.size()) == 0;
+}
+
+// Conversion functions for legacy wire format.
+RtcpMode GetRuntimeRtcpMode(rtclog::VideoReceiveConfig::RtcpMode rtcp_mode) {
+ switch (rtcp_mode) {
+ case rtclog::VideoReceiveConfig::RTCP_COMPOUND:
+ return RtcpMode::kCompound;
+ case rtclog::VideoReceiveConfig::RTCP_REDUCEDSIZE:
+ return RtcpMode::kReducedSize;
+ }
+ RTC_DCHECK_NOTREACHED();
+ return RtcpMode::kOff;
+}
+
+BandwidthUsage GetRuntimeDetectorState(
+ rtclog::DelayBasedBweUpdate::DetectorState detector_state) {
+ switch (detector_state) {
+ case rtclog::DelayBasedBweUpdate::BWE_NORMAL:
+ return BandwidthUsage::kBwNormal;
+ case rtclog::DelayBasedBweUpdate::BWE_UNDERUSING:
+ return BandwidthUsage::kBwUnderusing;
+ case rtclog::DelayBasedBweUpdate::BWE_OVERUSING:
+ return BandwidthUsage::kBwOverusing;
+ }
+ RTC_DCHECK_NOTREACHED();
+ return BandwidthUsage::kBwNormal;
+}
+
+IceCandidatePairConfigType GetRuntimeIceCandidatePairConfigType(
+ rtclog::IceCandidatePairConfig::IceCandidatePairConfigType type) {
+ switch (type) {
+ case rtclog::IceCandidatePairConfig::ADDED:
+ return IceCandidatePairConfigType::kAdded;
+ case rtclog::IceCandidatePairConfig::UPDATED:
+ return IceCandidatePairConfigType::kUpdated;
+ case rtclog::IceCandidatePairConfig::DESTROYED:
+ return IceCandidatePairConfigType::kDestroyed;
+ case rtclog::IceCandidatePairConfig::SELECTED:
+ return IceCandidatePairConfigType::kSelected;
+ }
+ RTC_DCHECK_NOTREACHED();
+ return IceCandidatePairConfigType::kAdded;
+}
+
+IceCandidateType GetRuntimeIceCandidateType(
+ rtclog::IceCandidatePairConfig::IceCandidateType type) {
+ switch (type) {
+ case rtclog::IceCandidatePairConfig::LOCAL:
+ return IceCandidateType::kLocal;
+ case rtclog::IceCandidatePairConfig::STUN:
+ return IceCandidateType::kStun;
+ case rtclog::IceCandidatePairConfig::PRFLX:
+ return IceCandidateType::kPrflx;
+ case rtclog::IceCandidatePairConfig::RELAY:
+ return IceCandidateType::kRelay;
+ case rtclog::IceCandidatePairConfig::UNKNOWN_CANDIDATE_TYPE:
+ return IceCandidateType::kUnknown;
+ }
+ RTC_DCHECK_NOTREACHED();
+ return IceCandidateType::kUnknown;
+}
+
+IceCandidatePairProtocol GetRuntimeIceCandidatePairProtocol(
+ rtclog::IceCandidatePairConfig::Protocol protocol) {
+ switch (protocol) {
+ case rtclog::IceCandidatePairConfig::UDP:
+ return IceCandidatePairProtocol::kUdp;
+ case rtclog::IceCandidatePairConfig::TCP:
+ return IceCandidatePairProtocol::kTcp;
+ case rtclog::IceCandidatePairConfig::SSLTCP:
+ return IceCandidatePairProtocol::kSsltcp;
+ case rtclog::IceCandidatePairConfig::TLS:
+ return IceCandidatePairProtocol::kTls;
+ case rtclog::IceCandidatePairConfig::UNKNOWN_PROTOCOL:
+ return IceCandidatePairProtocol::kUnknown;
+ }
+ RTC_DCHECK_NOTREACHED();
+ return IceCandidatePairProtocol::kUnknown;
+}
+
+IceCandidatePairAddressFamily GetRuntimeIceCandidatePairAddressFamily(
+ rtclog::IceCandidatePairConfig::AddressFamily address_family) {
+ switch (address_family) {
+ case rtclog::IceCandidatePairConfig::IPV4:
+ return IceCandidatePairAddressFamily::kIpv4;
+ case rtclog::IceCandidatePairConfig::IPV6:
+ return IceCandidatePairAddressFamily::kIpv6;
+ case rtclog::IceCandidatePairConfig::UNKNOWN_ADDRESS_FAMILY:
+ return IceCandidatePairAddressFamily::kUnknown;
+ }
+ RTC_DCHECK_NOTREACHED();
+ return IceCandidatePairAddressFamily::kUnknown;
+}
+
+IceCandidateNetworkType GetRuntimeIceCandidateNetworkType(
+ rtclog::IceCandidatePairConfig::NetworkType network_type) {
+ switch (network_type) {
+ case rtclog::IceCandidatePairConfig::ETHERNET:
+ return IceCandidateNetworkType::kEthernet;
+ case rtclog::IceCandidatePairConfig::LOOPBACK:
+ return IceCandidateNetworkType::kLoopback;
+ case rtclog::IceCandidatePairConfig::WIFI:
+ return IceCandidateNetworkType::kWifi;
+ case rtclog::IceCandidatePairConfig::VPN:
+ return IceCandidateNetworkType::kVpn;
+ case rtclog::IceCandidatePairConfig::CELLULAR:
+ return IceCandidateNetworkType::kCellular;
+ case rtclog::IceCandidatePairConfig::UNKNOWN_NETWORK_TYPE:
+ return IceCandidateNetworkType::kUnknown;
+ }
+ RTC_DCHECK_NOTREACHED();
+ return IceCandidateNetworkType::kUnknown;
+}
+
+IceCandidatePairEventType GetRuntimeIceCandidatePairEventType(
+ rtclog::IceCandidatePairEvent::IceCandidatePairEventType type) {
+ switch (type) {
+ case rtclog::IceCandidatePairEvent::CHECK_SENT:
+ return IceCandidatePairEventType::kCheckSent;
+ case rtclog::IceCandidatePairEvent::CHECK_RECEIVED:
+ return IceCandidatePairEventType::kCheckReceived;
+ case rtclog::IceCandidatePairEvent::CHECK_RESPONSE_SENT:
+ return IceCandidatePairEventType::kCheckResponseSent;
+ case rtclog::IceCandidatePairEvent::CHECK_RESPONSE_RECEIVED:
+ return IceCandidatePairEventType::kCheckResponseReceived;
+ }
+ RTC_DCHECK_NOTREACHED();
+ return IceCandidatePairEventType::kCheckSent;
+}
+
+VideoCodecType GetRuntimeCodecType(rtclog2::FrameDecodedEvents::Codec codec) {
+ switch (codec) {
+ case rtclog2::FrameDecodedEvents::CODEC_GENERIC:
+ return VideoCodecType::kVideoCodecGeneric;
+ case rtclog2::FrameDecodedEvents::CODEC_VP8:
+ return VideoCodecType::kVideoCodecVP8;
+ case rtclog2::FrameDecodedEvents::CODEC_VP9:
+ return VideoCodecType::kVideoCodecVP9;
+ case rtclog2::FrameDecodedEvents::CODEC_AV1:
+ return VideoCodecType::kVideoCodecAV1;
+ case rtclog2::FrameDecodedEvents::CODEC_H264:
+ return VideoCodecType::kVideoCodecH264;
+ case rtclog2::FrameDecodedEvents::CODEC_UNKNOWN:
+ RTC_LOG(LS_ERROR) << "Unknown codec type. Assuming "
+ "VideoCodecType::kVideoCodecMultiplex";
+ return VideoCodecType::kVideoCodecMultiplex;
+ }
+ RTC_DCHECK_NOTREACHED();
+ return VideoCodecType::kVideoCodecMultiplex;
+}
+
+ParsedRtcEventLog::ParseStatus GetHeaderExtensions(
+ std::vector<RtpExtension>* header_extensions,
+ const RepeatedPtrField<rtclog::RtpHeaderExtension>&
+ proto_header_extensions) {
+ header_extensions->clear();
+ for (auto& p : proto_header_extensions) {
+ RTC_PARSE_CHECK_OR_RETURN(p.has_name());
+ RTC_PARSE_CHECK_OR_RETURN(p.has_id());
+ const std::string& name = p.name();
+ int id = p.id();
+ header_extensions->push_back(RtpExtension(name, id));
+ }
+ return ParsedRtcEventLog::ParseStatus::Success();
+}
+
+template <typename ProtoType, typename LoggedType>
+ParsedRtcEventLog::ParseStatus StoreRtpPackets(
+ const ProtoType& proto,
+ std::map<uint32_t, std::vector<LoggedType>>* rtp_packets_map) {
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_timestamp_ms());
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_marker());
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_payload_type());
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_sequence_number());
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_rtp_timestamp());
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_ssrc());
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_payload_size());
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_header_size());
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_padding_size());
+
+ // Base event
+ {
+ RTPHeader header;
+ header.markerBit = rtc::checked_cast<bool>(proto.marker());
+ header.payloadType = rtc::checked_cast<uint8_t>(proto.payload_type());
+ header.sequenceNumber =
+ rtc::checked_cast<uint16_t>(proto.sequence_number());
+ header.timestamp = rtc::checked_cast<uint32_t>(proto.rtp_timestamp());
+ header.ssrc = rtc::checked_cast<uint32_t>(proto.ssrc());
+ header.numCSRCs = 0; // TODO(terelius): Implement CSRC.
+ header.paddingLength = rtc::checked_cast<size_t>(proto.padding_size());
+ header.headerLength = rtc::checked_cast<size_t>(proto.header_size());
+ // TODO(terelius): Should we implement payload_type_frequency?
+ if (proto.has_transport_sequence_number()) {
+ header.extension.hasTransportSequenceNumber = true;
+ header.extension.transportSequenceNumber =
+ rtc::checked_cast<uint16_t>(proto.transport_sequence_number());
+ }
+ if (proto.has_transmission_time_offset()) {
+ header.extension.hasTransmissionTimeOffset = true;
+ header.extension.transmissionTimeOffset =
+ rtc::checked_cast<int32_t>(proto.transmission_time_offset());
+ }
+ if (proto.has_absolute_send_time()) {
+ header.extension.hasAbsoluteSendTime = true;
+ header.extension.absoluteSendTime =
+ rtc::checked_cast<uint32_t>(proto.absolute_send_time());
+ }
+ if (proto.has_video_rotation()) {
+ header.extension.hasVideoRotation = true;
+ header.extension.videoRotation = ConvertCVOByteToVideoRotation(
+ rtc::checked_cast<uint8_t>(proto.video_rotation()));
+ }
+ if (proto.has_audio_level()) {
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_voice_activity());
+ header.extension.hasAudioLevel = true;
+ header.extension.voiceActivity =
+ rtc::checked_cast<bool>(proto.voice_activity());
+ const uint8_t audio_level =
+ rtc::checked_cast<uint8_t>(proto.audio_level());
+ RTC_PARSE_CHECK_OR_RETURN_LE(audio_level, 0x7Fu);
+ header.extension.audioLevel = audio_level;
+ } else {
+ RTC_PARSE_CHECK_OR_RETURN(!proto.has_voice_activity());
+ }
+ (*rtp_packets_map)[header.ssrc].emplace_back(
+ Timestamp::Millis(proto.timestamp_ms()), header, proto.header_size(),
+ proto.payload_size() + header.headerLength + header.paddingLength);
+ }
+
+ const size_t number_of_deltas =
+ proto.has_number_of_deltas() ? proto.number_of_deltas() : 0u;
+ if (number_of_deltas == 0) {
+ return ParsedRtcEventLog::ParseStatus::Success();
+ }
+
+ // timestamp_ms (event)
+ std::vector<absl::optional<uint64_t>> timestamp_ms_values =
+ DecodeDeltas(proto.timestamp_ms_deltas(),
+ ToUnsigned(proto.timestamp_ms()), number_of_deltas);
+ RTC_PARSE_CHECK_OR_RETURN_EQ(timestamp_ms_values.size(), number_of_deltas);
+
+ // marker (RTP base)
+ std::vector<absl::optional<uint64_t>> marker_values =
+ DecodeDeltas(proto.marker_deltas(), proto.marker(), number_of_deltas);
+ RTC_PARSE_CHECK_OR_RETURN_EQ(marker_values.size(), number_of_deltas);
+
+ // payload_type (RTP base)
+ std::vector<absl::optional<uint64_t>> payload_type_values = DecodeDeltas(
+ proto.payload_type_deltas(), proto.payload_type(), number_of_deltas);
+ RTC_PARSE_CHECK_OR_RETURN_EQ(payload_type_values.size(), number_of_deltas);
+
+ // sequence_number (RTP base)
+ std::vector<absl::optional<uint64_t>> sequence_number_values =
+ DecodeDeltas(proto.sequence_number_deltas(), proto.sequence_number(),
+ number_of_deltas);
+ RTC_PARSE_CHECK_OR_RETURN_EQ(sequence_number_values.size(), number_of_deltas);
+
+ // rtp_timestamp (RTP base)
+ std::vector<absl::optional<uint64_t>> rtp_timestamp_values = DecodeDeltas(
+ proto.rtp_timestamp_deltas(), proto.rtp_timestamp(), number_of_deltas);
+ RTC_PARSE_CHECK_OR_RETURN_EQ(rtp_timestamp_values.size(), number_of_deltas);
+
+ // ssrc (RTP base)
+ std::vector<absl::optional<uint64_t>> ssrc_values =
+ DecodeDeltas(proto.ssrc_deltas(), proto.ssrc(), number_of_deltas);
+ RTC_PARSE_CHECK_OR_RETURN_EQ(ssrc_values.size(), number_of_deltas);
+
+ // payload_size (RTP base)
+ std::vector<absl::optional<uint64_t>> payload_size_values = DecodeDeltas(
+ proto.payload_size_deltas(), proto.payload_size(), number_of_deltas);
+ RTC_PARSE_CHECK_OR_RETURN_EQ(payload_size_values.size(), number_of_deltas);
+
+ // header_size (RTP base)
+ std::vector<absl::optional<uint64_t>> header_size_values = DecodeDeltas(
+ proto.header_size_deltas(), proto.header_size(), number_of_deltas);
+ RTC_PARSE_CHECK_OR_RETURN_EQ(header_size_values.size(), number_of_deltas);
+
+ // padding_size (RTP base)
+ std::vector<absl::optional<uint64_t>> padding_size_values = DecodeDeltas(
+ proto.padding_size_deltas(), proto.padding_size(), number_of_deltas);
+ RTC_PARSE_CHECK_OR_RETURN_EQ(padding_size_values.size(), number_of_deltas);
+
+ // transport_sequence_number (RTP extension)
+ std::vector<absl::optional<uint64_t>> transport_sequence_number_values;
+ {
+ const absl::optional<uint64_t> base_transport_sequence_number =
+ proto.has_transport_sequence_number()
+ ? proto.transport_sequence_number()
+ : absl::optional<uint64_t>();
+ transport_sequence_number_values =
+ DecodeDeltas(proto.transport_sequence_number_deltas(),
+ base_transport_sequence_number, number_of_deltas);
+ RTC_PARSE_CHECK_OR_RETURN_EQ(transport_sequence_number_values.size(),
+ number_of_deltas);
+ }
+
+ // transmission_time_offset (RTP extension)
+ std::vector<absl::optional<uint64_t>> transmission_time_offset_values;
+ {
+ const absl::optional<uint64_t> unsigned_base_transmission_time_offset =
+ proto.has_transmission_time_offset()
+ ? ToUnsigned(proto.transmission_time_offset())
+ : absl::optional<uint64_t>();
+ transmission_time_offset_values =
+ DecodeDeltas(proto.transmission_time_offset_deltas(),
+ unsigned_base_transmission_time_offset, number_of_deltas);
+ RTC_PARSE_CHECK_OR_RETURN_EQ(transmission_time_offset_values.size(),
+ number_of_deltas);
+ }
+
+ // absolute_send_time (RTP extension)
+ std::vector<absl::optional<uint64_t>> absolute_send_time_values;
+ {
+ const absl::optional<uint64_t> base_absolute_send_time =
+ proto.has_absolute_send_time() ? proto.absolute_send_time()
+ : absl::optional<uint64_t>();
+ absolute_send_time_values =
+ DecodeDeltas(proto.absolute_send_time_deltas(), base_absolute_send_time,
+ number_of_deltas);
+ RTC_PARSE_CHECK_OR_RETURN_EQ(absolute_send_time_values.size(),
+ number_of_deltas);
+ }
+
+ // video_rotation (RTP extension)
+ std::vector<absl::optional<uint64_t>> video_rotation_values;
+ {
+ const absl::optional<uint64_t> base_video_rotation =
+ proto.has_video_rotation() ? proto.video_rotation()
+ : absl::optional<uint64_t>();
+ video_rotation_values = DecodeDeltas(proto.video_rotation_deltas(),
+ base_video_rotation, number_of_deltas);
+ RTC_PARSE_CHECK_OR_RETURN_EQ(video_rotation_values.size(),
+ number_of_deltas);
+ }
+
+ // audio_level (RTP extension)
+ std::vector<absl::optional<uint64_t>> audio_level_values;
+ {
+ const absl::optional<uint64_t> base_audio_level =
+ proto.has_audio_level() ? proto.audio_level()
+ : absl::optional<uint64_t>();
+ audio_level_values = DecodeDeltas(proto.audio_level_deltas(),
+ base_audio_level, number_of_deltas);
+ RTC_PARSE_CHECK_OR_RETURN_EQ(audio_level_values.size(), number_of_deltas);
+ }
+
+ // voice_activity (RTP extension)
+ std::vector<absl::optional<uint64_t>> voice_activity_values;
+ {
+ const absl::optional<uint64_t> base_voice_activity =
+ proto.has_voice_activity() ? proto.voice_activity()
+ : absl::optional<uint64_t>();
+ voice_activity_values = DecodeDeltas(proto.voice_activity_deltas(),
+ base_voice_activity, number_of_deltas);
+ RTC_PARSE_CHECK_OR_RETURN_EQ(voice_activity_values.size(),
+ number_of_deltas);
+ }
+
+ // Populate events from decoded deltas
+ for (size_t i = 0; i < number_of_deltas; ++i) {
+ RTC_PARSE_CHECK_OR_RETURN(timestamp_ms_values[i].has_value());
+ RTC_PARSE_CHECK_OR_RETURN(marker_values[i].has_value());
+ RTC_PARSE_CHECK_OR_RETURN(payload_type_values[i].has_value());
+ RTC_PARSE_CHECK_OR_RETURN(sequence_number_values[i].has_value());
+ RTC_PARSE_CHECK_OR_RETURN(rtp_timestamp_values[i].has_value());
+ RTC_PARSE_CHECK_OR_RETURN(ssrc_values[i].has_value());
+ RTC_PARSE_CHECK_OR_RETURN(payload_size_values[i].has_value());
+ RTC_PARSE_CHECK_OR_RETURN(header_size_values[i].has_value());
+ RTC_PARSE_CHECK_OR_RETURN(padding_size_values[i].has_value());
+
+ int64_t timestamp_ms;
+ RTC_PARSE_CHECK_OR_RETURN(
+ ToSigned(timestamp_ms_values[i].value(), &timestamp_ms));
+
+ RTPHeader header;
+ header.markerBit = rtc::checked_cast<bool>(*marker_values[i]);
+ header.payloadType = rtc::checked_cast<uint8_t>(*payload_type_values[i]);
+ header.sequenceNumber =
+ rtc::checked_cast<uint16_t>(*sequence_number_values[i]);
+ header.timestamp = rtc::checked_cast<uint32_t>(*rtp_timestamp_values[i]);
+ header.ssrc = rtc::checked_cast<uint32_t>(*ssrc_values[i]);
+ header.numCSRCs = 0; // TODO(terelius): Implement CSRC.
+ header.paddingLength = rtc::checked_cast<size_t>(*padding_size_values[i]);
+ header.headerLength = rtc::checked_cast<size_t>(*header_size_values[i]);
+ // TODO(terelius): Should we implement payload_type_frequency?
+ if (transport_sequence_number_values.size() > i &&
+ transport_sequence_number_values[i].has_value()) {
+ header.extension.hasTransportSequenceNumber = true;
+ header.extension.transportSequenceNumber = rtc::checked_cast<uint16_t>(
+ transport_sequence_number_values[i].value());
+ }
+ if (transmission_time_offset_values.size() > i &&
+ transmission_time_offset_values[i].has_value()) {
+ header.extension.hasTransmissionTimeOffset = true;
+ int32_t transmission_time_offset;
+ RTC_PARSE_CHECK_OR_RETURN(
+ ToSigned(transmission_time_offset_values[i].value(),
+ &transmission_time_offset));
+ header.extension.transmissionTimeOffset = transmission_time_offset;
+ }
+ if (absolute_send_time_values.size() > i &&
+ absolute_send_time_values[i].has_value()) {
+ header.extension.hasAbsoluteSendTime = true;
+ header.extension.absoluteSendTime =
+ rtc::checked_cast<uint32_t>(absolute_send_time_values[i].value());
+ }
+ if (video_rotation_values.size() > i &&
+ video_rotation_values[i].has_value()) {
+ header.extension.hasVideoRotation = true;
+ header.extension.videoRotation = ConvertCVOByteToVideoRotation(
+ rtc::checked_cast<uint8_t>(video_rotation_values[i].value()));
+ }
+ if (audio_level_values.size() > i && audio_level_values[i].has_value()) {
+ RTC_PARSE_CHECK_OR_RETURN(voice_activity_values.size() > i &&
+ voice_activity_values[i].has_value());
+ header.extension.hasAudioLevel = true;
+ header.extension.voiceActivity =
+ rtc::checked_cast<bool>(voice_activity_values[i].value());
+ const uint8_t audio_level =
+ rtc::checked_cast<uint8_t>(audio_level_values[i].value());
+ RTC_PARSE_CHECK_OR_RETURN_LE(audio_level, 0x7Fu);
+ header.extension.audioLevel = audio_level;
+ } else {
+ RTC_PARSE_CHECK_OR_RETURN(voice_activity_values.size() <= i ||
+ !voice_activity_values[i].has_value());
+ }
+ (*rtp_packets_map)[header.ssrc].emplace_back(
+ Timestamp::Millis(timestamp_ms), header, header.headerLength,
+ payload_size_values[i].value() + header.headerLength +
+ header.paddingLength);
+ }
+ return ParsedRtcEventLog::ParseStatus::Success();
+}
+
+template <typename ProtoType, typename LoggedType>
+ParsedRtcEventLog::ParseStatus StoreRtcpPackets(
+ const ProtoType& proto,
+ std::vector<LoggedType>* rtcp_packets,
+ bool remove_duplicates) {
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_timestamp_ms());
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_raw_packet());
+
+ // TODO(terelius): Incoming RTCP may be delivered once for audio and once
+ // for video. As a work around, we remove the duplicated packets since they
+ // cause problems when analyzing the log or feeding it into the transport
+ // feedback adapter.
+ if (!remove_duplicates || rtcp_packets->empty() ||
+ !IdenticalRtcpContents(rtcp_packets->back().rtcp.raw_data,
+ proto.raw_packet())) {
+ // Base event
+ rtcp_packets->emplace_back(Timestamp::Millis(proto.timestamp_ms()),
+ proto.raw_packet());
+ }
+
+ const size_t number_of_deltas =
+ proto.has_number_of_deltas() ? proto.number_of_deltas() : 0u;
+ if (number_of_deltas == 0) {
+ return ParsedRtcEventLog::ParseStatus::Success();
+ }
+
+ // timestamp_ms
+ std::vector<absl::optional<uint64_t>> timestamp_ms_values =
+ DecodeDeltas(proto.timestamp_ms_deltas(),
+ ToUnsigned(proto.timestamp_ms()), number_of_deltas);
+ RTC_PARSE_CHECK_OR_RETURN_EQ(timestamp_ms_values.size(), number_of_deltas);
+
+ // raw_packet
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_raw_packet_blobs());
+ std::vector<absl::string_view> raw_packet_values =
+ DecodeBlobs(proto.raw_packet_blobs(), number_of_deltas);
+ RTC_PARSE_CHECK_OR_RETURN_EQ(raw_packet_values.size(), number_of_deltas);
+
+ // Populate events from decoded deltas
+ for (size_t i = 0; i < number_of_deltas; ++i) {
+ RTC_PARSE_CHECK_OR_RETURN(timestamp_ms_values[i].has_value());
+ int64_t timestamp_ms;
+ RTC_PARSE_CHECK_OR_RETURN(
+ ToSigned(timestamp_ms_values[i].value(), &timestamp_ms));
+
+ // TODO(terelius): Incoming RTCP may be delivered once for audio and once
+ // for video. As a work around, we remove the duplicated packets since they
+ // cause problems when analyzing the log or feeding it into the transport
+ // feedback adapter.
+ if (remove_duplicates && !rtcp_packets->empty() &&
+ IdenticalRtcpContents(rtcp_packets->back().rtcp.raw_data,
+ raw_packet_values[i])) {
+ continue;
+ }
+ std::string data(raw_packet_values[i]);
+ rtcp_packets->emplace_back(Timestamp::Millis(timestamp_ms), data);
+ }
+ return ParsedRtcEventLog::ParseStatus::Success();
+}
+
+ParsedRtcEventLog::ParseStatus StoreRtcpBlocks(
+ int64_t timestamp_us,
+ const uint8_t* packet_begin,
+ const uint8_t* packet_end,
+ std::vector<LoggedRtcpPacketSenderReport>* sr_list,
+ std::vector<LoggedRtcpPacketReceiverReport>* rr_list,
+ std::vector<LoggedRtcpPacketExtendedReports>* xr_list,
+ std::vector<LoggedRtcpPacketRemb>* remb_list,
+ std::vector<LoggedRtcpPacketNack>* nack_list,
+ std::vector<LoggedRtcpPacketFir>* fir_list,
+ std::vector<LoggedRtcpPacketPli>* pli_list,
+ std::vector<LoggedRtcpPacketBye>* bye_list,
+ std::vector<LoggedRtcpPacketTransportFeedback>* transport_feedback_list,
+ std::vector<LoggedRtcpPacketLossNotification>* loss_notification_list) {
+ Timestamp timestamp = Timestamp::Micros(timestamp_us);
+ rtcp::CommonHeader header;
+ for (const uint8_t* block = packet_begin; block < packet_end;
+ block = header.NextPacket()) {
+ RTC_PARSE_CHECK_OR_RETURN(header.Parse(block, packet_end - block));
+ if (header.type() == rtcp::TransportFeedback::kPacketType &&
+ header.fmt() == rtcp::TransportFeedback::kFeedbackMessageType) {
+ LoggedRtcpPacketTransportFeedback parsed_block;
+ parsed_block.timestamp = timestamp;
+ RTC_PARSE_CHECK_OR_RETURN(parsed_block.transport_feedback.Parse(header));
+ transport_feedback_list->push_back(std::move(parsed_block));
+ } else if (header.type() == rtcp::SenderReport::kPacketType) {
+ LoggedRtcpPacketSenderReport parsed_block;
+ parsed_block.timestamp = timestamp;
+ RTC_PARSE_CHECK_OR_RETURN(parsed_block.sr.Parse(header));
+ sr_list->push_back(std::move(parsed_block));
+ } else if (header.type() == rtcp::ReceiverReport::kPacketType) {
+ LoggedRtcpPacketReceiverReport parsed_block;
+ parsed_block.timestamp = timestamp;
+ RTC_PARSE_CHECK_OR_RETURN(parsed_block.rr.Parse(header));
+ rr_list->push_back(std::move(parsed_block));
+ } else if (header.type() == rtcp::ExtendedReports::kPacketType) {
+ LoggedRtcpPacketExtendedReports parsed_block;
+ parsed_block.timestamp = timestamp;
+ RTC_PARSE_CHECK_OR_RETURN(parsed_block.xr.Parse(header));
+ xr_list->push_back(std::move(parsed_block));
+ } else if (header.type() == rtcp::Fir::kPacketType &&
+ header.fmt() == rtcp::Fir::kFeedbackMessageType) {
+ LoggedRtcpPacketFir parsed_block;
+ parsed_block.timestamp = timestamp;
+ RTC_PARSE_CHECK_OR_RETURN(parsed_block.fir.Parse(header));
+ fir_list->push_back(std::move(parsed_block));
+ } else if (header.type() == rtcp::Pli::kPacketType &&
+ header.fmt() == rtcp::Pli::kFeedbackMessageType) {
+ LoggedRtcpPacketPli parsed_block;
+ parsed_block.timestamp = timestamp;
+ RTC_PARSE_CHECK_OR_RETURN(parsed_block.pli.Parse(header));
+ pli_list->push_back(std::move(parsed_block));
+ } else if (header.type() == rtcp::Bye::kPacketType) {
+ LoggedRtcpPacketBye parsed_block;
+ parsed_block.timestamp = timestamp;
+ RTC_PARSE_CHECK_OR_RETURN(parsed_block.bye.Parse(header));
+ bye_list->push_back(std::move(parsed_block));
+ } else if (header.type() == rtcp::Psfb::kPacketType &&
+ header.fmt() == rtcp::Psfb::kAfbMessageType) {
+ bool type_found = false;
+ if (!type_found) {
+ LoggedRtcpPacketRemb parsed_block;
+ parsed_block.timestamp = timestamp;
+ if (parsed_block.remb.Parse(header)) {
+ remb_list->push_back(std::move(parsed_block));
+ type_found = true;
+ }
+ }
+ if (!type_found) {
+ LoggedRtcpPacketLossNotification parsed_block;
+ parsed_block.timestamp = timestamp;
+ if (parsed_block.loss_notification.Parse(header)) {
+ loss_notification_list->push_back(std::move(parsed_block));
+ type_found = true;
+ }
+ }
+ // We ignore other application-layer feedback types.
+ } else if (header.type() == rtcp::Nack::kPacketType &&
+ header.fmt() == rtcp::Nack::kFeedbackMessageType) {
+ LoggedRtcpPacketNack parsed_block;
+ parsed_block.timestamp = timestamp;
+ RTC_PARSE_CHECK_OR_RETURN(parsed_block.nack.Parse(header));
+ nack_list->push_back(std::move(parsed_block));
+ }
+ }
+ return ParsedRtcEventLog::ParseStatus::Success();
+}
+
+} // namespace
+
+// 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_DCHECK_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_DCHECK_NOTREACHED();
+ return ProbeFailureReason::kTimeout;
+}
+
+DtlsTransportState GetRuntimeDtlsTransportState(
+ rtclog2::DtlsTransportStateEvent::DtlsTransportState state) {
+ switch (state) {
+ case rtclog2::DtlsTransportStateEvent::DTLS_TRANSPORT_NEW:
+ return DtlsTransportState::kNew;
+ case rtclog2::DtlsTransportStateEvent::DTLS_TRANSPORT_CONNECTING:
+ return DtlsTransportState::kConnecting;
+ case rtclog2::DtlsTransportStateEvent::DTLS_TRANSPORT_CONNECTED:
+ return DtlsTransportState::kConnected;
+ case rtclog2::DtlsTransportStateEvent::DTLS_TRANSPORT_CLOSED:
+ return DtlsTransportState::kClosed;
+ case rtclog2::DtlsTransportStateEvent::DTLS_TRANSPORT_FAILED:
+ return DtlsTransportState::kFailed;
+ case rtclog2::DtlsTransportStateEvent::UNKNOWN_DTLS_TRANSPORT_STATE:
+ RTC_DCHECK_NOTREACHED();
+ return DtlsTransportState::kNumValues;
+ }
+ RTC_DCHECK_NOTREACHED();
+ return DtlsTransportState::kNumValues;
+}
+
+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_DCHECK_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_DCHECK_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_DCHECK_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_DCHECK_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_DCHECK_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_DCHECK_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.
+
+LoggedPacketInfo::LoggedPacketInfo(const LoggedRtpPacket& rtp,
+ LoggedMediaType media_type,
+ bool rtx,
+ Timestamp capture_time)
+ : ssrc(rtp.header.ssrc),
+ stream_seq_no(rtp.header.sequenceNumber),
+ size(static_cast<uint16_t>(rtp.total_length)),
+ payload_size(static_cast<uint16_t>(rtp.total_length -
+ rtp.header.paddingLength -
+ rtp.header.headerLength)),
+ padding_size(static_cast<uint16_t>(rtp.header.paddingLength)),
+ payload_type(rtp.header.payloadType),
+ media_type(media_type),
+ rtx(rtx),
+ marker_bit(rtp.header.markerBit),
+ has_transport_seq_no(rtp.header.extension.hasTransportSequenceNumber),
+ transport_seq_no(static_cast<uint16_t>(
+ has_transport_seq_no ? rtp.header.extension.transportSequenceNumber
+ : 0)),
+ capture_time(capture_time),
+ log_packet_time(Timestamp::Micros(rtp.log_time_us())),
+ reported_send_time(rtp.header.extension.hasAbsoluteSendTime
+ ? rtp.header.extension.GetAbsoluteSendTimestamp()
+ : Timestamp::MinusInfinity()) {}
+
+LoggedPacketInfo::LoggedPacketInfo(const LoggedPacketInfo&) = default;
+
+LoggedPacketInfo::~LoggedPacketInfo() {}
+
+ParsedRtcEventLog::~ParsedRtcEventLog() = default;
+
+ParsedRtcEventLog::LoggedRtpStreamIncoming::LoggedRtpStreamIncoming() = default;
+ParsedRtcEventLog::LoggedRtpStreamIncoming::LoggedRtpStreamIncoming(
+ const LoggedRtpStreamIncoming& rhs) = default;
+ParsedRtcEventLog::LoggedRtpStreamIncoming::~LoggedRtpStreamIncoming() =
+ default;
+
+ParsedRtcEventLog::LoggedRtpStreamOutgoing::LoggedRtpStreamOutgoing() = default;
+ParsedRtcEventLog::LoggedRtpStreamOutgoing::LoggedRtpStreamOutgoing(
+ const LoggedRtpStreamOutgoing& rhs) = default;
+ParsedRtcEventLog::LoggedRtpStreamOutgoing::~LoggedRtpStreamOutgoing() =
+ default;
+
+ParsedRtcEventLog::LoggedRtpStreamView::LoggedRtpStreamView(
+ uint32_t ssrc,
+ const std::vector<LoggedRtpPacketIncoming>& packets)
+ : ssrc(ssrc), packet_view() {
+ for (const LoggedRtpPacketIncoming& packet : packets) {
+ packet_view.push_back(&(packet.rtp));
+ }
+}
+
+ParsedRtcEventLog::LoggedRtpStreamView::LoggedRtpStreamView(
+ uint32_t ssrc,
+ const std::vector<LoggedRtpPacketOutgoing>& packets)
+ : ssrc(ssrc), packet_view() {
+ for (const LoggedRtpPacketOutgoing& packet : packets) {
+ packet_view.push_back(&(packet.rtp));
+ }
+}
+
+ParsedRtcEventLog::LoggedRtpStreamView::LoggedRtpStreamView(
+ const LoggedRtpStreamView&) = default;
+
+// Return default values for header extensions, to use on streams without stored
+// mapping data. Currently this only applies to audio streams, since the mapping
+// is not stored in the event log.
+// TODO(ivoc): Remove this once this mapping is stored in the event log for
+// audio streams. Tracking bug: webrtc:6399
+webrtc::RtpHeaderExtensionMap
+ParsedRtcEventLog::GetDefaultHeaderExtensionMap() {
+ // Values from before the default RTP header extension IDs were removed.
+ constexpr int kAudioLevelDefaultId = 1;
+ constexpr int kTimestampOffsetDefaultId = 2;
+ constexpr int kAbsSendTimeDefaultId = 3;
+ constexpr int kVideoRotationDefaultId = 4;
+ constexpr int kTransportSequenceNumberDefaultId = 5;
+ constexpr int kPlayoutDelayDefaultId = 6;
+ constexpr int kVideoContentTypeDefaultId = 7;
+ constexpr int kVideoTimingDefaultId = 8;
+
+ webrtc::RtpHeaderExtensionMap default_map;
+ default_map.Register<AudioLevel>(kAudioLevelDefaultId);
+ default_map.Register<TransmissionOffset>(kTimestampOffsetDefaultId);
+ default_map.Register<AbsoluteSendTime>(kAbsSendTimeDefaultId);
+ default_map.Register<VideoOrientation>(kVideoRotationDefaultId);
+ default_map.Register<TransportSequenceNumber>(
+ kTransportSequenceNumberDefaultId);
+ default_map.Register<PlayoutDelayLimits>(kPlayoutDelayDefaultId);
+ default_map.Register<VideoContentTypeExtension>(kVideoContentTypeDefaultId);
+ default_map.Register<VideoTimingExtension>(kVideoTimingDefaultId);
+ return default_map;
+}
+
+ParsedRtcEventLog::ParsedRtcEventLog(
+ UnconfiguredHeaderExtensions parse_unconfigured_header_extensions,
+ bool allow_incomplete_logs)
+ : parse_unconfigured_header_extensions_(
+ parse_unconfigured_header_extensions),
+ allow_incomplete_logs_(allow_incomplete_logs) {
+ Clear();
+}
+
+void ParsedRtcEventLog::Clear() {
+ default_extension_map_ = GetDefaultHeaderExtensionMap();
+
+ incoming_rtx_ssrcs_.clear();
+ incoming_video_ssrcs_.clear();
+ incoming_audio_ssrcs_.clear();
+ outgoing_rtx_ssrcs_.clear();
+ outgoing_video_ssrcs_.clear();
+ outgoing_audio_ssrcs_.clear();
+
+ incoming_rtp_packets_map_.clear();
+ outgoing_rtp_packets_map_.clear();
+ incoming_rtp_packets_by_ssrc_.clear();
+ outgoing_rtp_packets_by_ssrc_.clear();
+ incoming_rtp_packet_views_by_ssrc_.clear();
+ outgoing_rtp_packet_views_by_ssrc_.clear();
+
+ incoming_rtcp_packets_.clear();
+ outgoing_rtcp_packets_.clear();
+
+ incoming_rr_.clear();
+ outgoing_rr_.clear();
+ incoming_sr_.clear();
+ outgoing_sr_.clear();
+ incoming_nack_.clear();
+ outgoing_nack_.clear();
+ incoming_remb_.clear();
+ outgoing_remb_.clear();
+ incoming_transport_feedback_.clear();
+ outgoing_transport_feedback_.clear();
+ incoming_loss_notification_.clear();
+ outgoing_loss_notification_.clear();
+
+ start_log_events_.clear();
+ stop_log_events_.clear();
+ audio_playout_events_.clear();
+ neteq_set_minimum_delay_events_.clear();
+ audio_network_adaptation_events_.clear();
+ bwe_probe_cluster_created_events_.clear();
+ bwe_probe_failure_events_.clear();
+ bwe_probe_success_events_.clear();
+ bwe_delay_updates_.clear();
+ bwe_loss_updates_.clear();
+ dtls_transport_states_.clear();
+ dtls_writable_states_.clear();
+ decoded_frames_.clear();
+ alr_state_events_.clear();
+ ice_candidate_pair_configs_.clear();
+ ice_candidate_pair_events_.clear();
+ audio_recv_configs_.clear();
+ audio_send_configs_.clear();
+ video_recv_configs_.clear();
+ video_send_configs_.clear();
+
+ last_incoming_rtcp_packet_.clear();
+
+ first_timestamp_ = Timestamp::PlusInfinity();
+ last_timestamp_ = Timestamp::MinusInfinity();
+ first_log_segment_ = LogSegment(0, std::numeric_limits<int64_t>::max());
+
+ incoming_rtp_extensions_maps_.clear();
+ outgoing_rtp_extensions_maps_.clear();
+}
+
+ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::ParseFile(
+ absl::string_view filename) {
+ FileWrapper file = FileWrapper::OpenReadOnly(filename);
+ if (!file.is_open()) {
+ RTC_LOG(LS_WARNING) << "Could not open file " << filename
+ << " for reading.";
+ RTC_PARSE_CHECK_OR_RETURN(file.is_open());
+ }
+
+ // Compute file size.
+ long signed_filesize = file.FileSize(); // NOLINT(runtime/int)
+ RTC_PARSE_CHECK_OR_RETURN_GE(signed_filesize, 0);
+ RTC_PARSE_CHECK_OR_RETURN_LE(signed_filesize, kMaxLogSize);
+ size_t filesize = rtc::checked_cast<size_t>(signed_filesize);
+
+ // Read file into memory.
+ std::string buffer(filesize, '\0');
+ size_t bytes_read = file.Read(&buffer[0], buffer.size());
+ if (bytes_read != filesize) {
+ RTC_LOG(LS_WARNING) << "Failed to read file " << filename;
+ RTC_PARSE_CHECK_OR_RETURN_EQ(bytes_read, filesize);
+ }
+
+ return ParseStream(buffer);
+}
+
+ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::ParseString(
+ absl::string_view s) {
+ return ParseStream(s);
+}
+
+ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::ParseStream(
+ absl::string_view s) {
+ Clear();
+ ParseStatus status = ParseStreamInternal(s);
+
+ // Cache the configured SSRCs.
+ for (const auto& video_recv_config : video_recv_configs()) {
+ incoming_video_ssrcs_.insert(video_recv_config.config.remote_ssrc);
+ incoming_video_ssrcs_.insert(video_recv_config.config.rtx_ssrc);
+ incoming_rtx_ssrcs_.insert(video_recv_config.config.rtx_ssrc);
+ }
+ for (const auto& video_send_config : video_send_configs()) {
+ outgoing_video_ssrcs_.insert(video_send_config.config.local_ssrc);
+ outgoing_video_ssrcs_.insert(video_send_config.config.rtx_ssrc);
+ outgoing_rtx_ssrcs_.insert(video_send_config.config.rtx_ssrc);
+ }
+ for (const auto& audio_recv_config : audio_recv_configs()) {
+ incoming_audio_ssrcs_.insert(audio_recv_config.config.remote_ssrc);
+ }
+ for (const auto& audio_send_config : audio_send_configs()) {
+ outgoing_audio_ssrcs_.insert(audio_send_config.config.local_ssrc);
+ }
+
+ // ParseStreamInternal stores the RTP packets in a map indexed by SSRC.
+ // Since we dont need rapid lookup based on SSRC after parsing, we move the
+ // packets_streams from map to vector.
+ incoming_rtp_packets_by_ssrc_.reserve(incoming_rtp_packets_map_.size());
+ for (auto& kv : incoming_rtp_packets_map_) {
+ incoming_rtp_packets_by_ssrc_.emplace_back(LoggedRtpStreamIncoming());
+ incoming_rtp_packets_by_ssrc_.back().ssrc = kv.first;
+ incoming_rtp_packets_by_ssrc_.back().incoming_packets =
+ std::move(kv.second);
+ }
+ incoming_rtp_packets_map_.clear();
+ outgoing_rtp_packets_by_ssrc_.reserve(outgoing_rtp_packets_map_.size());
+ for (auto& kv : outgoing_rtp_packets_map_) {
+ outgoing_rtp_packets_by_ssrc_.emplace_back(LoggedRtpStreamOutgoing());
+ outgoing_rtp_packets_by_ssrc_.back().ssrc = kv.first;
+ outgoing_rtp_packets_by_ssrc_.back().outgoing_packets =
+ std::move(kv.second);
+ }
+ outgoing_rtp_packets_map_.clear();
+
+ // Build PacketViews for easier iteration over RTP packets.
+ for (const auto& stream : incoming_rtp_packets_by_ssrc_) {
+ incoming_rtp_packet_views_by_ssrc_.emplace_back(
+ LoggedRtpStreamView(stream.ssrc, stream.incoming_packets));
+ }
+ for (const auto& stream : outgoing_rtp_packets_by_ssrc_) {
+ outgoing_rtp_packet_views_by_ssrc_.emplace_back(
+ LoggedRtpStreamView(stream.ssrc, stream.outgoing_packets));
+ }
+
+ // Set up convenience wrappers around the most commonly used RTCP types.
+ for (const auto& incoming : incoming_rtcp_packets_) {
+ const int64_t timestamp_us = incoming.rtcp.timestamp.us();
+ const uint8_t* packet_begin = incoming.rtcp.raw_data.data();
+ const uint8_t* packet_end = packet_begin + incoming.rtcp.raw_data.size();
+ auto store_rtcp_status = StoreRtcpBlocks(
+ timestamp_us, packet_begin, packet_end, &incoming_sr_, &incoming_rr_,
+ &incoming_xr_, &incoming_remb_, &incoming_nack_, &incoming_fir_,
+ &incoming_pli_, &incoming_bye_, &incoming_transport_feedback_,
+ &incoming_loss_notification_);
+ RTC_RETURN_IF_ERROR(store_rtcp_status);
+ }
+
+ for (const auto& outgoing : outgoing_rtcp_packets_) {
+ const int64_t timestamp_us = outgoing.rtcp.timestamp.us();
+ const uint8_t* packet_begin = outgoing.rtcp.raw_data.data();
+ const uint8_t* packet_end = packet_begin + outgoing.rtcp.raw_data.size();
+ auto store_rtcp_status = StoreRtcpBlocks(
+ timestamp_us, packet_begin, packet_end, &outgoing_sr_, &outgoing_rr_,
+ &outgoing_xr_, &outgoing_remb_, &outgoing_nack_, &outgoing_fir_,
+ &outgoing_pli_, &outgoing_bye_, &outgoing_transport_feedback_,
+ &outgoing_loss_notification_);
+ RTC_RETURN_IF_ERROR(store_rtcp_status);
+ }
+
+ // Store first and last timestamp events that might happen before the call is
+ // connected or after the call is disconnected. Typical examples are
+ // stream configurations and starting/stopping the log.
+ // TODO(terelius): Figure out if we actually need to find the first and last
+ // timestamp in the parser. It seems like this could be done by the caller.
+ first_timestamp_ = Timestamp::PlusInfinity();
+ last_timestamp_ = Timestamp::MinusInfinity();
+ 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);
+ }
+ for (const auto& set_minimum_delay : neteq_set_minimum_delay_events()) {
+ // NetEq SetMinimumDelay grouped by SSRC.
+ StoreFirstAndLastTimestamp(set_minimum_delay.second);
+ }
+ StoreFirstAndLastTimestamp(audio_network_adaptation_events());
+ StoreFirstAndLastTimestamp(bwe_probe_cluster_created_events());
+ StoreFirstAndLastTimestamp(bwe_probe_failure_events());
+ StoreFirstAndLastTimestamp(bwe_probe_success_events());
+ StoreFirstAndLastTimestamp(bwe_delay_updates());
+ StoreFirstAndLastTimestamp(bwe_loss_updates());
+ for (const auto& frame_stream : decoded_frames()) {
+ StoreFirstAndLastTimestamp(frame_stream.second);
+ }
+ StoreFirstAndLastTimestamp(dtls_transport_states());
+ StoreFirstAndLastTimestamp(dtls_writable_states());
+ StoreFirstAndLastTimestamp(ice_candidate_pair_configs());
+ StoreFirstAndLastTimestamp(ice_candidate_pair_events());
+ for (const auto& rtp_stream : incoming_rtp_packets_by_ssrc()) {
+ StoreFirstAndLastTimestamp(rtp_stream.incoming_packets);
+ }
+ for (const auto& rtp_stream : outgoing_rtp_packets_by_ssrc()) {
+ StoreFirstAndLastTimestamp(rtp_stream.outgoing_packets);
+ }
+ StoreFirstAndLastTimestamp(incoming_rtcp_packets());
+ StoreFirstAndLastTimestamp(outgoing_rtcp_packets());
+ StoreFirstAndLastTimestamp(generic_packets_sent_);
+ StoreFirstAndLastTimestamp(generic_packets_received_);
+ StoreFirstAndLastTimestamp(generic_acks_received_);
+ StoreFirstAndLastTimestamp(remote_estimate_events_);
+
+ // Stop events could be missing due to file size limits. If so, use the
+ // last event, or the next start timestamp if available.
+ // TODO(terelius): This could be improved. Instead of using the next start
+ // event, we could use the timestamp of the the last previous regular event.
+ auto start_iter = start_log_events().begin();
+ auto stop_iter = stop_log_events().begin();
+ int64_t start_us =
+ first_timestamp().us_or(std::numeric_limits<int64_t>::max());
+ int64_t next_start_us = std::numeric_limits<int64_t>::max();
+ int64_t stop_us = std::numeric_limits<int64_t>::max();
+ if (start_iter != start_log_events().end()) {
+ start_us = std::min(start_us, start_iter->log_time_us());
+ ++start_iter;
+ if (start_iter != start_log_events().end())
+ next_start_us = start_iter->log_time_us();
+ }
+ if (stop_iter != stop_log_events().end()) {
+ stop_us = stop_iter->log_time_us();
+ }
+ stop_us = std::min(stop_us, next_start_us);
+ if (stop_us == std::numeric_limits<int64_t>::max() &&
+ !last_timestamp().IsMinusInfinity()) {
+ stop_us = last_timestamp().us();
+ }
+ RTC_PARSE_CHECK_OR_RETURN_LE(start_us, stop_us);
+ first_log_segment_ = LogSegment(start_us, stop_us);
+
+ if (first_timestamp_ > last_timestamp_) {
+ first_timestamp_ = last_timestamp_ = Timestamp::Zero();
+ }
+
+ return status;
+}
+
+ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::ParseStreamInternal(
+ absl::string_view s) {
+ constexpr uint64_t kMaxEventSize = 10000000; // Sanity check.
+ // 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;
+ bool success = false;
+
+ // "Peek" at the first varint.
+ absl::string_view event_start = s;
+ uint64_t tag = 0;
+ std::tie(success, std::ignore) = DecodeVarInt(s, &tag);
+ if (!success) {
+ RTC_LOG(LS_WARNING) << "Failed to read varint from beginning of event log.";
+ RTC_PARSE_WARN_AND_RETURN_SUCCESS_IF(allow_incomplete_logs_,
+ kIncompleteLogError);
+ return ParseStatus::Error("Failed to read field tag varint", __FILE__,
+ __LINE__);
+ }
+ s = event_start;
+
+ if (tag >> 1 == static_cast<uint64_t>(RtcEvent::Type::BeginV3Log)) {
+ return ParseStreamInternalV3(s);
+ }
+
+ while (!s.empty()) {
+ // If not, "reset" event_start and read the field tag for the next event.
+ event_start = s;
+ std::tie(success, s) = DecodeVarInt(s, &tag);
+ if (!success) {
+ RTC_LOG(LS_WARNING)
+ << "Failed to read field tag from beginning of protobuf event.";
+ RTC_PARSE_WARN_AND_RETURN_SUCCESS_IF(allow_incomplete_logs_,
+ kIncompleteLogError);
+ return ParseStatus::Error("Failed to read field tag varint", __FILE__,
+ __LINE__);
+ }
+
+ 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;
+ RTC_PARSE_WARN_AND_RETURN_SUCCESS_IF(allow_incomplete_logs_,
+ kIncompleteLogError);
+ RTC_PARSE_CHECK_OR_RETURN_EQ(wire_type, 2);
+ }
+
+ // Read the length field.
+ uint64_t message_length = 0;
+ std::tie(success, s) = DecodeVarInt(s, &message_length);
+ if (!success) {
+ RTC_LOG(LS_WARNING) << "Missing message length after protobuf field tag.";
+ RTC_PARSE_WARN_AND_RETURN_SUCCESS_IF(allow_incomplete_logs_,
+ kIncompleteLogError);
+ return ParseStatus::Error("Failed to read message length varint",
+ __FILE__, __LINE__);
+ }
+
+ if (message_length > s.size()) {
+ RTC_LOG(LS_WARNING) << "Protobuf message length is larger than the "
+ "remaining bytes in the proto.";
+ RTC_PARSE_WARN_AND_RETURN_SUCCESS_IF(allow_incomplete_logs_,
+ kIncompleteLogError);
+ return ParseStatus::Error(
+ "Incomplete message: the length of the next message is larger than "
+ "the remaining bytes in the proto",
+ __FILE__, __LINE__);
+ }
+
+ RTC_PARSE_CHECK_OR_RETURN_LE(message_length, kMaxEventSize);
+ // Skip forward to the start of the next event.
+ s = s.substr(message_length);
+ size_t total_event_size = event_start.size() - s.size();
+ RTC_CHECK_LE(total_event_size, event_start.size());
+
+ if (tag == kExpectedV1Tag) {
+ // Parse the protobuf event from the buffer.
+ rtclog::EventStream event_stream;
+ if (!event_stream.ParseFromArray(event_start.data(), total_event_size)) {
+ RTC_LOG(LS_WARNING)
+ << "Failed to parse legacy-format protobuf message.";
+ RTC_PARSE_WARN_AND_RETURN_SUCCESS_IF(allow_incomplete_logs_,
+ kIncompleteLogError);
+ RTC_PARSE_CHECK_OR_RETURN(false);
+ }
+
+ RTC_PARSE_CHECK_OR_RETURN_EQ(event_stream.stream_size(), 1);
+ auto status = StoreParsedLegacyEvent(event_stream.stream(0));
+ RTC_RETURN_IF_ERROR(status);
+ } else {
+ // Parse the protobuf event from the buffer.
+ rtclog2::EventStream event_stream;
+ if (!event_stream.ParseFromArray(event_start.data(), total_event_size)) {
+ RTC_LOG(LS_WARNING) << "Failed to parse new-format protobuf message.";
+ RTC_PARSE_WARN_AND_RETURN_SUCCESS_IF(allow_incomplete_logs_,
+ kIncompleteLogError);
+ RTC_PARSE_CHECK_OR_RETURN(false);
+ }
+ auto status = StoreParsedNewFormatEvent(event_stream);
+ RTC_RETURN_IF_ERROR(status);
+ }
+ }
+ return ParseStatus::Success();
+}
+
+ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::ParseStreamInternalV3(
+ absl::string_view s) {
+ constexpr uint64_t kMaxEventSize = 10000000; // Sanity check.
+ bool expect_begin_log_event = true;
+ bool success = false;
+
+ while (!s.empty()) {
+ // Read event type.
+ uint64_t event_tag = 0;
+ std::tie(success, s) = DecodeVarInt(s, &event_tag);
+ RTC_PARSE_CHECK_OR_RETURN_MESSAGE(success, "Failed to read event type.");
+ bool batched = event_tag & 1;
+ uint64_t event_type = event_tag >> 1;
+
+ // Read event size
+ uint64_t event_size_bytes = 0;
+ std::tie(success, s) = DecodeVarInt(s, &event_size_bytes);
+ RTC_PARSE_CHECK_OR_RETURN_MESSAGE(success, "Failed to read event size.");
+ if (event_size_bytes > kMaxEventSize || event_size_bytes > s.size()) {
+ RTC_LOG(LS_WARNING) << "Event size is too large.";
+ RTC_PARSE_CHECK_OR_RETURN_LE(event_size_bytes, kMaxEventSize);
+ RTC_PARSE_CHECK_OR_RETURN_LE(event_size_bytes, s.size());
+ }
+
+ // Read remaining event fields into a buffer.
+ absl::string_view event_fields = s.substr(0, event_size_bytes);
+ s = s.substr(event_size_bytes);
+
+ if (expect_begin_log_event) {
+ RTC_PARSE_CHECK_OR_RETURN_EQ(
+ event_type, static_cast<uint32_t>(RtcEvent::Type::BeginV3Log));
+ expect_begin_log_event = false;
+ }
+
+ switch (event_type) {
+ case static_cast<uint32_t>(RtcEvent::Type::BeginV3Log):
+ RtcEventBeginLog::Parse(event_fields, batched, start_log_events_);
+ break;
+ case static_cast<uint32_t>(RtcEvent::Type::EndV3Log):
+ RtcEventEndLog::Parse(event_fields, batched, stop_log_events_);
+ expect_begin_log_event = true;
+ break;
+ case static_cast<uint32_t>(RtcEvent::Type::AlrStateEvent):
+ RtcEventAlrState::Parse(event_fields, batched, alr_state_events_);
+ break;
+ case static_cast<uint32_t>(RtcEvent::Type::AudioPlayout):
+ RtcEventAudioPlayout::Parse(event_fields, batched,
+ audio_playout_events_);
+ break;
+ case static_cast<uint32_t>(RtcEvent::Type::BweUpdateDelayBased):
+ RtcEventBweUpdateDelayBased::Parse(event_fields, batched,
+ bwe_delay_updates_);
+ break;
+ case static_cast<uint32_t>(RtcEvent::Type::AudioNetworkAdaptation):
+ RtcEventAudioNetworkAdaptation::Parse(event_fields, batched,
+ audio_network_adaptation_events_);
+ break;
+ case static_cast<uint32_t>(RtcEvent::Type::AudioReceiveStreamConfig):
+ RtcEventAudioReceiveStreamConfig::Parse(event_fields, batched,
+ audio_recv_configs_);
+ break;
+ case static_cast<uint32_t>(RtcEvent::Type::AudioSendStreamConfig):
+ RtcEventAudioSendStreamConfig::Parse(event_fields, batched,
+ audio_send_configs_);
+ break;
+ case static_cast<uint32_t>(RtcEvent::Type::BweUpdateLossBased):
+ RtcEventBweUpdateLossBased::Parse(event_fields, batched,
+ bwe_loss_updates_);
+ break;
+ case static_cast<uint32_t>(RtcEvent::Type::DtlsTransportState):
+ RtcEventDtlsTransportState::Parse(event_fields, batched,
+ dtls_transport_states_);
+ break;
+ case static_cast<uint32_t>(RtcEvent::Type::DtlsWritableState):
+ RtcEventDtlsWritableState::Parse(event_fields, batched,
+ dtls_writable_states_);
+ break;
+ case static_cast<uint32_t>(RtcEvent::Type::FrameDecoded):
+ RtcEventFrameDecoded::Parse(event_fields, batched, decoded_frames_);
+ break;
+ case static_cast<uint32_t>(RtcEvent::Type::GenericAckReceived):
+ RtcEventGenericAckReceived::Parse(event_fields, batched,
+ generic_acks_received_);
+ break;
+ case static_cast<uint32_t>(RtcEvent::Type::GenericPacketReceived):
+ RtcEventGenericPacketReceived::Parse(event_fields, batched,
+ generic_packets_received_);
+ break;
+ case static_cast<uint32_t>(RtcEvent::Type::GenericPacketSent):
+ RtcEventGenericPacketSent::Parse(event_fields, batched,
+ generic_packets_sent_);
+ break;
+ case static_cast<uint32_t>(RtcEvent::Type::IceCandidatePairConfig):
+ RtcEventIceCandidatePairConfig::Parse(event_fields, batched,
+ ice_candidate_pair_configs_);
+ break;
+ case static_cast<uint32_t>(RtcEvent::Type::IceCandidatePairEvent):
+ RtcEventIceCandidatePair::Parse(event_fields, batched,
+ ice_candidate_pair_events_);
+ break;
+ case static_cast<uint32_t>(RtcEvent::Type::ProbeClusterCreated):
+ RtcEventProbeClusterCreated::Parse(event_fields, batched,
+ bwe_probe_cluster_created_events_);
+ break;
+ case static_cast<uint32_t>(RtcEvent::Type::ProbeResultFailure):
+ RtcEventProbeResultFailure::Parse(event_fields, batched,
+ bwe_probe_failure_events_);
+ break;
+ case static_cast<uint32_t>(RtcEvent::Type::ProbeResultSuccess):
+ RtcEventProbeResultSuccess::Parse(event_fields, batched,
+ bwe_probe_success_events_);
+ break;
+ case static_cast<uint32_t>(RtcEvent::Type::RemoteEstimateEvent):
+ RtcEventRemoteEstimate::Parse(event_fields, batched,
+ remote_estimate_events_);
+ break;
+ case static_cast<uint32_t>(RtcEvent::Type::RouteChangeEvent):
+ RtcEventRouteChange::Parse(event_fields, batched, route_change_events_);
+ break;
+ case static_cast<uint32_t>(RtcEvent::Type::RtcpPacketIncoming):
+ RtcEventRtcpPacketIncoming::Parse(event_fields, batched,
+ incoming_rtcp_packets_);
+ break;
+ case static_cast<uint32_t>(RtcEvent::Type::RtcpPacketOutgoing):
+ RtcEventRtcpPacketOutgoing::Parse(event_fields, batched,
+ outgoing_rtcp_packets_);
+ break;
+ case static_cast<uint32_t>(RtcEvent::Type::RtpPacketIncoming):
+ RtcEventRtpPacketIncoming::Parse(event_fields, batched,
+ incoming_rtp_packets_map_);
+ break;
+ case static_cast<uint32_t>(RtcEvent::Type::RtpPacketOutgoing):
+ RtcEventRtpPacketOutgoing::Parse(event_fields, batched,
+ outgoing_rtp_packets_map_);
+ break;
+ case static_cast<uint32_t>(RtcEvent::Type::VideoReceiveStreamConfig):
+ RtcEventVideoReceiveStreamConfig::Parse(event_fields, batched,
+ video_recv_configs_);
+ break;
+ case static_cast<uint32_t>(RtcEvent::Type::VideoSendStreamConfig):
+ RtcEventVideoSendStreamConfig::Parse(event_fields, batched,
+ video_send_configs_);
+ break;
+ }
+ }
+
+ return ParseStatus::Success();
+}
+
+template <typename T>
+void ParsedRtcEventLog::StoreFirstAndLastTimestamp(const std::vector<T>& v) {
+ if (v.empty())
+ return;
+ first_timestamp_ = std::min(first_timestamp_, v.front().log_time());
+ last_timestamp_ = std::max(last_timestamp_, v.back().log_time());
+}
+
+ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreParsedLegacyEvent(
+ const rtclog::Event& event) {
+ RTC_PARSE_CHECK_OR_RETURN(event.has_type());
+ switch (event.type()) {
+ case rtclog::Event::VIDEO_RECEIVER_CONFIG_EVENT: {
+ auto config = GetVideoReceiveConfig(event);
+ if (!config.ok())
+ return config.status();
+
+ RTC_PARSE_CHECK_OR_RETURN(event.has_timestamp_us());
+ int64_t timestamp_us = event.timestamp_us();
+ video_recv_configs_.emplace_back(Timestamp::Micros(timestamp_us),
+ config.value());
+ incoming_rtp_extensions_maps_[config.value().remote_ssrc] =
+ RtpHeaderExtensionMap(config.value().rtp_extensions);
+ incoming_rtp_extensions_maps_[config.value().rtx_ssrc] =
+ RtpHeaderExtensionMap(config.value().rtp_extensions);
+ break;
+ }
+ case rtclog::Event::VIDEO_SENDER_CONFIG_EVENT: {
+ auto config = GetVideoSendConfig(event);
+ if (!config.ok())
+ return config.status();
+
+ RTC_PARSE_CHECK_OR_RETURN(event.has_timestamp_us());
+ int64_t timestamp_us = event.timestamp_us();
+ video_send_configs_.emplace_back(Timestamp::Micros(timestamp_us),
+ config.value());
+ outgoing_rtp_extensions_maps_[config.value().local_ssrc] =
+ RtpHeaderExtensionMap(config.value().rtp_extensions);
+ outgoing_rtp_extensions_maps_[config.value().rtx_ssrc] =
+ RtpHeaderExtensionMap(config.value().rtp_extensions);
+ break;
+ }
+ case rtclog::Event::AUDIO_RECEIVER_CONFIG_EVENT: {
+ auto config = GetAudioReceiveConfig(event);
+ if (!config.ok())
+ return config.status();
+
+ RTC_PARSE_CHECK_OR_RETURN(event.has_timestamp_us());
+ int64_t timestamp_us = event.timestamp_us();
+ audio_recv_configs_.emplace_back(Timestamp::Micros(timestamp_us),
+ config.value());
+ incoming_rtp_extensions_maps_[config.value().remote_ssrc] =
+ RtpHeaderExtensionMap(config.value().rtp_extensions);
+ break;
+ }
+ case rtclog::Event::AUDIO_SENDER_CONFIG_EVENT: {
+ auto config = GetAudioSendConfig(event);
+ if (!config.ok())
+ return config.status();
+ RTC_PARSE_CHECK_OR_RETURN(event.has_timestamp_us());
+ int64_t timestamp_us = event.timestamp_us();
+ audio_send_configs_.emplace_back(Timestamp::Micros(timestamp_us),
+ config.value());
+ outgoing_rtp_extensions_maps_[config.value().local_ssrc] =
+ RtpHeaderExtensionMap(config.value().rtp_extensions);
+ break;
+ }
+ case rtclog::Event::RTP_EVENT: {
+ RTC_PARSE_CHECK_OR_RETURN(event.has_rtp_packet());
+ const rtclog::RtpPacket& rtp_packet = event.rtp_packet();
+ RTC_PARSE_CHECK_OR_RETURN(rtp_packet.has_header());
+ RTC_PARSE_CHECK_OR_RETURN(rtp_packet.has_incoming());
+ RTC_PARSE_CHECK_OR_RETURN(rtp_packet.has_packet_length());
+ size_t total_length = rtp_packet.packet_length();
+
+ // Use RtpPacketReceived instead of more generic RtpPacket because former
+ // has a buildin convertion to RTPHeader.
+ RtpPacketReceived rtp_header;
+ RTC_PARSE_CHECK_OR_RETURN(
+ rtp_header.Parse(rtc::CopyOnWriteBuffer(rtp_packet.header())));
+
+ if (const RtpHeaderExtensionMap* extension_map = GetRtpHeaderExtensionMap(
+ rtp_packet.incoming(), rtp_header.Ssrc())) {
+ rtp_header.IdentifyExtensions(*extension_map);
+ }
+
+ RTPHeader parsed_header;
+ rtp_header.GetHeader(&parsed_header);
+
+ // Since we give the parser only a header, there is no way for it to know
+ // the padding length. The best solution would be to log the padding
+ // length in RTC event log. In absence of it, we assume the RTP packet to
+ // contain only padding, if the padding bit is set.
+ // TODO(webrtc:9730): Use a generic way to obtain padding length.
+ if (rtp_header.has_padding())
+ parsed_header.paddingLength = total_length - rtp_header.size();
+
+ RTC_PARSE_CHECK_OR_RETURN(event.has_timestamp_us());
+ int64_t timestamp_us = event.timestamp_us();
+ if (rtp_packet.incoming()) {
+ incoming_rtp_packets_map_[parsed_header.ssrc].push_back(
+ LoggedRtpPacketIncoming(Timestamp::Micros(timestamp_us),
+ parsed_header, rtp_header.size(),
+ total_length));
+ } else {
+ outgoing_rtp_packets_map_[parsed_header.ssrc].push_back(
+ LoggedRtpPacketOutgoing(Timestamp::Micros(timestamp_us),
+ parsed_header, rtp_header.size(),
+ total_length));
+ }
+ break;
+ }
+ case rtclog::Event::RTCP_EVENT: {
+ PacketDirection direction;
+ std::vector<uint8_t> packet;
+ auto status = GetRtcpPacket(event, &direction, &packet);
+ RTC_RETURN_IF_ERROR(status);
+ RTC_PARSE_CHECK_OR_RETURN(event.has_timestamp_us());
+ int64_t timestamp_us = event.timestamp_us();
+ if (direction == kIncomingPacket) {
+ // Currently incoming RTCP packets are logged twice, both for audio and
+ // video. Only act on one of them. Compare against the previous parsed
+ // incoming RTCP packet.
+ if (packet == last_incoming_rtcp_packet_)
+ break;
+ incoming_rtcp_packets_.push_back(
+ LoggedRtcpPacketIncoming(Timestamp::Micros(timestamp_us), packet));
+ last_incoming_rtcp_packet_ = packet;
+ } else {
+ outgoing_rtcp_packets_.push_back(
+ LoggedRtcpPacketOutgoing(Timestamp::Micros(timestamp_us), packet));
+ }
+ break;
+ }
+ case rtclog::Event::LOG_START: {
+ RTC_PARSE_CHECK_OR_RETURN(event.has_timestamp_us());
+ int64_t timestamp_us = event.timestamp_us();
+ start_log_events_.push_back(
+ LoggedStartEvent(Timestamp::Micros(timestamp_us)));
+ break;
+ }
+ case rtclog::Event::LOG_END: {
+ RTC_PARSE_CHECK_OR_RETURN(event.has_timestamp_us());
+ int64_t timestamp_us = event.timestamp_us();
+ stop_log_events_.push_back(
+ LoggedStopEvent(Timestamp::Micros(timestamp_us)));
+ break;
+ }
+ case rtclog::Event::AUDIO_PLAYOUT_EVENT: {
+ auto status_or_value = GetAudioPlayout(event);
+ RTC_RETURN_IF_ERROR(status_or_value.status());
+ LoggedAudioPlayoutEvent playout_event = status_or_value.value();
+ audio_playout_events_[playout_event.ssrc].push_back(playout_event);
+ break;
+ }
+ case rtclog::Event::LOSS_BASED_BWE_UPDATE: {
+ auto status_or_value = GetLossBasedBweUpdate(event);
+ RTC_RETURN_IF_ERROR(status_or_value.status());
+ bwe_loss_updates_.push_back(status_or_value.value());
+ break;
+ }
+ case rtclog::Event::DELAY_BASED_BWE_UPDATE: {
+ auto status_or_value = GetDelayBasedBweUpdate(event);
+ RTC_RETURN_IF_ERROR(status_or_value.status());
+ bwe_delay_updates_.push_back(status_or_value.value());
+ break;
+ }
+ case rtclog::Event::AUDIO_NETWORK_ADAPTATION_EVENT: {
+ auto status_or_value = GetAudioNetworkAdaptation(event);
+ RTC_RETURN_IF_ERROR(status_or_value.status());
+ LoggedAudioNetworkAdaptationEvent ana_event = status_or_value.value();
+ audio_network_adaptation_events_.push_back(ana_event);
+ break;
+ }
+ case rtclog::Event::BWE_PROBE_CLUSTER_CREATED_EVENT: {
+ auto status_or_value = GetBweProbeClusterCreated(event);
+ RTC_RETURN_IF_ERROR(status_or_value.status());
+ bwe_probe_cluster_created_events_.push_back(status_or_value.value());
+ break;
+ }
+ case rtclog::Event::BWE_PROBE_RESULT_EVENT: {
+ // Probe successes and failures are currently stored in the same proto
+ // message, we are moving towards separate messages. Probe results
+ // therefore need special treatment in the parser.
+ RTC_PARSE_CHECK_OR_RETURN(event.has_probe_result());
+ RTC_PARSE_CHECK_OR_RETURN(event.probe_result().has_result());
+ if (event.probe_result().result() == rtclog::BweProbeResult::SUCCESS) {
+ auto status_or_value = GetBweProbeSuccess(event);
+ RTC_RETURN_IF_ERROR(status_or_value.status());
+ bwe_probe_success_events_.push_back(status_or_value.value());
+ } else {
+ auto status_or_value = GetBweProbeFailure(event);
+ RTC_RETURN_IF_ERROR(status_or_value.status());
+ bwe_probe_failure_events_.push_back(status_or_value.value());
+ }
+ break;
+ }
+ case rtclog::Event::ALR_STATE_EVENT: {
+ auto status_or_value = GetAlrState(event);
+ RTC_RETURN_IF_ERROR(status_or_value.status());
+ alr_state_events_.push_back(status_or_value.value());
+ break;
+ }
+ case rtclog::Event::ICE_CANDIDATE_PAIR_CONFIG: {
+ auto status_or_value = GetIceCandidatePairConfig(event);
+ RTC_RETURN_IF_ERROR(status_or_value.status());
+ ice_candidate_pair_configs_.push_back(status_or_value.value());
+ break;
+ }
+ case rtclog::Event::ICE_CANDIDATE_PAIR_EVENT: {
+ auto status_or_value = GetIceCandidatePairEvent(event);
+ RTC_RETURN_IF_ERROR(status_or_value.status());
+ ice_candidate_pair_events_.push_back(status_or_value.value());
+ break;
+ }
+ case rtclog::Event::REMOTE_ESTIMATE: {
+ auto status_or_value = GetRemoteEstimateEvent(event);
+ RTC_RETURN_IF_ERROR(status_or_value.status());
+ remote_estimate_events_.push_back(status_or_value.value());
+ break;
+ }
+ case rtclog::Event::UNKNOWN_EVENT: {
+ break;
+ }
+ }
+ return ParseStatus::Success();
+}
+
+const RtpHeaderExtensionMap* ParsedRtcEventLog::GetRtpHeaderExtensionMap(
+ bool incoming,
+ uint32_t ssrc) {
+ auto& extensions_maps =
+ incoming ? incoming_rtp_extensions_maps_ : outgoing_rtp_extensions_maps_;
+ auto it = extensions_maps.find(ssrc);
+ if (it != extensions_maps.end()) {
+ return &(it->second);
+ }
+ if (parse_unconfigured_header_extensions_ ==
+ UnconfiguredHeaderExtensions::kAttemptWebrtcDefaultConfig) {
+ RTC_DLOG(LS_WARNING) << "Using default header extension map for SSRC "
+ << ssrc;
+ extensions_maps.insert(std::make_pair(ssrc, default_extension_map_));
+ return &default_extension_map_;
+ }
+ RTC_DLOG(LS_WARNING) << "Not parsing header extensions for SSRC " << ssrc
+ << ". No header extension map found.";
+ return nullptr;
+}
+
+ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::GetRtcpPacket(
+ const rtclog::Event& event,
+ PacketDirection* incoming,
+ std::vector<uint8_t>* packet) const {
+ RTC_PARSE_CHECK_OR_RETURN(event.has_type());
+ RTC_PARSE_CHECK_OR_RETURN_EQ(event.type(), rtclog::Event::RTCP_EVENT);
+ RTC_PARSE_CHECK_OR_RETURN(event.has_rtcp_packet());
+ const rtclog::RtcpPacket& rtcp_packet = event.rtcp_packet();
+ // Get direction of packet.
+ RTC_PARSE_CHECK_OR_RETURN(rtcp_packet.has_incoming());
+ if (incoming != nullptr) {
+ *incoming = rtcp_packet.incoming() ? kIncomingPacket : kOutgoingPacket;
+ }
+ // Get packet contents.
+ RTC_PARSE_CHECK_OR_RETURN(rtcp_packet.has_packet_data());
+ if (packet != nullptr) {
+ packet->resize(rtcp_packet.packet_data().size());
+ memcpy(packet->data(), rtcp_packet.packet_data().data(),
+ rtcp_packet.packet_data().size());
+ }
+ return ParseStatus::Success();
+}
+
+ParsedRtcEventLog::ParseStatusOr<rtclog::StreamConfig>
+ParsedRtcEventLog::GetVideoReceiveConfig(const rtclog::Event& event) const {
+ rtclog::StreamConfig config;
+ RTC_PARSE_CHECK_OR_RETURN(event.has_type());
+ RTC_PARSE_CHECK_OR_RETURN_EQ(event.type(),
+ rtclog::Event::VIDEO_RECEIVER_CONFIG_EVENT);
+ RTC_PARSE_CHECK_OR_RETURN(event.has_video_receiver_config());
+ const rtclog::VideoReceiveConfig& receiver_config =
+ event.video_receiver_config();
+ // Get SSRCs.
+ RTC_PARSE_CHECK_OR_RETURN(receiver_config.has_remote_ssrc());
+ config.remote_ssrc = receiver_config.remote_ssrc();
+ RTC_PARSE_CHECK_OR_RETURN(receiver_config.has_local_ssrc());
+ config.local_ssrc = receiver_config.local_ssrc();
+ config.rtx_ssrc = 0;
+ // Get RTCP settings.
+ RTC_PARSE_CHECK_OR_RETURN(receiver_config.has_rtcp_mode());
+ config.rtcp_mode = GetRuntimeRtcpMode(receiver_config.rtcp_mode());
+ RTC_PARSE_CHECK_OR_RETURN(receiver_config.has_remb());
+ config.remb = receiver_config.remb();
+
+ // Get RTX map.
+ std::map<uint32_t, const rtclog::RtxConfig> rtx_map;
+ for (int i = 0; i < receiver_config.rtx_map_size(); i++) {
+ const rtclog::RtxMap& map = receiver_config.rtx_map(i);
+ RTC_PARSE_CHECK_OR_RETURN(map.has_payload_type());
+ RTC_PARSE_CHECK_OR_RETURN(map.has_config());
+ RTC_PARSE_CHECK_OR_RETURN(map.config().has_rtx_ssrc());
+ RTC_PARSE_CHECK_OR_RETURN(map.config().has_rtx_payload_type());
+ rtx_map.insert(std::make_pair(map.payload_type(), map.config()));
+ }
+
+ // Get header extensions.
+ auto status = GetHeaderExtensions(&config.rtp_extensions,
+ receiver_config.header_extensions());
+ RTC_RETURN_IF_ERROR(status);
+
+ // Get decoders.
+ config.codecs.clear();
+ for (int i = 0; i < receiver_config.decoders_size(); i++) {
+ RTC_PARSE_CHECK_OR_RETURN(receiver_config.decoders(i).has_name());
+ RTC_PARSE_CHECK_OR_RETURN(receiver_config.decoders(i).has_payload_type());
+ int rtx_payload_type = 0;
+ auto rtx_it = rtx_map.find(receiver_config.decoders(i).payload_type());
+ if (rtx_it != rtx_map.end()) {
+ rtx_payload_type = rtx_it->second.rtx_payload_type();
+ if (config.rtx_ssrc != 0 &&
+ config.rtx_ssrc != rtx_it->second.rtx_ssrc()) {
+ RTC_LOG(LS_WARNING)
+ << "RtcEventLog protobuf contained different SSRCs for "
+ "different received RTX payload types. Will only use "
+ "rtx_ssrc = "
+ << config.rtx_ssrc << ".";
+ } else {
+ config.rtx_ssrc = rtx_it->second.rtx_ssrc();
+ }
+ }
+ config.codecs.emplace_back(receiver_config.decoders(i).name(),
+ receiver_config.decoders(i).payload_type(),
+ rtx_payload_type);
+ }
+ return config;
+}
+
+ParsedRtcEventLog::ParseStatusOr<rtclog::StreamConfig>
+ParsedRtcEventLog::GetVideoSendConfig(const rtclog::Event& event) const {
+ rtclog::StreamConfig config;
+ RTC_PARSE_CHECK_OR_RETURN(event.has_type());
+ RTC_PARSE_CHECK_OR_RETURN_EQ(event.type(),
+ rtclog::Event::VIDEO_SENDER_CONFIG_EVENT);
+ RTC_PARSE_CHECK_OR_RETURN(event.has_video_sender_config());
+ const rtclog::VideoSendConfig& sender_config = event.video_sender_config();
+
+ // Get SSRCs.
+ // VideoSendStreamConfig no longer stores multiple SSRCs. If you are
+ // analyzing a very old log, try building the parser from the same
+ // WebRTC version.
+ RTC_PARSE_CHECK_OR_RETURN_EQ(sender_config.ssrcs_size(), 1);
+ config.local_ssrc = sender_config.ssrcs(0);
+ RTC_PARSE_CHECK_OR_RETURN_LE(sender_config.rtx_ssrcs_size(), 1);
+ if (sender_config.rtx_ssrcs_size() == 1) {
+ config.rtx_ssrc = sender_config.rtx_ssrcs(0);
+ }
+
+ // Get header extensions.
+ auto status = GetHeaderExtensions(&config.rtp_extensions,
+ sender_config.header_extensions());
+ RTC_RETURN_IF_ERROR(status);
+
+ // Get the codec.
+ RTC_PARSE_CHECK_OR_RETURN(sender_config.has_encoder());
+ RTC_PARSE_CHECK_OR_RETURN(sender_config.encoder().has_name());
+ RTC_PARSE_CHECK_OR_RETURN(sender_config.encoder().has_payload_type());
+ config.codecs.emplace_back(
+ sender_config.encoder().name(), sender_config.encoder().payload_type(),
+ sender_config.has_rtx_payload_type() ? sender_config.rtx_payload_type()
+ : 0);
+ return config;
+}
+
+ParsedRtcEventLog::ParseStatusOr<rtclog::StreamConfig>
+ParsedRtcEventLog::GetAudioReceiveConfig(const rtclog::Event& event) const {
+ rtclog::StreamConfig config;
+ RTC_PARSE_CHECK_OR_RETURN(event.has_type());
+ RTC_PARSE_CHECK_OR_RETURN_EQ(event.type(),
+ rtclog::Event::AUDIO_RECEIVER_CONFIG_EVENT);
+ RTC_PARSE_CHECK_OR_RETURN(event.has_audio_receiver_config());
+ const rtclog::AudioReceiveConfig& receiver_config =
+ event.audio_receiver_config();
+ // Get SSRCs.
+ RTC_PARSE_CHECK_OR_RETURN(receiver_config.has_remote_ssrc());
+ config.remote_ssrc = receiver_config.remote_ssrc();
+ RTC_PARSE_CHECK_OR_RETURN(receiver_config.has_local_ssrc());
+ config.local_ssrc = receiver_config.local_ssrc();
+ // Get header extensions.
+ auto status = GetHeaderExtensions(&config.rtp_extensions,
+ receiver_config.header_extensions());
+ RTC_RETURN_IF_ERROR(status);
+
+ return config;
+}
+
+ParsedRtcEventLog::ParseStatusOr<rtclog::StreamConfig>
+ParsedRtcEventLog::GetAudioSendConfig(const rtclog::Event& event) const {
+ rtclog::StreamConfig config;
+ RTC_PARSE_CHECK_OR_RETURN(event.has_type());
+ RTC_PARSE_CHECK_OR_RETURN_EQ(event.type(),
+ rtclog::Event::AUDIO_SENDER_CONFIG_EVENT);
+ RTC_PARSE_CHECK_OR_RETURN(event.has_audio_sender_config());
+ const rtclog::AudioSendConfig& sender_config = event.audio_sender_config();
+ // Get SSRCs.
+ RTC_PARSE_CHECK_OR_RETURN(sender_config.has_ssrc());
+ config.local_ssrc = sender_config.ssrc();
+ // Get header extensions.
+ auto status = GetHeaderExtensions(&config.rtp_extensions,
+ sender_config.header_extensions());
+ RTC_RETURN_IF_ERROR(status);
+
+ return config;
+}
+
+ParsedRtcEventLog::ParseStatusOr<LoggedAudioPlayoutEvent>
+ParsedRtcEventLog::GetAudioPlayout(const rtclog::Event& event) const {
+ RTC_PARSE_CHECK_OR_RETURN(event.has_type());
+ RTC_PARSE_CHECK_OR_RETURN_EQ(event.type(),
+ rtclog::Event::AUDIO_PLAYOUT_EVENT);
+ RTC_PARSE_CHECK_OR_RETURN(event.has_audio_playout_event());
+ const rtclog::AudioPlayoutEvent& playout_event = event.audio_playout_event();
+ LoggedAudioPlayoutEvent res;
+ RTC_PARSE_CHECK_OR_RETURN(event.has_timestamp_us());
+ res.timestamp = Timestamp::Micros(event.timestamp_us());
+ RTC_PARSE_CHECK_OR_RETURN(playout_event.has_local_ssrc());
+ res.ssrc = playout_event.local_ssrc();
+ return res;
+}
+
+ParsedRtcEventLog::ParseStatusOr<LoggedBweLossBasedUpdate>
+ParsedRtcEventLog::GetLossBasedBweUpdate(const rtclog::Event& event) const {
+ RTC_PARSE_CHECK_OR_RETURN(event.has_type());
+ RTC_PARSE_CHECK_OR_RETURN_EQ(event.type(),
+ rtclog::Event::LOSS_BASED_BWE_UPDATE);
+ RTC_PARSE_CHECK_OR_RETURN(event.has_loss_based_bwe_update());
+ const rtclog::LossBasedBweUpdate& loss_event = event.loss_based_bwe_update();
+
+ LoggedBweLossBasedUpdate bwe_update;
+ RTC_CHECK(event.has_timestamp_us());
+ bwe_update.timestamp = Timestamp::Micros(event.timestamp_us());
+ RTC_PARSE_CHECK_OR_RETURN(loss_event.has_bitrate_bps());
+ bwe_update.bitrate_bps = loss_event.bitrate_bps();
+ RTC_PARSE_CHECK_OR_RETURN(loss_event.has_fraction_loss());
+ bwe_update.fraction_lost = loss_event.fraction_loss();
+ RTC_PARSE_CHECK_OR_RETURN(loss_event.has_total_packets());
+ bwe_update.expected_packets = loss_event.total_packets();
+ return bwe_update;
+}
+
+ParsedRtcEventLog::ParseStatusOr<LoggedBweDelayBasedUpdate>
+ParsedRtcEventLog::GetDelayBasedBweUpdate(const rtclog::Event& event) const {
+ RTC_PARSE_CHECK_OR_RETURN(event.has_type());
+ RTC_PARSE_CHECK_OR_RETURN_EQ(event.type(),
+ rtclog::Event::DELAY_BASED_BWE_UPDATE);
+ RTC_PARSE_CHECK_OR_RETURN(event.has_delay_based_bwe_update());
+ const rtclog::DelayBasedBweUpdate& delay_event =
+ event.delay_based_bwe_update();
+
+ LoggedBweDelayBasedUpdate res;
+ RTC_PARSE_CHECK_OR_RETURN(event.has_timestamp_us());
+ res.timestamp = Timestamp::Micros(event.timestamp_us());
+ RTC_PARSE_CHECK_OR_RETURN(delay_event.has_bitrate_bps());
+ res.bitrate_bps = delay_event.bitrate_bps();
+ RTC_PARSE_CHECK_OR_RETURN(delay_event.has_detector_state());
+ res.detector_state = GetRuntimeDetectorState(delay_event.detector_state());
+ return res;
+}
+
+ParsedRtcEventLog::ParseStatusOr<LoggedAudioNetworkAdaptationEvent>
+ParsedRtcEventLog::GetAudioNetworkAdaptation(const rtclog::Event& event) const {
+ RTC_PARSE_CHECK_OR_RETURN(event.has_type());
+ RTC_PARSE_CHECK_OR_RETURN_EQ(event.type(),
+ rtclog::Event::AUDIO_NETWORK_ADAPTATION_EVENT);
+ RTC_PARSE_CHECK_OR_RETURN(event.has_audio_network_adaptation());
+ const rtclog::AudioNetworkAdaptation& ana_event =
+ event.audio_network_adaptation();
+
+ LoggedAudioNetworkAdaptationEvent res;
+ RTC_PARSE_CHECK_OR_RETURN(event.has_timestamp_us());
+ res.timestamp = Timestamp::Micros(event.timestamp_us());
+ if (ana_event.has_bitrate_bps())
+ res.config.bitrate_bps = ana_event.bitrate_bps();
+ if (ana_event.has_enable_fec())
+ res.config.enable_fec = ana_event.enable_fec();
+ if (ana_event.has_enable_dtx())
+ res.config.enable_dtx = ana_event.enable_dtx();
+ if (ana_event.has_frame_length_ms())
+ res.config.frame_length_ms = ana_event.frame_length_ms();
+ if (ana_event.has_num_channels())
+ res.config.num_channels = ana_event.num_channels();
+ if (ana_event.has_uplink_packet_loss_fraction())
+ res.config.uplink_packet_loss_fraction =
+ ana_event.uplink_packet_loss_fraction();
+ return res;
+}
+
+ParsedRtcEventLog::ParseStatusOr<LoggedBweProbeClusterCreatedEvent>
+ParsedRtcEventLog::GetBweProbeClusterCreated(const rtclog::Event& event) const {
+ RTC_PARSE_CHECK_OR_RETURN(event.has_type());
+ RTC_PARSE_CHECK_OR_RETURN_EQ(event.type(),
+ rtclog::Event::BWE_PROBE_CLUSTER_CREATED_EVENT);
+ RTC_PARSE_CHECK_OR_RETURN(event.has_probe_cluster());
+ const rtclog::BweProbeCluster& pcc_event = event.probe_cluster();
+ LoggedBweProbeClusterCreatedEvent res;
+ RTC_PARSE_CHECK_OR_RETURN(event.has_timestamp_us());
+ res.timestamp = Timestamp::Micros(event.timestamp_us());
+ RTC_PARSE_CHECK_OR_RETURN(pcc_event.has_id());
+ res.id = pcc_event.id();
+ RTC_PARSE_CHECK_OR_RETURN(pcc_event.has_bitrate_bps());
+ res.bitrate_bps = pcc_event.bitrate_bps();
+ RTC_PARSE_CHECK_OR_RETURN(pcc_event.has_min_packets());
+ res.min_packets = pcc_event.min_packets();
+ RTC_PARSE_CHECK_OR_RETURN(pcc_event.has_min_bytes());
+ res.min_bytes = pcc_event.min_bytes();
+ return res;
+}
+
+ParsedRtcEventLog::ParseStatusOr<LoggedBweProbeFailureEvent>
+ParsedRtcEventLog::GetBweProbeFailure(const rtclog::Event& event) const {
+ RTC_PARSE_CHECK_OR_RETURN(event.has_type());
+ RTC_PARSE_CHECK_OR_RETURN_EQ(event.type(),
+ rtclog::Event::BWE_PROBE_RESULT_EVENT);
+ RTC_PARSE_CHECK_OR_RETURN(event.has_probe_result());
+ const rtclog::BweProbeResult& pr_event = event.probe_result();
+ RTC_PARSE_CHECK_OR_RETURN(pr_event.has_result());
+ RTC_PARSE_CHECK_OR_RETURN_NE(pr_event.result(),
+ rtclog::BweProbeResult::SUCCESS);
+
+ LoggedBweProbeFailureEvent res;
+ RTC_PARSE_CHECK_OR_RETURN(event.has_timestamp_us());
+ res.timestamp = Timestamp::Micros(event.timestamp_us());
+ RTC_PARSE_CHECK_OR_RETURN(pr_event.has_id());
+ res.id = pr_event.id();
+ RTC_PARSE_CHECK_OR_RETURN(pr_event.has_result());
+ if (pr_event.result() ==
+ rtclog::BweProbeResult::INVALID_SEND_RECEIVE_INTERVAL) {
+ res.failure_reason = ProbeFailureReason::kInvalidSendReceiveInterval;
+ } else if (pr_event.result() ==
+ rtclog::BweProbeResult::INVALID_SEND_RECEIVE_RATIO) {
+ res.failure_reason = ProbeFailureReason::kInvalidSendReceiveRatio;
+ } else if (pr_event.result() == rtclog::BweProbeResult::TIMEOUT) {
+ res.failure_reason = ProbeFailureReason::kTimeout;
+ } else {
+ RTC_DCHECK_NOTREACHED();
+ }
+ RTC_PARSE_CHECK_OR_RETURN(!pr_event.has_bitrate_bps());
+
+ return res;
+}
+
+ParsedRtcEventLog::ParseStatusOr<LoggedBweProbeSuccessEvent>
+ParsedRtcEventLog::GetBweProbeSuccess(const rtclog::Event& event) const {
+ RTC_PARSE_CHECK_OR_RETURN(event.has_type());
+ RTC_PARSE_CHECK_OR_RETURN_EQ(event.type(),
+ rtclog::Event::BWE_PROBE_RESULT_EVENT);
+ RTC_PARSE_CHECK_OR_RETURN(event.has_probe_result());
+ const rtclog::BweProbeResult& pr_event = event.probe_result();
+ RTC_PARSE_CHECK_OR_RETURN(pr_event.has_result());
+ RTC_PARSE_CHECK_OR_RETURN_EQ(pr_event.result(),
+ rtclog::BweProbeResult::SUCCESS);
+
+ LoggedBweProbeSuccessEvent res;
+ RTC_PARSE_CHECK_OR_RETURN(event.has_timestamp_us());
+ res.timestamp = Timestamp::Micros(event.timestamp_us());
+ RTC_PARSE_CHECK_OR_RETURN(pr_event.has_id());
+ res.id = pr_event.id();
+ RTC_PARSE_CHECK_OR_RETURN(pr_event.has_bitrate_bps());
+ res.bitrate_bps = pr_event.bitrate_bps();
+
+ return res;
+}
+
+ParsedRtcEventLog::ParseStatusOr<LoggedAlrStateEvent>
+ParsedRtcEventLog::GetAlrState(const rtclog::Event& event) const {
+ RTC_PARSE_CHECK_OR_RETURN(event.has_type());
+ RTC_PARSE_CHECK_OR_RETURN_EQ(event.type(), rtclog::Event::ALR_STATE_EVENT);
+ RTC_PARSE_CHECK_OR_RETURN(event.has_alr_state());
+ const rtclog::AlrState& alr_event = event.alr_state();
+ LoggedAlrStateEvent res;
+ RTC_PARSE_CHECK_OR_RETURN(event.has_timestamp_us());
+ res.timestamp = Timestamp::Micros(event.timestamp_us());
+ RTC_PARSE_CHECK_OR_RETURN(alr_event.has_in_alr());
+ res.in_alr = alr_event.in_alr();
+
+ return res;
+}
+
+ParsedRtcEventLog::ParseStatusOr<LoggedIceCandidatePairConfig>
+ParsedRtcEventLog::GetIceCandidatePairConfig(
+ const rtclog::Event& rtc_event) const {
+ RTC_PARSE_CHECK_OR_RETURN(rtc_event.has_type());
+ RTC_PARSE_CHECK_OR_RETURN_EQ(rtc_event.type(),
+ rtclog::Event::ICE_CANDIDATE_PAIR_CONFIG);
+ LoggedIceCandidatePairConfig res;
+ const rtclog::IceCandidatePairConfig& config =
+ rtc_event.ice_candidate_pair_config();
+ RTC_PARSE_CHECK_OR_RETURN(rtc_event.has_timestamp_us());
+ res.timestamp = Timestamp::Micros(rtc_event.timestamp_us());
+ RTC_PARSE_CHECK_OR_RETURN(config.has_config_type());
+ res.type = GetRuntimeIceCandidatePairConfigType(config.config_type());
+ RTC_PARSE_CHECK_OR_RETURN(config.has_candidate_pair_id());
+ res.candidate_pair_id = config.candidate_pair_id();
+ RTC_PARSE_CHECK_OR_RETURN(config.has_local_candidate_type());
+ res.local_candidate_type =
+ GetRuntimeIceCandidateType(config.local_candidate_type());
+ RTC_PARSE_CHECK_OR_RETURN(config.has_local_relay_protocol());
+ res.local_relay_protocol =
+ GetRuntimeIceCandidatePairProtocol(config.local_relay_protocol());
+ RTC_PARSE_CHECK_OR_RETURN(config.has_local_network_type());
+ res.local_network_type =
+ GetRuntimeIceCandidateNetworkType(config.local_network_type());
+ RTC_PARSE_CHECK_OR_RETURN(config.has_local_address_family());
+ res.local_address_family =
+ GetRuntimeIceCandidatePairAddressFamily(config.local_address_family());
+ RTC_PARSE_CHECK_OR_RETURN(config.has_remote_candidate_type());
+ res.remote_candidate_type =
+ GetRuntimeIceCandidateType(config.remote_candidate_type());
+ RTC_PARSE_CHECK_OR_RETURN(config.has_remote_address_family());
+ res.remote_address_family =
+ GetRuntimeIceCandidatePairAddressFamily(config.remote_address_family());
+ RTC_PARSE_CHECK_OR_RETURN(config.has_candidate_pair_protocol());
+ res.candidate_pair_protocol =
+ GetRuntimeIceCandidatePairProtocol(config.candidate_pair_protocol());
+ return res;
+}
+
+ParsedRtcEventLog::ParseStatusOr<LoggedIceCandidatePairEvent>
+ParsedRtcEventLog::GetIceCandidatePairEvent(
+ const rtclog::Event& rtc_event) const {
+ RTC_PARSE_CHECK_OR_RETURN(rtc_event.has_type());
+ RTC_PARSE_CHECK_OR_RETURN_EQ(rtc_event.type(),
+ rtclog::Event::ICE_CANDIDATE_PAIR_EVENT);
+ LoggedIceCandidatePairEvent res;
+ const rtclog::IceCandidatePairEvent& event =
+ rtc_event.ice_candidate_pair_event();
+ RTC_PARSE_CHECK_OR_RETURN(rtc_event.has_timestamp_us());
+ res.timestamp = Timestamp::Micros(rtc_event.timestamp_us());
+ RTC_PARSE_CHECK_OR_RETURN(event.has_event_type());
+ res.type = GetRuntimeIceCandidatePairEventType(event.event_type());
+ RTC_PARSE_CHECK_OR_RETURN(event.has_candidate_pair_id());
+ res.candidate_pair_id = event.candidate_pair_id();
+ // transaction_id is not supported by rtclog::Event
+ res.transaction_id = 0;
+ return res;
+}
+
+ParsedRtcEventLog::ParseStatusOr<LoggedRemoteEstimateEvent>
+ParsedRtcEventLog::GetRemoteEstimateEvent(const rtclog::Event& event) const {
+ RTC_PARSE_CHECK_OR_RETURN(event.has_type());
+ RTC_PARSE_CHECK_OR_RETURN_EQ(event.type(), rtclog::Event::REMOTE_ESTIMATE);
+ LoggedRemoteEstimateEvent res;
+ const rtclog::RemoteEstimate& remote_estimate_event = event.remote_estimate();
+ RTC_PARSE_CHECK_OR_RETURN(event.has_timestamp_us());
+ res.timestamp = Timestamp::Micros(event.timestamp_us());
+ if (remote_estimate_event.has_link_capacity_lower_kbps())
+ res.link_capacity_lower = DataRate::KilobitsPerSec(
+ remote_estimate_event.link_capacity_lower_kbps());
+ if (remote_estimate_event.has_link_capacity_upper_kbps())
+ res.link_capacity_upper = DataRate::KilobitsPerSec(
+ remote_estimate_event.link_capacity_upper_kbps());
+ return res;
+}
+
+// Returns the MediaType for registered SSRCs. Search from the end to use last
+// registered types first.
+ParsedRtcEventLog::MediaType ParsedRtcEventLog::GetMediaType(
+ uint32_t ssrc,
+ PacketDirection direction) const {
+ if (direction == kIncomingPacket) {
+ if (std::find(incoming_video_ssrcs_.begin(), incoming_video_ssrcs_.end(),
+ ssrc) != incoming_video_ssrcs_.end()) {
+ return MediaType::VIDEO;
+ }
+ if (std::find(incoming_audio_ssrcs_.begin(), incoming_audio_ssrcs_.end(),
+ ssrc) != incoming_audio_ssrcs_.end()) {
+ return MediaType::AUDIO;
+ }
+ } else {
+ if (std::find(outgoing_video_ssrcs_.begin(), outgoing_video_ssrcs_.end(),
+ ssrc) != outgoing_video_ssrcs_.end()) {
+ return MediaType::VIDEO;
+ }
+ if (std::find(outgoing_audio_ssrcs_.begin(), outgoing_audio_ssrcs_.end(),
+ ssrc) != outgoing_audio_ssrcs_.end()) {
+ return MediaType::AUDIO;
+ }
+ }
+ return MediaType::ANY;
+}
+
+std::vector<InferredRouteChangeEvent> ParsedRtcEventLog::GetRouteChanges()
+ const {
+ std::vector<InferredRouteChangeEvent> route_changes;
+ for (auto& candidate : ice_candidate_pair_configs()) {
+ if (candidate.type == IceCandidatePairConfigType::kSelected) {
+ InferredRouteChangeEvent route;
+ route.route_id = candidate.candidate_pair_id;
+ route.log_time = Timestamp::Millis(candidate.log_time_ms());
+
+ route.send_overhead = kUdpOverhead + kSrtpOverhead + kIpv4Overhead;
+ if (candidate.remote_address_family ==
+ IceCandidatePairAddressFamily::kIpv6)
+ route.send_overhead += kIpv6Overhead - kIpv4Overhead;
+ if (candidate.remote_candidate_type != IceCandidateType::kLocal)
+ route.send_overhead += kStunOverhead;
+ route.return_overhead = kUdpOverhead + kSrtpOverhead + kIpv4Overhead;
+ if (candidate.remote_address_family ==
+ IceCandidatePairAddressFamily::kIpv6)
+ route.return_overhead += kIpv6Overhead - kIpv4Overhead;
+ if (candidate.remote_candidate_type != IceCandidateType::kLocal)
+ route.return_overhead += kStunOverhead;
+ route_changes.push_back(route);
+ }
+ }
+ return route_changes;
+}
+
+std::vector<LoggedPacketInfo> ParsedRtcEventLog::GetPacketInfos(
+ PacketDirection direction) const {
+ std::map<uint32_t, MediaStreamInfo> streams;
+ if (direction == PacketDirection::kIncomingPacket) {
+ AddRecvStreamInfos(&streams, audio_recv_configs(), LoggedMediaType::kAudio);
+ AddRecvStreamInfos(&streams, video_recv_configs(), LoggedMediaType::kVideo);
+ } else if (direction == PacketDirection::kOutgoingPacket) {
+ AddSendStreamInfos(&streams, audio_send_configs(), LoggedMediaType::kAudio);
+ AddSendStreamInfos(&streams, video_send_configs(), LoggedMediaType::kVideo);
+ }
+
+ std::vector<OverheadChangeEvent> overheads =
+ GetOverheadChangingEvents(GetRouteChanges(), direction);
+ auto overhead_iter = overheads.begin();
+ std::vector<LoggedPacketInfo> packets;
+ std::map<int64_t, size_t> indices;
+ uint16_t current_overhead = kDefaultOverhead;
+ Timestamp last_log_time = Timestamp::Zero();
+ RtpSequenceNumberUnwrapper seq_num_unwrapper;
+
+ auto advance_time = [&](Timestamp new_log_time) {
+ if (overhead_iter != overheads.end() &&
+ new_log_time >= overhead_iter->timestamp) {
+ current_overhead = overhead_iter->overhead;
+ ++overhead_iter;
+ }
+ // If we have a large time delta, it can be caused by a gap in logging,
+ // therefore we don't want to match up sequence numbers as we might have had
+ // a wraparound.
+ if (new_log_time - last_log_time > TimeDelta::Seconds(30)) {
+ seq_num_unwrapper.Reset();
+ indices.clear();
+ }
+ RTC_DCHECK_GE(new_log_time, last_log_time);
+ last_log_time = new_log_time;
+ };
+
+ auto rtp_handler = [&](const LoggedRtpPacket& rtp) {
+ advance_time(rtp.log_time());
+ MediaStreamInfo* stream = &streams[rtp.header.ssrc];
+ Timestamp capture_time = Timestamp::MinusInfinity();
+ if (!stream->rtx) {
+ // RTX copy the timestamp of the retransmitted packets. This means that
+ // RTX streams don't have a unique clock offset and frequency, so
+ // the RTP timstamps can't be unwrapped.
+
+ // Add an offset to avoid `capture_ticks` to become negative in the case
+ // of reordering.
+ constexpr int64_t kStartingCaptureTimeTicks = 90 * 48 * 10000;
+ int64_t capture_ticks =
+ kStartingCaptureTimeTicks +
+ stream->unwrap_capture_ticks.Unwrap(rtp.header.timestamp);
+ // TODO(srte): Use logged sample rate when it is added to the format.
+ capture_time = Timestamp::Seconds(
+ capture_ticks /
+ (stream->media_type == LoggedMediaType::kAudio ? 48000.0 : 90000.0));
+ }
+ LoggedPacketInfo logged(rtp, stream->media_type, stream->rtx, capture_time);
+ logged.overhead = current_overhead;
+ if (logged.has_transport_seq_no) {
+ logged.log_feedback_time = Timestamp::PlusInfinity();
+ int64_t unwrapped_seq_num =
+ seq_num_unwrapper.Unwrap(logged.transport_seq_no);
+ if (indices.find(unwrapped_seq_num) != indices.end()) {
+ auto prev = packets[indices[unwrapped_seq_num]];
+ RTC_LOG(LS_WARNING)
+ << "Repeated sent packet sequence number: " << unwrapped_seq_num
+ << " Packet time:" << prev.log_packet_time.seconds() << "s vs "
+ << logged.log_packet_time.seconds()
+ << "s at:" << rtp.log_time_ms() / 1000;
+ }
+ indices[unwrapped_seq_num] = packets.size();
+ }
+ packets.push_back(logged);
+ };
+
+ Timestamp feedback_base_time = Timestamp::MinusInfinity();
+ Timestamp last_feedback_base_time = Timestamp::MinusInfinity();
+
+ auto feedback_handler =
+ [&](const LoggedRtcpPacketTransportFeedback& logged_rtcp) {
+ auto log_feedback_time = logged_rtcp.log_time();
+ advance_time(log_feedback_time);
+ const auto& feedback = logged_rtcp.transport_feedback;
+ // Add timestamp deltas to a local time base selected on first packet
+ // arrival. This won't be the true time base, but makes it easier to
+ // manually inspect time stamps.
+ if (!last_feedback_base_time.IsFinite()) {
+ feedback_base_time = log_feedback_time;
+ } else {
+ feedback_base_time += feedback.GetBaseDelta(last_feedback_base_time);
+ }
+ last_feedback_base_time = feedback.BaseTime();
+
+ std::vector<LoggedPacketInfo*> packet_feedbacks;
+ packet_feedbacks.reserve(feedback.GetPacketStatusCount());
+ std::vector<int64_t> unknown_seq_nums;
+ feedback.ForAllPackets([&](uint16_t sequence_number,
+ TimeDelta delta_since_base) {
+ int64_t unwrapped_seq_num = seq_num_unwrapper.Unwrap(sequence_number);
+ auto it = indices.find(unwrapped_seq_num);
+ if (it == indices.end()) {
+ unknown_seq_nums.push_back(unwrapped_seq_num);
+ return;
+ }
+ LoggedPacketInfo* sent = &packets[it->second];
+ if (log_feedback_time - sent->log_packet_time >
+ TimeDelta::Seconds(60)) {
+ RTC_LOG(LS_WARNING)
+ << "Received very late feedback, possibly due to wraparound.";
+ return;
+ }
+ if (delta_since_base.IsFinite()) {
+ if (sent->reported_recv_time.IsInfinite()) {
+ sent->reported_recv_time = feedback_base_time + delta_since_base;
+ sent->log_feedback_time = log_feedback_time;
+ }
+ } else {
+ if (sent->reported_recv_time.IsInfinite() &&
+ sent->log_feedback_time.IsInfinite()) {
+ sent->reported_recv_time = Timestamp::PlusInfinity();
+ sent->log_feedback_time = log_feedback_time;
+ }
+ }
+ packet_feedbacks.push_back(sent);
+ });
+ if (!unknown_seq_nums.empty()) {
+ RTC_LOG(LS_WARNING)
+ << "Received feedback for unknown packets: "
+ << unknown_seq_nums.front() << " - " << unknown_seq_nums.back();
+ }
+ if (packet_feedbacks.empty())
+ return;
+ LoggedPacketInfo* last = packet_feedbacks.back();
+ last->last_in_feedback = true;
+ for (LoggedPacketInfo* fb : packet_feedbacks) {
+ if (direction == PacketDirection::kOutgoingPacket) {
+ if (last->reported_recv_time.IsFinite() &&
+ fb->reported_recv_time.IsFinite()) {
+ fb->feedback_hold_duration =
+ last->reported_recv_time - fb->reported_recv_time;
+ }
+ } else {
+ fb->feedback_hold_duration =
+ log_feedback_time - fb->log_packet_time;
+ }
+ }
+ };
+
+ RtcEventProcessor process;
+ for (const auto& rtp_packets : rtp_packets_by_ssrc(direction)) {
+ process.AddEvents(rtp_packets.packet_view, rtp_handler);
+ }
+ if (direction == PacketDirection::kOutgoingPacket) {
+ process.AddEvents(incoming_transport_feedback_, feedback_handler);
+ } else {
+ process.AddEvents(outgoing_transport_feedback_, feedback_handler);
+ }
+ process.ProcessEventsInOrder();
+ return packets;
+}
+
+std::vector<LoggedIceCandidatePairConfig> ParsedRtcEventLog::GetIceCandidates()
+ const {
+ std::vector<LoggedIceCandidatePairConfig> candidates;
+ std::set<uint32_t> added;
+ for (auto& candidate : ice_candidate_pair_configs()) {
+ if (added.find(candidate.candidate_pair_id) == added.end()) {
+ candidates.push_back(candidate);
+ added.insert(candidate.candidate_pair_id);
+ }
+ }
+ return candidates;
+}
+
+std::vector<LoggedIceEvent> ParsedRtcEventLog::GetIceEvents() const {
+ using CheckType = IceCandidatePairEventType;
+ using ConfigType = IceCandidatePairConfigType;
+ using Combined = LoggedIceEventType;
+ std::map<CheckType, Combined> check_map(
+ {{CheckType::kCheckSent, Combined::kCheckSent},
+ {CheckType::kCheckReceived, Combined::kCheckReceived},
+ {CheckType::kCheckResponseSent, Combined::kCheckResponseSent},
+ {CheckType::kCheckResponseReceived, Combined::kCheckResponseReceived}});
+ std::map<ConfigType, Combined> config_map(
+ {{ConfigType::kAdded, Combined::kAdded},
+ {ConfigType::kUpdated, Combined::kUpdated},
+ {ConfigType::kDestroyed, Combined::kDestroyed},
+ {ConfigType::kSelected, Combined::kSelected}});
+ std::vector<LoggedIceEvent> log_events;
+ auto handle_check = [&](const LoggedIceCandidatePairEvent& check) {
+ log_events.push_back(LoggedIceEvent{check.candidate_pair_id,
+ Timestamp::Millis(check.log_time_ms()),
+ check_map[check.type]});
+ };
+ auto handle_config = [&](const LoggedIceCandidatePairConfig& conf) {
+ log_events.push_back(LoggedIceEvent{conf.candidate_pair_id,
+ Timestamp::Millis(conf.log_time_ms()),
+ config_map[conf.type]});
+ };
+ RtcEventProcessor process;
+ process.AddEvents(ice_candidate_pair_events(), handle_check);
+ process.AddEvents(ice_candidate_pair_configs(), handle_config);
+ process.ProcessEventsInOrder();
+ return log_events;
+}
+
+const std::vector<MatchedSendArrivalTimes> GetNetworkTrace(
+ const ParsedRtcEventLog& parsed_log) {
+ std::vector<MatchedSendArrivalTimes> rtp_rtcp_matched;
+ for (auto& packet :
+ parsed_log.GetPacketInfos(PacketDirection::kOutgoingPacket)) {
+ if (packet.log_feedback_time.IsFinite()) {
+ rtp_rtcp_matched.emplace_back(packet.log_feedback_time.ms(),
+ packet.log_packet_time.ms(),
+ packet.reported_recv_time.ms_or(
+ MatchedSendArrivalTimes::kNotReceived),
+ packet.size);
+ }
+ }
+ return rtp_rtcp_matched;
+}
+
+// Helper functions for new format start here
+ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreParsedNewFormatEvent(
+ const rtclog2::EventStream& stream) {
+ RTC_DCHECK_EQ(stream.stream_size(), 0); // No legacy format event.
+
+ RTC_DCHECK_EQ(
+ stream.incoming_rtp_packets_size() + stream.outgoing_rtp_packets_size() +
+ stream.incoming_rtcp_packets_size() +
+ stream.outgoing_rtcp_packets_size() +
+ stream.audio_playout_events_size() + stream.begin_log_events_size() +
+ stream.end_log_events_size() + stream.loss_based_bwe_updates_size() +
+ stream.delay_based_bwe_updates_size() +
+ stream.dtls_transport_state_events_size() +
+ stream.dtls_writable_states_size() +
+ stream.audio_network_adaptations_size() +
+ stream.probe_clusters_size() + stream.probe_success_size() +
+ stream.probe_failure_size() + stream.alr_states_size() +
+ stream.route_changes_size() + stream.remote_estimates_size() +
+ stream.ice_candidate_configs_size() +
+ stream.ice_candidate_events_size() +
+ 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.generic_packets_sent_size() +
+ stream.generic_packets_received_size() +
+ stream.generic_acks_received_size() +
+ stream.frame_decoded_events_size() +
+ stream.neteq_set_minimum_delay_size(),
+ 1u);
+
+ if (stream.incoming_rtp_packets_size() == 1) {
+ return StoreIncomingRtpPackets(stream.incoming_rtp_packets(0));
+ } else if (stream.outgoing_rtp_packets_size() == 1) {
+ return StoreOutgoingRtpPackets(stream.outgoing_rtp_packets(0));
+ } else if (stream.incoming_rtcp_packets_size() == 1) {
+ return StoreIncomingRtcpPackets(stream.incoming_rtcp_packets(0));
+ } else if (stream.outgoing_rtcp_packets_size() == 1) {
+ return StoreOutgoingRtcpPackets(stream.outgoing_rtcp_packets(0));
+ } else if (stream.audio_playout_events_size() == 1) {
+ return StoreAudioPlayoutEvent(stream.audio_playout_events(0));
+ } else if (stream.begin_log_events_size() == 1) {
+ return StoreStartEvent(stream.begin_log_events(0));
+ } else if (stream.end_log_events_size() == 1) {
+ return StoreStopEvent(stream.end_log_events(0));
+ } else if (stream.loss_based_bwe_updates_size() == 1) {
+ return StoreBweLossBasedUpdate(stream.loss_based_bwe_updates(0));
+ } else if (stream.delay_based_bwe_updates_size() == 1) {
+ return StoreBweDelayBasedUpdate(stream.delay_based_bwe_updates(0));
+ } else if (stream.dtls_transport_state_events_size() == 1) {
+ return StoreDtlsTransportState(stream.dtls_transport_state_events(0));
+ } else if (stream.dtls_writable_states_size() == 1) {
+ return StoreDtlsWritableState(stream.dtls_writable_states(0));
+ } else if (stream.audio_network_adaptations_size() == 1) {
+ return StoreAudioNetworkAdaptationEvent(
+ stream.audio_network_adaptations(0));
+ } else if (stream.probe_clusters_size() == 1) {
+ return StoreBweProbeClusterCreated(stream.probe_clusters(0));
+ } else if (stream.probe_success_size() == 1) {
+ return StoreBweProbeSuccessEvent(stream.probe_success(0));
+ } else if (stream.probe_failure_size() == 1) {
+ return StoreBweProbeFailureEvent(stream.probe_failure(0));
+ } else if (stream.alr_states_size() == 1) {
+ return StoreAlrStateEvent(stream.alr_states(0));
+ } else if (stream.route_changes_size() == 1) {
+ return StoreRouteChangeEvent(stream.route_changes(0));
+ } else if (stream.remote_estimates_size() == 1) {
+ return StoreRemoteEstimateEvent(stream.remote_estimates(0));
+ } else if (stream.ice_candidate_configs_size() == 1) {
+ return StoreIceCandidatePairConfig(stream.ice_candidate_configs(0));
+ } else if (stream.ice_candidate_events_size() == 1) {
+ return StoreIceCandidateEvent(stream.ice_candidate_events(0));
+ } else if (stream.audio_recv_stream_configs_size() == 1) {
+ return StoreAudioRecvConfig(stream.audio_recv_stream_configs(0));
+ } else if (stream.audio_send_stream_configs_size() == 1) {
+ return StoreAudioSendConfig(stream.audio_send_stream_configs(0));
+ } else if (stream.video_recv_stream_configs_size() == 1) {
+ return StoreVideoRecvConfig(stream.video_recv_stream_configs(0));
+ } else if (stream.video_send_stream_configs_size() == 1) {
+ return StoreVideoSendConfig(stream.video_send_stream_configs(0));
+ } else if (stream.generic_packets_received_size() == 1) {
+ return StoreGenericPacketReceivedEvent(stream.generic_packets_received(0));
+ } else if (stream.generic_packets_sent_size() == 1) {
+ return StoreGenericPacketSentEvent(stream.generic_packets_sent(0));
+ } else if (stream.generic_acks_received_size() == 1) {
+ return StoreGenericAckReceivedEvent(stream.generic_acks_received(0));
+ } else if (stream.frame_decoded_events_size() == 1) {
+ return StoreFrameDecodedEvents(stream.frame_decoded_events(0));
+ } else if (stream.neteq_set_minimum_delay_size() == 1) {
+ return StoreNetEqSetMinimumDelay(stream.neteq_set_minimum_delay(0));
+ } else {
+ RTC_DCHECK_NOTREACHED();
+ return ParseStatus::Success();
+ }
+}
+
+ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreAlrStateEvent(
+ const rtclog2::AlrState& proto) {
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_timestamp_ms());
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_in_alr());
+ LoggedAlrStateEvent alr_event;
+ alr_event.timestamp = Timestamp::Millis(proto.timestamp_ms());
+ alr_event.in_alr = proto.in_alr();
+
+ alr_state_events_.push_back(alr_event);
+ // TODO(terelius): Should we delta encode this event type?
+ return ParseStatus::Success();
+}
+
+ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreRouteChangeEvent(
+ const rtclog2::RouteChange& proto) {
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_timestamp_ms());
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_connected());
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_overhead());
+ LoggedRouteChangeEvent route_event;
+ route_event.timestamp = Timestamp::Millis(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?
+ return ParseStatus::Success();
+}
+
+ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreRemoteEstimateEvent(
+ const rtclog2::RemoteEstimates& proto) {
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_timestamp_ms());
+ // Base event
+ LoggedRemoteEstimateEvent base_event;
+ base_event.timestamp = Timestamp::Millis(proto.timestamp_ms());
+
+ absl::optional<uint64_t> base_link_capacity_lower_kbps;
+ if (proto.has_link_capacity_lower_kbps()) {
+ base_link_capacity_lower_kbps = proto.link_capacity_lower_kbps();
+ base_event.link_capacity_lower =
+ DataRate::KilobitsPerSec(proto.link_capacity_lower_kbps());
+ }
+
+ absl::optional<uint64_t> base_link_capacity_upper_kbps;
+ if (proto.has_link_capacity_upper_kbps()) {
+ base_link_capacity_upper_kbps = proto.link_capacity_upper_kbps();
+ base_event.link_capacity_upper =
+ DataRate::KilobitsPerSec(proto.link_capacity_upper_kbps());
+ }
+
+ remote_estimate_events_.push_back(base_event);
+
+ const size_t number_of_deltas =
+ proto.has_number_of_deltas() ? proto.number_of_deltas() : 0u;
+ if (number_of_deltas == 0) {
+ return ParseStatus::Success();
+ }
+
+ // timestamp_ms
+ auto timestamp_ms_values =
+ DecodeDeltas(proto.timestamp_ms_deltas(),
+ ToUnsigned(proto.timestamp_ms()), number_of_deltas);
+ RTC_PARSE_CHECK_OR_RETURN_EQ(timestamp_ms_values.size(), number_of_deltas);
+
+ // link_capacity_lower_kbps
+ auto link_capacity_lower_kbps_values =
+ DecodeDeltas(proto.link_capacity_lower_kbps_deltas(),
+ base_link_capacity_lower_kbps, number_of_deltas);
+ RTC_PARSE_CHECK_OR_RETURN_EQ(link_capacity_lower_kbps_values.size(),
+ number_of_deltas);
+
+ // link_capacity_upper_kbps
+ auto link_capacity_upper_kbps_values =
+ DecodeDeltas(proto.link_capacity_upper_kbps_deltas(),
+ base_link_capacity_upper_kbps, number_of_deltas);
+ RTC_PARSE_CHECK_OR_RETURN_EQ(link_capacity_upper_kbps_values.size(),
+ number_of_deltas);
+
+ // Populate events from decoded deltas
+ for (size_t i = 0; i < number_of_deltas; ++i) {
+ LoggedRemoteEstimateEvent event;
+ RTC_PARSE_CHECK_OR_RETURN(timestamp_ms_values[i].has_value());
+ event.timestamp = Timestamp::Millis(*timestamp_ms_values[i]);
+ if (link_capacity_lower_kbps_values[i])
+ event.link_capacity_lower =
+ DataRate::KilobitsPerSec(*link_capacity_lower_kbps_values[i]);
+ if (link_capacity_upper_kbps_values[i])
+ event.link_capacity_upper =
+ DataRate::KilobitsPerSec(*link_capacity_upper_kbps_values[i]);
+ remote_estimate_events_.push_back(event);
+ }
+ return ParseStatus::Success();
+}
+
+ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreAudioPlayoutEvent(
+ const rtclog2::AudioPlayoutEvents& proto) {
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_timestamp_ms());
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_local_ssrc());
+
+ // Base event
+ audio_playout_events_[proto.local_ssrc()].emplace_back(
+ Timestamp::Millis(proto.timestamp_ms()), proto.local_ssrc());
+
+ const size_t number_of_deltas =
+ proto.has_number_of_deltas() ? proto.number_of_deltas() : 0u;
+ if (number_of_deltas == 0) {
+ return ParseStatus::Success();
+ }
+
+ // timestamp_ms
+ std::vector<absl::optional<uint64_t>> timestamp_ms_values =
+ DecodeDeltas(proto.timestamp_ms_deltas(),
+ ToUnsigned(proto.timestamp_ms()), number_of_deltas);
+ RTC_PARSE_CHECK_OR_RETURN_EQ(timestamp_ms_values.size(), number_of_deltas);
+
+ // local_ssrc
+ std::vector<absl::optional<uint64_t>> local_ssrc_values = DecodeDeltas(
+ proto.local_ssrc_deltas(), proto.local_ssrc(), number_of_deltas);
+ RTC_PARSE_CHECK_OR_RETURN_EQ(local_ssrc_values.size(), number_of_deltas);
+
+ // Populate events from decoded deltas
+ for (size_t i = 0; i < number_of_deltas; ++i) {
+ RTC_PARSE_CHECK_OR_RETURN(timestamp_ms_values[i].has_value());
+ RTC_PARSE_CHECK_OR_RETURN(local_ssrc_values[i].has_value());
+ RTC_PARSE_CHECK_OR_RETURN_LE(local_ssrc_values[i].value(),
+ std::numeric_limits<uint32_t>::max());
+
+ int64_t timestamp_ms;
+ RTC_PARSE_CHECK_OR_RETURN(
+ ToSigned(timestamp_ms_values[i].value(), &timestamp_ms));
+
+ const uint32_t local_ssrc =
+ static_cast<uint32_t>(local_ssrc_values[i].value());
+ audio_playout_events_[local_ssrc].emplace_back(
+ Timestamp::Millis(timestamp_ms), local_ssrc);
+ }
+ return ParseStatus::Success();
+}
+
+ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreNetEqSetMinimumDelay(
+ const rtclog2::NetEqSetMinimumDelay& proto) {
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_timestamp_ms());
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_remote_ssrc());
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_minimum_delay_ms());
+
+ // Base event
+ neteq_set_minimum_delay_events_[proto.remote_ssrc()].emplace_back(
+ Timestamp::Millis(proto.timestamp_ms()), proto.remote_ssrc(),
+ static_cast<int>(proto.minimum_delay_ms()));
+
+ const size_t number_of_deltas =
+ proto.has_number_of_deltas() ? proto.number_of_deltas() : 0u;
+ if (number_of_deltas == 0) {
+ return ParseStatus::Success();
+ }
+
+ // timestamp_ms
+ std::vector<absl::optional<uint64_t>> timestamp_ms_values =
+ DecodeDeltas(proto.timestamp_ms_deltas(),
+ ToUnsigned(proto.timestamp_ms()), number_of_deltas);
+ RTC_PARSE_CHECK_OR_RETURN_EQ(timestamp_ms_values.size(), number_of_deltas);
+
+ // remote_ssrc
+ std::vector<absl::optional<uint64_t>> remote_ssrc_values = DecodeDeltas(
+ proto.remote_ssrc_deltas(), proto.remote_ssrc(), number_of_deltas);
+ RTC_PARSE_CHECK_OR_RETURN_EQ(remote_ssrc_values.size(), number_of_deltas);
+
+ // minimum_delay_ms
+ std::vector<absl::optional<uint64_t>> minimum_delay_ms_values =
+ DecodeDeltas(proto.minimum_delay_ms_deltas(),
+ ToUnsigned(proto.minimum_delay_ms()), number_of_deltas);
+ RTC_PARSE_CHECK_OR_RETURN_EQ(minimum_delay_ms_values.size(),
+ number_of_deltas);
+
+ // Populate events from decoded deltas
+ for (size_t i = 0; i < number_of_deltas; ++i) {
+ RTC_PARSE_CHECK_OR_RETURN(timestamp_ms_values[i].has_value());
+ RTC_PARSE_CHECK_OR_RETURN(remote_ssrc_values[i].has_value());
+ RTC_PARSE_CHECK_OR_RETURN_LE(remote_ssrc_values[i].value(),
+ std::numeric_limits<uint32_t>::max());
+ RTC_PARSE_CHECK_OR_RETURN(minimum_delay_ms_values[i].has_value());
+
+ int64_t timestamp_ms;
+ RTC_PARSE_CHECK_OR_RETURN(
+ ToSigned(timestamp_ms_values[i].value(), &timestamp_ms));
+
+ const uint32_t remote_ssrc =
+ static_cast<uint32_t>(remote_ssrc_values[i].value());
+ int minimum_delay_ms;
+ RTC_PARSE_CHECK_OR_RETURN(
+ ToSigned(minimum_delay_ms_values[i].value(), &minimum_delay_ms));
+ neteq_set_minimum_delay_events_[remote_ssrc].emplace_back(
+ Timestamp::Millis(timestamp_ms), remote_ssrc, minimum_delay_ms);
+ }
+
+ return ParseStatus::Success();
+}
+
+ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreIncomingRtpPackets(
+ const rtclog2::IncomingRtpPackets& proto) {
+ return StoreRtpPackets(proto, &incoming_rtp_packets_map_);
+}
+
+ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreOutgoingRtpPackets(
+ const rtclog2::OutgoingRtpPackets& proto) {
+ return StoreRtpPackets(proto, &outgoing_rtp_packets_map_);
+}
+
+ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreIncomingRtcpPackets(
+ const rtclog2::IncomingRtcpPackets& proto) {
+ return StoreRtcpPackets(proto, &incoming_rtcp_packets_,
+ /*remove_duplicates=*/true);
+}
+
+ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreOutgoingRtcpPackets(
+ const rtclog2::OutgoingRtcpPackets& proto) {
+ return StoreRtcpPackets(proto, &outgoing_rtcp_packets_,
+ /*remove_duplicates=*/false);
+}
+
+ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreStartEvent(
+ const rtclog2::BeginLogEvent& proto) {
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_timestamp_ms());
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_version());
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_utc_time_ms());
+ RTC_PARSE_CHECK_OR_RETURN_EQ(proto.version(), 2);
+ LoggedStartEvent start_event(Timestamp::Millis(proto.timestamp_ms()),
+ Timestamp::Millis(proto.utc_time_ms()));
+
+ start_log_events_.push_back(start_event);
+ return ParseStatus::Success();
+}
+
+ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreStopEvent(
+ const rtclog2::EndLogEvent& proto) {
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_timestamp_ms());
+ LoggedStopEvent stop_event(Timestamp::Millis(proto.timestamp_ms()));
+
+ stop_log_events_.push_back(stop_event);
+ return ParseStatus::Success();
+}
+
+ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreBweLossBasedUpdate(
+ const rtclog2::LossBasedBweUpdates& proto) {
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_timestamp_ms());
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_bitrate_bps());
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_fraction_loss());
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_total_packets());
+
+ // Base event
+ bwe_loss_updates_.emplace_back(Timestamp::Millis(proto.timestamp_ms()),
+ proto.bitrate_bps(), proto.fraction_loss(),
+ proto.total_packets());
+
+ const size_t number_of_deltas =
+ proto.has_number_of_deltas() ? proto.number_of_deltas() : 0u;
+ if (number_of_deltas == 0) {
+ return ParseStatus::Success();
+ }
+
+ // timestamp_ms
+ std::vector<absl::optional<uint64_t>> timestamp_ms_values =
+ DecodeDeltas(proto.timestamp_ms_deltas(),
+ ToUnsigned(proto.timestamp_ms()), number_of_deltas);
+ RTC_PARSE_CHECK_OR_RETURN_EQ(timestamp_ms_values.size(), number_of_deltas);
+
+ // bitrate_bps
+ std::vector<absl::optional<uint64_t>> bitrate_bps_values = DecodeDeltas(
+ proto.bitrate_bps_deltas(), proto.bitrate_bps(), number_of_deltas);
+ RTC_PARSE_CHECK_OR_RETURN_EQ(bitrate_bps_values.size(), number_of_deltas);
+
+ // fraction_loss
+ std::vector<absl::optional<uint64_t>> fraction_loss_values = DecodeDeltas(
+ proto.fraction_loss_deltas(), proto.fraction_loss(), number_of_deltas);
+ RTC_PARSE_CHECK_OR_RETURN_EQ(fraction_loss_values.size(), number_of_deltas);
+
+ // total_packets
+ std::vector<absl::optional<uint64_t>> total_packets_values = DecodeDeltas(
+ proto.total_packets_deltas(), proto.total_packets(), number_of_deltas);
+ RTC_PARSE_CHECK_OR_RETURN_EQ(total_packets_values.size(), number_of_deltas);
+
+ // Populate events from decoded deltas
+ for (size_t i = 0; i < number_of_deltas; ++i) {
+ RTC_PARSE_CHECK_OR_RETURN(timestamp_ms_values[i].has_value());
+ int64_t timestamp_ms;
+ RTC_PARSE_CHECK_OR_RETURN(
+ ToSigned(timestamp_ms_values[i].value(), &timestamp_ms));
+
+ RTC_PARSE_CHECK_OR_RETURN(bitrate_bps_values[i].has_value());
+ RTC_PARSE_CHECK_OR_RETURN_LE(bitrate_bps_values[i].value(),
+ std::numeric_limits<uint32_t>::max());
+ const uint32_t bitrate_bps =
+ static_cast<uint32_t>(bitrate_bps_values[i].value());
+
+ RTC_PARSE_CHECK_OR_RETURN(fraction_loss_values[i].has_value());
+ RTC_PARSE_CHECK_OR_RETURN_LE(fraction_loss_values[i].value(),
+ std::numeric_limits<uint32_t>::max());
+ const uint32_t fraction_loss =
+ static_cast<uint32_t>(fraction_loss_values[i].value());
+
+ RTC_PARSE_CHECK_OR_RETURN(total_packets_values[i].has_value());
+ RTC_PARSE_CHECK_OR_RETURN_LE(total_packets_values[i].value(),
+ std::numeric_limits<uint32_t>::max());
+ const uint32_t total_packets =
+ static_cast<uint32_t>(total_packets_values[i].value());
+
+ bwe_loss_updates_.emplace_back(Timestamp::Millis(timestamp_ms), bitrate_bps,
+ fraction_loss, total_packets);
+ }
+ return ParseStatus::Success();
+}
+
+ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreBweDelayBasedUpdate(
+ const rtclog2::DelayBasedBweUpdates& proto) {
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_timestamp_ms());
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_bitrate_bps());
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_detector_state());
+
+ // Base event
+ const BandwidthUsage base_detector_state =
+ GetRuntimeDetectorState(proto.detector_state());
+ bwe_delay_updates_.emplace_back(Timestamp::Millis(proto.timestamp_ms()),
+ proto.bitrate_bps(), base_detector_state);
+
+ const size_t number_of_deltas =
+ proto.has_number_of_deltas() ? proto.number_of_deltas() : 0u;
+ if (number_of_deltas == 0) {
+ return ParseStatus::Success();
+ }
+
+ // timestamp_ms
+ std::vector<absl::optional<uint64_t>> timestamp_ms_values =
+ DecodeDeltas(proto.timestamp_ms_deltas(),
+ ToUnsigned(proto.timestamp_ms()), number_of_deltas);
+ RTC_PARSE_CHECK_OR_RETURN_EQ(timestamp_ms_values.size(), number_of_deltas);
+
+ // bitrate_bps
+ std::vector<absl::optional<uint64_t>> bitrate_bps_values = DecodeDeltas(
+ proto.bitrate_bps_deltas(), proto.bitrate_bps(), number_of_deltas);
+ RTC_PARSE_CHECK_OR_RETURN_EQ(bitrate_bps_values.size(), number_of_deltas);
+
+ // detector_state
+ std::vector<absl::optional<uint64_t>> detector_state_values = DecodeDeltas(
+ proto.detector_state_deltas(),
+ static_cast<uint64_t>(proto.detector_state()), number_of_deltas);
+ RTC_PARSE_CHECK_OR_RETURN_EQ(detector_state_values.size(), number_of_deltas);
+
+ // Populate events from decoded deltas
+ for (size_t i = 0; i < number_of_deltas; ++i) {
+ RTC_PARSE_CHECK_OR_RETURN(timestamp_ms_values[i].has_value());
+ int64_t timestamp_ms;
+ RTC_PARSE_CHECK_OR_RETURN(
+ ToSigned(timestamp_ms_values[i].value(), &timestamp_ms));
+
+ RTC_PARSE_CHECK_OR_RETURN(bitrate_bps_values[i].has_value());
+ RTC_PARSE_CHECK_OR_RETURN_LE(bitrate_bps_values[i].value(),
+ std::numeric_limits<uint32_t>::max());
+ const uint32_t bitrate_bps =
+ static_cast<uint32_t>(bitrate_bps_values[i].value());
+
+ RTC_PARSE_CHECK_OR_RETURN(detector_state_values[i].has_value());
+ const auto detector_state =
+ static_cast<rtclog2::DelayBasedBweUpdates::DetectorState>(
+ detector_state_values[i].value());
+
+ bwe_delay_updates_.emplace_back(Timestamp::Millis(timestamp_ms),
+ bitrate_bps,
+ GetRuntimeDetectorState(detector_state));
+ }
+ return ParseStatus::Success();
+}
+
+ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreBweProbeClusterCreated(
+ const rtclog2::BweProbeCluster& proto) {
+ LoggedBweProbeClusterCreatedEvent probe_cluster;
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_timestamp_ms());
+ probe_cluster.timestamp = Timestamp::Millis(proto.timestamp_ms());
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_id());
+ probe_cluster.id = proto.id();
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_bitrate_bps());
+ probe_cluster.bitrate_bps = proto.bitrate_bps();
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_min_packets());
+ probe_cluster.min_packets = proto.min_packets();
+ RTC_PARSE_CHECK_OR_RETURN(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?
+ return ParseStatus::Success();
+}
+
+ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreBweProbeSuccessEvent(
+ const rtclog2::BweProbeResultSuccess& proto) {
+ LoggedBweProbeSuccessEvent probe_result;
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_timestamp_ms());
+ probe_result.timestamp = Timestamp::Millis(proto.timestamp_ms());
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_id());
+ probe_result.id = proto.id();
+ RTC_PARSE_CHECK_OR_RETURN(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?
+ return ParseStatus::Success();
+}
+
+ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreBweProbeFailureEvent(
+ const rtclog2::BweProbeResultFailure& proto) {
+ LoggedBweProbeFailureEvent probe_result;
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_timestamp_ms());
+ probe_result.timestamp = Timestamp::Millis(proto.timestamp_ms());
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_id());
+ probe_result.id = proto.id();
+ RTC_PARSE_CHECK_OR_RETURN(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?
+ return ParseStatus::Success();
+}
+
+ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreFrameDecodedEvents(
+ const rtclog2::FrameDecodedEvents& proto) {
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_timestamp_ms());
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_ssrc());
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_render_time_ms());
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_width());
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_height());
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_codec());
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_qp());
+
+ LoggedFrameDecoded base_frame;
+ base_frame.timestamp = Timestamp::Millis(proto.timestamp_ms());
+ base_frame.ssrc = proto.ssrc();
+ base_frame.render_time_ms = proto.render_time_ms();
+ base_frame.width = proto.width();
+ base_frame.height = proto.height();
+ base_frame.codec = GetRuntimeCodecType(proto.codec());
+ RTC_PARSE_CHECK_OR_RETURN_GE(proto.qp(), 0);
+ RTC_PARSE_CHECK_OR_RETURN_LE(proto.qp(), 255);
+ base_frame.qp = static_cast<uint8_t>(proto.qp());
+
+ decoded_frames_[base_frame.ssrc].push_back(base_frame);
+
+ const size_t number_of_deltas =
+ proto.has_number_of_deltas() ? proto.number_of_deltas() : 0u;
+ if (number_of_deltas == 0) {
+ return ParseStatus::Success();
+ }
+
+ // timestamp_ms
+ std::vector<absl::optional<uint64_t>> timestamp_ms_values =
+ DecodeDeltas(proto.timestamp_ms_deltas(),
+ ToUnsigned(proto.timestamp_ms()), number_of_deltas);
+ RTC_PARSE_CHECK_OR_RETURN_EQ(timestamp_ms_values.size(), number_of_deltas);
+
+ // SSRC
+ std::vector<absl::optional<uint64_t>> ssrc_values =
+ DecodeDeltas(proto.ssrc_deltas(), proto.ssrc(), number_of_deltas);
+ RTC_PARSE_CHECK_OR_RETURN_EQ(ssrc_values.size(), number_of_deltas);
+
+ // render_time_ms
+ std::vector<absl::optional<uint64_t>> render_time_ms_values =
+ DecodeDeltas(proto.render_time_ms_deltas(),
+ ToUnsigned(proto.render_time_ms()), number_of_deltas);
+ RTC_PARSE_CHECK_OR_RETURN_EQ(render_time_ms_values.size(), number_of_deltas);
+
+ // width
+ std::vector<absl::optional<uint64_t>> width_values = DecodeDeltas(
+ proto.width_deltas(), ToUnsigned(proto.width()), number_of_deltas);
+ RTC_PARSE_CHECK_OR_RETURN_EQ(width_values.size(), number_of_deltas);
+
+ // height
+ std::vector<absl::optional<uint64_t>> height_values = DecodeDeltas(
+ proto.height_deltas(), ToUnsigned(proto.height()), number_of_deltas);
+ RTC_PARSE_CHECK_OR_RETURN_EQ(height_values.size(), number_of_deltas);
+
+ // codec
+ std::vector<absl::optional<uint64_t>> codec_values =
+ DecodeDeltas(proto.codec_deltas(), static_cast<uint64_t>(proto.codec()),
+ number_of_deltas);
+ RTC_PARSE_CHECK_OR_RETURN_EQ(codec_values.size(), number_of_deltas);
+
+ // qp
+ std::vector<absl::optional<uint64_t>> qp_values =
+ DecodeDeltas(proto.qp_deltas(), proto.qp(), number_of_deltas);
+ RTC_PARSE_CHECK_OR_RETURN_EQ(qp_values.size(), number_of_deltas);
+
+ // Populate events from decoded deltas
+ for (size_t i = 0; i < number_of_deltas; ++i) {
+ LoggedFrameDecoded frame;
+ int64_t timestamp_ms;
+ RTC_PARSE_CHECK_OR_RETURN(timestamp_ms_values[i].has_value());
+ RTC_PARSE_CHECK_OR_RETURN(
+ ToSigned(timestamp_ms_values[i].value(), &timestamp_ms));
+ frame.timestamp = Timestamp::Millis(timestamp_ms);
+
+ RTC_PARSE_CHECK_OR_RETURN(ssrc_values[i].has_value());
+ RTC_PARSE_CHECK_OR_RETURN_LE(ssrc_values[i].value(),
+ std::numeric_limits<uint32_t>::max());
+ frame.ssrc = static_cast<uint32_t>(ssrc_values[i].value());
+
+ RTC_PARSE_CHECK_OR_RETURN(render_time_ms_values[i].has_value());
+ RTC_PARSE_CHECK_OR_RETURN(
+ ToSigned(render_time_ms_values[i].value(), &frame.render_time_ms));
+
+ RTC_PARSE_CHECK_OR_RETURN(width_values[i].has_value());
+ RTC_PARSE_CHECK_OR_RETURN(ToSigned(width_values[i].value(), &frame.width));
+
+ RTC_PARSE_CHECK_OR_RETURN(height_values[i].has_value());
+ RTC_PARSE_CHECK_OR_RETURN(
+ ToSigned(height_values[i].value(), &frame.height));
+
+ RTC_PARSE_CHECK_OR_RETURN(codec_values[i].has_value());
+ frame.codec =
+ GetRuntimeCodecType(static_cast<rtclog2::FrameDecodedEvents::Codec>(
+ codec_values[i].value()));
+
+ RTC_PARSE_CHECK_OR_RETURN(qp_values[i].has_value());
+ RTC_PARSE_CHECK_OR_RETURN_LE(qp_values[i].value(),
+ std::numeric_limits<uint8_t>::max());
+ frame.qp = static_cast<uint8_t>(qp_values[i].value());
+
+ decoded_frames_[frame.ssrc].push_back(frame);
+ }
+ return ParseStatus::Success();
+}
+
+ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreGenericAckReceivedEvent(
+ const rtclog2::GenericAckReceived& proto) {
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_timestamp_ms());
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_packet_number());
+ RTC_PARSE_CHECK_OR_RETURN(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(
+ {Timestamp::Millis(proto.timestamp_ms()), 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 ParseStatus::Success();
+ }
+
+ // timestamp_ms
+ std::vector<absl::optional<uint64_t>> timestamp_ms_values =
+ DecodeDeltas(proto.timestamp_ms_deltas(),
+ ToUnsigned(proto.timestamp_ms()), number_of_deltas);
+ RTC_PARSE_CHECK_OR_RETURN_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_PARSE_CHECK_OR_RETURN_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_PARSE_CHECK_OR_RETURN_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_PARSE_CHECK_OR_RETURN_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_PARSE_CHECK_OR_RETURN(
+ ToSigned(timestamp_ms_values[i].value(), &timestamp_ms));
+ int64_t packet_number;
+ RTC_PARSE_CHECK_OR_RETURN(
+ ToSigned(packet_number_values[i].value(), &packet_number));
+ int64_t acked_packet_number;
+ RTC_PARSE_CHECK_OR_RETURN(
+ 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_PARSE_CHECK_OR_RETURN(
+ ToSigned(receive_acked_packet_time_ms_values[i].value(), &value));
+ receive_acked_packet_time_ms = value;
+ }
+ generic_acks_received_.push_back({Timestamp::Millis(timestamp_ms),
+ packet_number, acked_packet_number,
+ receive_acked_packet_time_ms});
+ }
+ return ParseStatus::Success();
+}
+
+ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreGenericPacketSentEvent(
+ const rtclog2::GenericPacketSent& proto) {
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_timestamp_ms());
+
+ // Base event
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_packet_number());
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_overhead_length());
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_payload_length());
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_padding_length());
+
+ generic_packets_sent_.push_back(
+ {Timestamp::Millis(proto.timestamp_ms()), 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 ParseStatus::Success();
+ }
+
+ // timestamp_ms
+ std::vector<absl::optional<uint64_t>> timestamp_ms_values =
+ DecodeDeltas(proto.timestamp_ms_deltas(),
+ ToUnsigned(proto.timestamp_ms()), number_of_deltas);
+ RTC_PARSE_CHECK_OR_RETURN_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_PARSE_CHECK_OR_RETURN_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_PARSE_CHECK_OR_RETURN_EQ(overhead_length_values.size(), number_of_deltas);
+
+ std::vector<absl::optional<uint64_t>> payload_length_values = DecodeDeltas(
+ proto.payload_length_deltas(), proto.payload_length(), number_of_deltas);
+ RTC_PARSE_CHECK_OR_RETURN_EQ(payload_length_values.size(), number_of_deltas);
+
+ std::vector<absl::optional<uint64_t>> padding_length_values = DecodeDeltas(
+ proto.padding_length_deltas(), proto.padding_length(), number_of_deltas);
+ RTC_PARSE_CHECK_OR_RETURN_EQ(padding_length_values.size(), number_of_deltas);
+
+ for (size_t i = 0; i < number_of_deltas; i++) {
+ int64_t timestamp_ms;
+ RTC_PARSE_CHECK_OR_RETURN(
+ ToSigned(timestamp_ms_values[i].value(), &timestamp_ms));
+ int64_t packet_number;
+ RTC_PARSE_CHECK_OR_RETURN(
+ ToSigned(packet_number_values[i].value(), &packet_number));
+ RTC_PARSE_CHECK_OR_RETURN(overhead_length_values[i].has_value());
+ RTC_PARSE_CHECK_OR_RETURN(payload_length_values[i].has_value());
+ RTC_PARSE_CHECK_OR_RETURN(padding_length_values[i].has_value());
+ generic_packets_sent_.push_back(
+ {Timestamp::Millis(timestamp_ms), 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())});
+ }
+ return ParseStatus::Success();
+}
+
+ParsedRtcEventLog::ParseStatus
+ParsedRtcEventLog::StoreGenericPacketReceivedEvent(
+ const rtclog2::GenericPacketReceived& proto) {
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_timestamp_ms());
+
+ // Base event
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_packet_number());
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_packet_length());
+
+ generic_packets_received_.push_back({Timestamp::Millis(proto.timestamp_ms()),
+ 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 ParseStatus::Success();
+ }
+
+ // timestamp_ms
+ std::vector<absl::optional<uint64_t>> timestamp_ms_values =
+ DecodeDeltas(proto.timestamp_ms_deltas(),
+ ToUnsigned(proto.timestamp_ms()), number_of_deltas);
+ RTC_PARSE_CHECK_OR_RETURN_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_PARSE_CHECK_OR_RETURN_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_PARSE_CHECK_OR_RETURN_EQ(packet_length_values.size(), number_of_deltas);
+
+ for (size_t i = 0; i < number_of_deltas; i++) {
+ int64_t timestamp_ms;
+ RTC_PARSE_CHECK_OR_RETURN(
+ ToSigned(timestamp_ms_values[i].value(), &timestamp_ms));
+ int64_t packet_number;
+ RTC_PARSE_CHECK_OR_RETURN(
+ ToSigned(packet_number_values[i].value(), &packet_number));
+ RTC_PARSE_CHECK_OR_RETURN_LE(packet_length_values[i].value(),
+ std::numeric_limits<int32_t>::max());
+ int32_t packet_length =
+ static_cast<int32_t>(packet_length_values[i].value());
+ generic_packets_received_.push_back(
+ {Timestamp::Millis(timestamp_ms), packet_number, packet_length});
+ }
+ return ParseStatus::Success();
+}
+
+ParsedRtcEventLog::ParseStatus
+ParsedRtcEventLog::StoreAudioNetworkAdaptationEvent(
+ const rtclog2::AudioNetworkAdaptations& proto) {
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_timestamp_ms());
+
+ // Base event
+ {
+ AudioEncoderRuntimeConfig runtime_config;
+ if (proto.has_bitrate_bps()) {
+ runtime_config.bitrate_bps = proto.bitrate_bps();
+ }
+ if (proto.has_frame_length_ms()) {
+ runtime_config.frame_length_ms = proto.frame_length_ms();
+ }
+ if (proto.has_uplink_packet_loss_fraction()) {
+ float uplink_packet_loss_fraction;
+ RTC_PARSE_CHECK_OR_RETURN(ParsePacketLossFractionFromProtoFormat(
+ proto.uplink_packet_loss_fraction(), &uplink_packet_loss_fraction));
+ runtime_config.uplink_packet_loss_fraction = uplink_packet_loss_fraction;
+ }
+ if (proto.has_enable_fec()) {
+ runtime_config.enable_fec = proto.enable_fec();
+ }
+ if (proto.has_enable_dtx()) {
+ runtime_config.enable_dtx = proto.enable_dtx();
+ }
+ if (proto.has_num_channels()) {
+ // Note: Encoding N as N-1 only done for `num_channels_deltas`.
+ runtime_config.num_channels = proto.num_channels();
+ }
+ audio_network_adaptation_events_.emplace_back(
+ Timestamp::Millis(proto.timestamp_ms()), runtime_config);
+ }
+
+ const size_t number_of_deltas =
+ proto.has_number_of_deltas() ? proto.number_of_deltas() : 0u;
+ if (number_of_deltas == 0) {
+ return ParseStatus::Success();
+ }
+
+ // timestamp_ms
+ std::vector<absl::optional<uint64_t>> timestamp_ms_values =
+ DecodeDeltas(proto.timestamp_ms_deltas(),
+ ToUnsigned(proto.timestamp_ms()), number_of_deltas);
+ RTC_PARSE_CHECK_OR_RETURN_EQ(timestamp_ms_values.size(), number_of_deltas);
+
+ // bitrate_bps
+ const absl::optional<uint64_t> unsigned_base_bitrate_bps =
+ proto.has_bitrate_bps()
+ ? absl::optional<uint64_t>(ToUnsigned(proto.bitrate_bps()))
+ : absl::optional<uint64_t>();
+ std::vector<absl::optional<uint64_t>> bitrate_bps_values = DecodeDeltas(
+ proto.bitrate_bps_deltas(), unsigned_base_bitrate_bps, number_of_deltas);
+ RTC_PARSE_CHECK_OR_RETURN_EQ(bitrate_bps_values.size(), number_of_deltas);
+
+ // frame_length_ms
+ const absl::optional<uint64_t> unsigned_base_frame_length_ms =
+ proto.has_frame_length_ms()
+ ? absl::optional<uint64_t>(ToUnsigned(proto.frame_length_ms()))
+ : absl::optional<uint64_t>();
+ std::vector<absl::optional<uint64_t>> frame_length_ms_values =
+ DecodeDeltas(proto.frame_length_ms_deltas(),
+ unsigned_base_frame_length_ms, number_of_deltas);
+ RTC_PARSE_CHECK_OR_RETURN_EQ(frame_length_ms_values.size(), number_of_deltas);
+
+ // uplink_packet_loss_fraction
+ const absl::optional<uint64_t> uplink_packet_loss_fraction =
+ proto.has_uplink_packet_loss_fraction()
+ ? absl::optional<uint64_t>(proto.uplink_packet_loss_fraction())
+ : absl::optional<uint64_t>();
+ std::vector<absl::optional<uint64_t>> uplink_packet_loss_fraction_values =
+ DecodeDeltas(proto.uplink_packet_loss_fraction_deltas(),
+ uplink_packet_loss_fraction, number_of_deltas);
+ RTC_PARSE_CHECK_OR_RETURN_EQ(uplink_packet_loss_fraction_values.size(),
+ number_of_deltas);
+
+ // enable_fec
+ const absl::optional<uint64_t> enable_fec =
+ proto.has_enable_fec() ? absl::optional<uint64_t>(proto.enable_fec())
+ : absl::optional<uint64_t>();
+ std::vector<absl::optional<uint64_t>> enable_fec_values =
+ DecodeDeltas(proto.enable_fec_deltas(), enable_fec, number_of_deltas);
+ RTC_PARSE_CHECK_OR_RETURN_EQ(enable_fec_values.size(), number_of_deltas);
+
+ // enable_dtx
+ const absl::optional<uint64_t> enable_dtx =
+ proto.has_enable_dtx() ? absl::optional<uint64_t>(proto.enable_dtx())
+ : absl::optional<uint64_t>();
+ std::vector<absl::optional<uint64_t>> enable_dtx_values =
+ DecodeDeltas(proto.enable_dtx_deltas(), enable_dtx, number_of_deltas);
+ RTC_PARSE_CHECK_OR_RETURN_EQ(enable_dtx_values.size(), number_of_deltas);
+
+ // num_channels
+ // Note: For delta encoding, all num_channel values, including the base,
+ // were shifted down by one, but in the base event, they were not.
+ // We likewise shift the base event down by one, to get the same base as
+ // encoding had, but then shift all of the values (except the base) back up
+ // to their original value.
+ absl::optional<uint64_t> shifted_base_num_channels;
+ if (proto.has_num_channels()) {
+ shifted_base_num_channels =
+ absl::optional<uint64_t>(proto.num_channels() - 1);
+ }
+ std::vector<absl::optional<uint64_t>> num_channels_values = DecodeDeltas(
+ proto.num_channels_deltas(), shifted_base_num_channels, number_of_deltas);
+ for (size_t i = 0; i < num_channels_values.size(); ++i) {
+ if (num_channels_values[i].has_value()) {
+ num_channels_values[i] = num_channels_values[i].value() + 1;
+ }
+ }
+ RTC_PARSE_CHECK_OR_RETURN_EQ(num_channels_values.size(), number_of_deltas);
+
+ // Populate events from decoded deltas
+ for (size_t i = 0; i < number_of_deltas; ++i) {
+ RTC_PARSE_CHECK_OR_RETURN(timestamp_ms_values[i].has_value());
+ int64_t timestamp_ms;
+ RTC_PARSE_CHECK_OR_RETURN(
+ ToSigned(timestamp_ms_values[i].value(), &timestamp_ms));
+
+ AudioEncoderRuntimeConfig runtime_config;
+ if (bitrate_bps_values[i].has_value()) {
+ int signed_bitrate_bps;
+ RTC_PARSE_CHECK_OR_RETURN(
+ ToSigned(bitrate_bps_values[i].value(), &signed_bitrate_bps));
+ runtime_config.bitrate_bps = signed_bitrate_bps;
+ }
+ if (frame_length_ms_values[i].has_value()) {
+ int signed_frame_length_ms;
+ RTC_PARSE_CHECK_OR_RETURN(
+ ToSigned(frame_length_ms_values[i].value(), &signed_frame_length_ms));
+ runtime_config.frame_length_ms = signed_frame_length_ms;
+ }
+ if (uplink_packet_loss_fraction_values[i].has_value()) {
+ float uplink_packet_loss_fraction2;
+ RTC_PARSE_CHECK_OR_RETURN(ParsePacketLossFractionFromProtoFormat(
+ rtc::checked_cast<uint32_t>(
+ uplink_packet_loss_fraction_values[i].value()),
+ &uplink_packet_loss_fraction2));
+ runtime_config.uplink_packet_loss_fraction = uplink_packet_loss_fraction2;
+ }
+ if (enable_fec_values[i].has_value()) {
+ runtime_config.enable_fec =
+ rtc::checked_cast<bool>(enable_fec_values[i].value());
+ }
+ if (enable_dtx_values[i].has_value()) {
+ runtime_config.enable_dtx =
+ rtc::checked_cast<bool>(enable_dtx_values[i].value());
+ }
+ if (num_channels_values[i].has_value()) {
+ runtime_config.num_channels =
+ rtc::checked_cast<size_t>(num_channels_values[i].value());
+ }
+ audio_network_adaptation_events_.emplace_back(
+ Timestamp::Millis(timestamp_ms), runtime_config);
+ }
+ return ParseStatus::Success();
+}
+
+ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreDtlsTransportState(
+ const rtclog2::DtlsTransportStateEvent& proto) {
+ LoggedDtlsTransportState dtls_state;
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_timestamp_ms());
+ dtls_state.timestamp = Timestamp::Millis(proto.timestamp_ms());
+
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_dtls_transport_state());
+ dtls_state.dtls_transport_state =
+ GetRuntimeDtlsTransportState(proto.dtls_transport_state());
+
+ dtls_transport_states_.push_back(dtls_state);
+ return ParseStatus::Success();
+}
+
+ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreDtlsWritableState(
+ const rtclog2::DtlsWritableState& proto) {
+ LoggedDtlsWritableState dtls_writable_state;
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_timestamp_ms());
+ dtls_writable_state.timestamp = Timestamp::Millis(proto.timestamp_ms());
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_writable());
+ dtls_writable_state.writable = proto.writable();
+
+ dtls_writable_states_.push_back(dtls_writable_state);
+ return ParseStatus::Success();
+}
+
+ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreIceCandidatePairConfig(
+ const rtclog2::IceCandidatePairConfig& proto) {
+ LoggedIceCandidatePairConfig ice_config;
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_timestamp_ms());
+ ice_config.timestamp = Timestamp::Millis(proto.timestamp_ms());
+
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_config_type());
+ ice_config.type = GetRuntimeIceCandidatePairConfigType(proto.config_type());
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_candidate_pair_id());
+ ice_config.candidate_pair_id = proto.candidate_pair_id();
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_local_candidate_type());
+ ice_config.local_candidate_type =
+ GetRuntimeIceCandidateType(proto.local_candidate_type());
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_local_relay_protocol());
+ ice_config.local_relay_protocol =
+ GetRuntimeIceCandidatePairProtocol(proto.local_relay_protocol());
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_local_network_type());
+ ice_config.local_network_type =
+ GetRuntimeIceCandidateNetworkType(proto.local_network_type());
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_local_address_family());
+ ice_config.local_address_family =
+ GetRuntimeIceCandidatePairAddressFamily(proto.local_address_family());
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_remote_candidate_type());
+ ice_config.remote_candidate_type =
+ GetRuntimeIceCandidateType(proto.remote_candidate_type());
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_remote_address_family());
+ ice_config.remote_address_family =
+ GetRuntimeIceCandidatePairAddressFamily(proto.remote_address_family());
+ RTC_PARSE_CHECK_OR_RETURN(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?
+ return ParseStatus::Success();
+}
+
+ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreIceCandidateEvent(
+ const rtclog2::IceCandidatePairEvent& proto) {
+ LoggedIceCandidatePairEvent ice_event;
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_timestamp_ms());
+ ice_event.timestamp = Timestamp::Millis(proto.timestamp_ms());
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_event_type());
+ ice_event.type = GetRuntimeIceCandidatePairEventType(proto.event_type());
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_candidate_pair_id());
+ ice_event.candidate_pair_id = proto.candidate_pair_id();
+ // TODO(zstein): Make the transaction_id field required once all old versions
+ // of the log (which don't have the field) are obsolete.
+ ice_event.transaction_id =
+ proto.has_transaction_id() ? proto.transaction_id() : 0;
+
+ ice_candidate_pair_events_.push_back(ice_event);
+
+ // TODO(terelius): Should we delta encode this event type?
+ return ParseStatus::Success();
+}
+
+ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreVideoRecvConfig(
+ const rtclog2::VideoRecvStreamConfig& proto) {
+ LoggedVideoRecvConfig stream;
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_timestamp_ms());
+ stream.timestamp = Timestamp::Millis(proto.timestamp_ms());
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_remote_ssrc());
+ stream.config.remote_ssrc = proto.remote_ssrc();
+ RTC_PARSE_CHECK_OR_RETURN(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_header_extensions()) {
+ stream.config.rtp_extensions =
+ GetRuntimeRtpHeaderExtensionConfig(proto.header_extensions());
+ }
+ video_recv_configs_.push_back(stream);
+ return ParseStatus::Success();
+}
+
+ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreVideoSendConfig(
+ const rtclog2::VideoSendStreamConfig& proto) {
+ LoggedVideoSendConfig stream;
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_timestamp_ms());
+ stream.timestamp = Timestamp::Millis(proto.timestamp_ms());
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_ssrc());
+ stream.config.local_ssrc = proto.ssrc();
+ if (proto.has_rtx_ssrc()) {
+ stream.config.rtx_ssrc = proto.rtx_ssrc();
+ }
+ if (proto.has_header_extensions()) {
+ stream.config.rtp_extensions =
+ GetRuntimeRtpHeaderExtensionConfig(proto.header_extensions());
+ }
+ video_send_configs_.push_back(stream);
+ return ParseStatus::Success();
+}
+
+ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreAudioRecvConfig(
+ const rtclog2::AudioRecvStreamConfig& proto) {
+ LoggedAudioRecvConfig stream;
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_timestamp_ms());
+ stream.timestamp = Timestamp::Millis(proto.timestamp_ms());
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_remote_ssrc());
+ stream.config.remote_ssrc = proto.remote_ssrc();
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_local_ssrc());
+ stream.config.local_ssrc = proto.local_ssrc();
+ if (proto.has_header_extensions()) {
+ stream.config.rtp_extensions =
+ GetRuntimeRtpHeaderExtensionConfig(proto.header_extensions());
+ }
+ audio_recv_configs_.push_back(stream);
+ return ParseStatus::Success();
+}
+
+ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreAudioSendConfig(
+ const rtclog2::AudioSendStreamConfig& proto) {
+ LoggedAudioSendConfig stream;
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_timestamp_ms());
+ stream.timestamp = Timestamp::Millis(proto.timestamp_ms());
+ RTC_PARSE_CHECK_OR_RETURN(proto.has_ssrc());
+ stream.config.local_ssrc = proto.ssrc();
+ if (proto.has_header_extensions()) {
+ stream.config.rtp_extensions =
+ GetRuntimeRtpHeaderExtensionConfig(proto.header_extensions());
+ }
+ audio_send_configs_.push_back(stream);
+ return ParseStatus::Success();
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/logging/rtc_event_log/rtc_event_log_parser.h b/third_party/libwebrtc/logging/rtc_event_log/rtc_event_log_parser.h
new file mode 100644
index 0000000000..9ad96274d3
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/rtc_event_log_parser.h
@@ -0,0 +1,941 @@
+/*
+ * Copyright 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_RTC_EVENT_LOG_PARSER_H_
+#define LOGGING_RTC_EVENT_LOG_RTC_EVENT_LOG_PARSER_H_
+
+#include <iterator>
+#include <limits>
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "absl/base/attributes.h"
+#include "absl/strings/string_view.h"
+#include "api/rtc_event_log/rtc_event_log.h"
+#include "call/video_receive_stream.h"
+#include "call/video_send_stream.h"
+#include "logging/rtc_event_log/events/logged_rtp_rtcp.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"
+#include "logging/rtc_event_log/events/rtc_event_audio_receive_stream_config.h"
+#include "logging/rtc_event_log/events/rtc_event_audio_send_stream_config.h"
+#include "logging/rtc_event_log/events/rtc_event_begin_log.h"
+#include "logging/rtc_event_log/events/rtc_event_bwe_update_delay_based.h"
+#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_end_log.h"
+#include "logging/rtc_event_log/events/rtc_event_frame_decoded.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_neteq_set_minimum_delay.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"
+#include "logging/rtc_event_log/events/rtc_event_remote_estimate.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"
+#include "logging/rtc_event_log/events/rtc_event_rtp_packet_outgoing.h"
+#include "logging/rtc_event_log/events/rtc_event_video_receive_stream_config.h"
+#include "logging/rtc_event_log/events/rtc_event_video_send_stream_config.h"
+#include "modules/rtp_rtcp/include/rtp_header_extension_map.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h"
+#include "rtc_base/ignore_wundef.h"
+
+// Files generated at build-time by the protobuf compiler.
+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()
+
+namespace webrtc {
+
+enum PacketDirection { kIncomingPacket = 0, kOutgoingPacket };
+
+enum class LoggedMediaType : uint8_t { kUnknown, kAudio, kVideo };
+
+struct LoggedPacketInfo {
+ LoggedPacketInfo(const LoggedRtpPacket& rtp,
+ LoggedMediaType media_type,
+ bool rtx,
+ Timestamp capture_time);
+ LoggedPacketInfo(const LoggedPacketInfo&);
+ ~LoggedPacketInfo();
+ int64_t log_time_ms() const { return log_packet_time.ms(); }
+ int64_t log_time_us() const { return log_packet_time.us(); }
+ uint32_t ssrc;
+ uint16_t stream_seq_no;
+ uint16_t size;
+ uint16_t payload_size;
+ uint16_t padding_size;
+ uint16_t overhead = 0;
+ uint8_t payload_type;
+ LoggedMediaType media_type = LoggedMediaType::kUnknown;
+ bool rtx = false;
+ bool marker_bit = false;
+ bool has_transport_seq_no = false;
+ bool last_in_feedback = false;
+ uint16_t transport_seq_no = 0;
+ // The RTP header timestamp unwrapped and converted from tick count to seconds
+ // based timestamp.
+ Timestamp capture_time;
+ // The time the packet was logged. This is the receive time for incoming
+ // packets and send time for outgoing.
+ Timestamp log_packet_time;
+ // Send time as reported by abs-send-time extension, For outgoing packets this
+ // corresponds to log_packet_time, but might be measured using another clock.
+ Timestamp reported_send_time;
+ // The receive time that was reported in feedback. For incoming packets this
+ // corresponds to log_packet_time, but might be measured using another clock.
+ // PlusInfinity indicates that the packet was lost.
+ Timestamp reported_recv_time = Timestamp::MinusInfinity();
+ // The time feedback message was logged. This is the feedback send time for
+ // incoming packets and feedback receive time for outgoing.
+ // PlusInfinity indicates that feedback was expected but not received.
+ Timestamp log_feedback_time = Timestamp::MinusInfinity();
+ // The delay betweeen receiving an RTP packet and sending feedback for
+ // incoming packets. For outgoing packets we don't know the feedback send
+ // time, and this is instead calculated as the difference in reported receive
+ // time between this packet and the last packet in the same feedback message.
+ TimeDelta feedback_hold_duration = TimeDelta::MinusInfinity();
+};
+
+struct InferredRouteChangeEvent {
+ int64_t log_time_ms() const { return log_time.ms(); }
+ int64_t log_time_us() const { return log_time.us(); }
+ uint32_t route_id;
+ Timestamp log_time = Timestamp::MinusInfinity();
+ uint16_t send_overhead;
+ uint16_t return_overhead;
+};
+
+enum class LoggedIceEventType {
+ kAdded,
+ kUpdated,
+ kDestroyed,
+ kSelected,
+ kCheckSent,
+ kCheckReceived,
+ kCheckResponseSent,
+ kCheckResponseReceived,
+};
+
+struct LoggedIceEvent {
+ uint32_t candidate_pair_id;
+ Timestamp log_time;
+ LoggedIceEventType event_type;
+};
+
+// This class is used to process lists of LoggedRtpPacketIncoming
+// and LoggedRtpPacketOutgoing without duplicating the code.
+// TODO(terelius): Remove this class. Instead use e.g. a vector of pointers
+// to LoggedRtpPacket or templatize the surrounding code.
+template <typename T>
+class DereferencingVector {
+ public:
+ template <bool IsConst>
+ class DereferencingIterator {
+ public:
+ // Standard iterator traits.
+ using difference_type = std::ptrdiff_t;
+ using value_type = T;
+ using pointer = typename std::conditional_t<IsConst, const T*, T*>;
+ using reference = typename std::conditional_t<IsConst, const T&, T&>;
+ using iterator_category = std::bidirectional_iterator_tag;
+
+ using representation =
+ typename std::conditional_t<IsConst, const T* const*, T**>;
+
+ explicit DereferencingIterator(representation ptr) : ptr_(ptr) {}
+
+ DereferencingIterator(const DereferencingIterator& other)
+ : ptr_(other.ptr_) {}
+ DereferencingIterator(const DereferencingIterator&& other)
+ : ptr_(other.ptr_) {}
+ ~DereferencingIterator() = default;
+
+ DereferencingIterator& operator=(const DereferencingIterator& other) {
+ ptr_ = other.ptr_;
+ return *this;
+ }
+ DereferencingIterator& operator=(const DereferencingIterator&& other) {
+ ptr_ = other.ptr_;
+ return *this;
+ }
+
+ bool operator==(const DereferencingIterator& other) const {
+ return ptr_ == other.ptr_;
+ }
+ bool operator!=(const DereferencingIterator& other) const {
+ return ptr_ != other.ptr_;
+ }
+
+ DereferencingIterator& operator++() {
+ ++ptr_;
+ return *this;
+ }
+ DereferencingIterator& operator--() {
+ --ptr_;
+ return *this;
+ }
+ DereferencingIterator operator++(int) {
+ DereferencingIterator iter_copy(ptr_);
+ ++ptr_;
+ return iter_copy;
+ }
+ DereferencingIterator operator--(int) {
+ DereferencingIterator iter_copy(ptr_);
+ --ptr_;
+ return iter_copy;
+ }
+
+ template <bool _IsConst = IsConst>
+ std::enable_if_t<!_IsConst, reference> operator*() {
+ return **ptr_;
+ }
+
+ template <bool _IsConst = IsConst>
+ std::enable_if_t<_IsConst, reference> operator*() const {
+ return **ptr_;
+ }
+
+ template <bool _IsConst = IsConst>
+ std::enable_if_t<!_IsConst, pointer> operator->() {
+ return *ptr_;
+ }
+
+ template <bool _IsConst = IsConst>
+ std::enable_if_t<_IsConst, pointer> operator->() const {
+ return *ptr_;
+ }
+
+ private:
+ representation ptr_;
+ };
+
+ using value_type = T;
+ using reference = value_type&;
+ using const_reference = const value_type&;
+
+ using iterator = DereferencingIterator<false>;
+ using const_iterator = DereferencingIterator<true>;
+ using reverse_iterator = std::reverse_iterator<iterator>;
+ using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+
+ iterator begin() { return iterator(elems_.data()); }
+ iterator end() { return iterator(elems_.data() + elems_.size()); }
+
+ const_iterator begin() const { return const_iterator(elems_.data()); }
+ const_iterator end() const {
+ return const_iterator(elems_.data() + elems_.size());
+ }
+
+ reverse_iterator rbegin() { return reverse_iterator(end()); }
+ reverse_iterator rend() { return reverse_iterator(begin()); }
+
+ const_reverse_iterator rbegin() const {
+ return const_reverse_iterator(end());
+ }
+ const_reverse_iterator rend() const {
+ return const_reverse_iterator(begin());
+ }
+
+ size_t size() const { return elems_.size(); }
+
+ bool empty() const { return elems_.empty(); }
+
+ T& operator[](size_t i) {
+ RTC_DCHECK_LT(i, elems_.size());
+ return *elems_[i];
+ }
+
+ const T& operator[](size_t i) const {
+ RTC_DCHECK_LT(i, elems_.size());
+ return *elems_[i];
+ }
+
+ void push_back(T* elem) {
+ RTC_DCHECK(elem != nullptr);
+ elems_.push_back(elem);
+ }
+
+ private:
+ std::vector<T*> elems_;
+};
+
+// Conversion functions for version 2 of the wire format.
+BandwidthUsage GetRuntimeDetectorState(
+ rtclog2::DelayBasedBweUpdates::DetectorState detector_state);
+
+ProbeFailureReason GetRuntimeProbeFailureReason(
+ rtclog2::BweProbeResultFailure::FailureReason failure);
+
+DtlsTransportState GetRuntimeDtlsTransportState(
+ rtclog2::DtlsTransportStateEvent::DtlsTransportState state);
+
+IceCandidatePairConfigType GetRuntimeIceCandidatePairConfigType(
+ rtclog2::IceCandidatePairConfig::IceCandidatePairConfigType type);
+
+IceCandidateType GetRuntimeIceCandidateType(
+ rtclog2::IceCandidatePairConfig::IceCandidateType type);
+
+IceCandidatePairProtocol GetRuntimeIceCandidatePairProtocol(
+ rtclog2::IceCandidatePairConfig::Protocol protocol);
+
+IceCandidatePairAddressFamily GetRuntimeIceCandidatePairAddressFamily(
+ rtclog2::IceCandidatePairConfig::AddressFamily address_family);
+
+IceCandidateNetworkType GetRuntimeIceCandidateNetworkType(
+ rtclog2::IceCandidatePairConfig::NetworkType network_type);
+
+IceCandidatePairEventType GetRuntimeIceCandidatePairEventType(
+ rtclog2::IceCandidatePairEvent::IceCandidatePairEventType type);
+
+std::vector<RtpExtension> GetRuntimeRtpHeaderExtensionConfig(
+ const rtclog2::RtpHeaderExtensionConfig& proto_header_extensions);
+// End of conversion functions.
+
+class ParsedRtcEventLog {
+ public:
+ enum class MediaType { ANY, AUDIO, VIDEO, DATA };
+ enum class UnconfiguredHeaderExtensions {
+ kDontParse,
+ kAttemptWebrtcDefaultConfig
+ };
+
+ using ParseStatus = RtcEventLogParseStatus;
+
+ template <typename T>
+ using ParseStatusOr = RtcEventLogParseStatusOr<T>;
+
+ struct LoggedRtpStreamIncoming {
+ LoggedRtpStreamIncoming();
+ LoggedRtpStreamIncoming(const LoggedRtpStreamIncoming&);
+ ~LoggedRtpStreamIncoming();
+ uint32_t ssrc;
+ std::vector<LoggedRtpPacketIncoming> incoming_packets;
+ };
+
+ struct LoggedRtpStreamOutgoing {
+ LoggedRtpStreamOutgoing();
+ LoggedRtpStreamOutgoing(const LoggedRtpStreamOutgoing&);
+ ~LoggedRtpStreamOutgoing();
+ uint32_t ssrc;
+ std::vector<LoggedRtpPacketOutgoing> outgoing_packets;
+ };
+
+ struct LoggedRtpStreamView {
+ LoggedRtpStreamView(uint32_t ssrc,
+ const std::vector<LoggedRtpPacketIncoming>& packets);
+ LoggedRtpStreamView(uint32_t ssrc,
+ const std::vector<LoggedRtpPacketOutgoing>& packets);
+ LoggedRtpStreamView(const LoggedRtpStreamView&);
+ uint32_t ssrc;
+ DereferencingVector<const LoggedRtpPacket> packet_view;
+ };
+
+ class LogSegment {
+ public:
+ LogSegment(int64_t start_time_us, int64_t stop_time_us)
+ : start_time_us_(start_time_us), stop_time_us_(stop_time_us) {}
+ int64_t start_time_ms() const { return start_time_us_ / 1000; }
+ int64_t start_time_us() const { return start_time_us_; }
+ int64_t stop_time_ms() const { return stop_time_us_ / 1000; }
+ int64_t stop_time_us() const { return stop_time_us_; }
+
+ private:
+ int64_t start_time_us_;
+ int64_t stop_time_us_;
+ };
+
+ static webrtc::RtpHeaderExtensionMap GetDefaultHeaderExtensionMap();
+
+ explicit ParsedRtcEventLog(
+ UnconfiguredHeaderExtensions parse_unconfigured_header_extensions =
+ UnconfiguredHeaderExtensions::kDontParse,
+ bool allow_incomplete_log = false);
+
+ ~ParsedRtcEventLog();
+
+ // Clears previously parsed events and resets the ParsedRtcEventLogNew to an
+ // empty state.
+ void Clear();
+
+ // Reads an RtcEventLog file and returns success if parsing was successful.
+ ParseStatus ParseFile(absl::string_view file_name);
+
+ // Reads an RtcEventLog from a string and returns success if successful.
+ ParseStatus ParseString(absl::string_view s);
+
+ // Reads an RtcEventLog from an string and returns success if successful.
+ ParseStatus ParseStream(absl::string_view s);
+
+ MediaType GetMediaType(uint32_t ssrc, PacketDirection direction) const;
+
+ // Configured SSRCs.
+ const std::set<uint32_t>& incoming_rtx_ssrcs() const {
+ return incoming_rtx_ssrcs_;
+ }
+
+ const std::set<uint32_t>& incoming_video_ssrcs() const {
+ return incoming_video_ssrcs_;
+ }
+
+ const std::set<uint32_t>& incoming_audio_ssrcs() const {
+ return incoming_audio_ssrcs_;
+ }
+
+ const std::set<uint32_t>& outgoing_rtx_ssrcs() const {
+ return outgoing_rtx_ssrcs_;
+ }
+
+ const std::set<uint32_t>& outgoing_video_ssrcs() const {
+ return outgoing_video_ssrcs_;
+ }
+
+ const std::set<uint32_t>& outgoing_audio_ssrcs() const {
+ return outgoing_audio_ssrcs_;
+ }
+
+ // Stream configurations.
+ const std::vector<LoggedAudioRecvConfig>& audio_recv_configs() const {
+ return audio_recv_configs_;
+ }
+
+ const std::vector<LoggedAudioSendConfig>& audio_send_configs() const {
+ return audio_send_configs_;
+ }
+
+ const std::vector<LoggedVideoRecvConfig>& video_recv_configs() const {
+ return video_recv_configs_;
+ }
+
+ const std::vector<LoggedVideoSendConfig>& video_send_configs() const {
+ return video_send_configs_;
+ }
+
+ // Beginning and end of log segments.
+ const std::vector<LoggedStartEvent>& start_log_events() const {
+ return start_log_events_;
+ }
+
+ const std::vector<LoggedStopEvent>& stop_log_events() const {
+ return stop_log_events_;
+ }
+
+ const std::vector<LoggedAlrStateEvent>& alr_state_events() const {
+ return alr_state_events_;
+ }
+
+ // Audio
+ const std::map<uint32_t, std::vector<LoggedAudioPlayoutEvent>>&
+ audio_playout_events() const {
+ return audio_playout_events_;
+ }
+
+ const std::map<uint32_t, std::vector<LoggedNetEqSetMinimumDelayEvent>>&
+ neteq_set_minimum_delay_events() const {
+ return neteq_set_minimum_delay_events_;
+ }
+
+ const std::vector<LoggedAudioNetworkAdaptationEvent>&
+ audio_network_adaptation_events() const {
+ return audio_network_adaptation_events_;
+ }
+
+ // Bandwidth estimation
+ const std::vector<LoggedBweProbeClusterCreatedEvent>&
+ bwe_probe_cluster_created_events() const {
+ return bwe_probe_cluster_created_events_;
+ }
+
+ const std::vector<LoggedBweProbeFailureEvent>& bwe_probe_failure_events()
+ const {
+ return bwe_probe_failure_events_;
+ }
+
+ const std::vector<LoggedBweProbeSuccessEvent>& bwe_probe_success_events()
+ const {
+ return bwe_probe_success_events_;
+ }
+
+ const std::vector<LoggedBweDelayBasedUpdate>& bwe_delay_updates() const {
+ return bwe_delay_updates_;
+ }
+
+ const std::vector<LoggedBweLossBasedUpdate>& bwe_loss_updates() const {
+ return bwe_loss_updates_;
+ }
+
+ // DTLS
+ const std::vector<LoggedDtlsTransportState>& dtls_transport_states() const {
+ return dtls_transport_states_;
+ }
+
+ const std::vector<LoggedDtlsWritableState>& dtls_writable_states() const {
+ return dtls_writable_states_;
+ }
+
+ // ICE events
+ const std::vector<LoggedIceCandidatePairConfig>& ice_candidate_pair_configs()
+ const {
+ return ice_candidate_pair_configs_;
+ }
+
+ const std::vector<LoggedIceCandidatePairEvent>& ice_candidate_pair_events()
+ const {
+ return ice_candidate_pair_events_;
+ }
+
+ const std::vector<LoggedRouteChangeEvent>& route_change_events() const {
+ return route_change_events_;
+ }
+
+ const std::vector<LoggedRemoteEstimateEvent>& remote_estimate_events() const {
+ return remote_estimate_events_;
+ }
+
+ // RTP
+ const std::vector<LoggedRtpStreamIncoming>& incoming_rtp_packets_by_ssrc()
+ const {
+ return incoming_rtp_packets_by_ssrc_;
+ }
+
+ const std::vector<LoggedRtpStreamOutgoing>& outgoing_rtp_packets_by_ssrc()
+ const {
+ return outgoing_rtp_packets_by_ssrc_;
+ }
+
+ const std::vector<LoggedRtpStreamView>& rtp_packets_by_ssrc(
+ PacketDirection direction) const {
+ if (direction == kIncomingPacket)
+ return incoming_rtp_packet_views_by_ssrc_;
+ else
+ return outgoing_rtp_packet_views_by_ssrc_;
+ }
+
+ // RTCP
+ const std::vector<LoggedRtcpPacketIncoming>& incoming_rtcp_packets() const {
+ return incoming_rtcp_packets_;
+ }
+
+ const std::vector<LoggedRtcpPacketOutgoing>& outgoing_rtcp_packets() const {
+ return outgoing_rtcp_packets_;
+ }
+
+ const std::vector<LoggedRtcpPacketReceiverReport>& receiver_reports(
+ PacketDirection direction) const {
+ if (direction == kIncomingPacket) {
+ return incoming_rr_;
+ } else {
+ return outgoing_rr_;
+ }
+ }
+
+ const std::vector<LoggedRtcpPacketSenderReport>& sender_reports(
+ PacketDirection direction) const {
+ if (direction == kIncomingPacket) {
+ return incoming_sr_;
+ } else {
+ return outgoing_sr_;
+ }
+ }
+
+ const std::vector<LoggedRtcpPacketExtendedReports>& extended_reports(
+ PacketDirection direction) const {
+ if (direction == kIncomingPacket) {
+ return incoming_xr_;
+ } else {
+ return outgoing_xr_;
+ }
+ }
+
+ const std::vector<LoggedRtcpPacketNack>& nacks(
+ PacketDirection direction) const {
+ if (direction == kIncomingPacket) {
+ return incoming_nack_;
+ } else {
+ return outgoing_nack_;
+ }
+ }
+
+ const std::vector<LoggedRtcpPacketRemb>& rembs(
+ PacketDirection direction) const {
+ if (direction == kIncomingPacket) {
+ return incoming_remb_;
+ } else {
+ return outgoing_remb_;
+ }
+ }
+
+ const std::vector<LoggedRtcpPacketFir>& firs(
+ PacketDirection direction) const {
+ if (direction == kIncomingPacket) {
+ return incoming_fir_;
+ } else {
+ return outgoing_fir_;
+ }
+ }
+
+ const std::vector<LoggedRtcpPacketPli>& plis(
+ PacketDirection direction) const {
+ if (direction == kIncomingPacket) {
+ return incoming_pli_;
+ } else {
+ return outgoing_pli_;
+ }
+ }
+
+ const std::vector<LoggedRtcpPacketBye>& byes(
+ PacketDirection direction) const {
+ if (direction == kIncomingPacket) {
+ return incoming_bye_;
+ } else {
+ return outgoing_bye_;
+ }
+ }
+
+ const std::vector<LoggedRtcpPacketTransportFeedback>& transport_feedbacks(
+ PacketDirection direction) const {
+ if (direction == kIncomingPacket) {
+ return incoming_transport_feedback_;
+ } else {
+ return outgoing_transport_feedback_;
+ }
+ }
+
+ const std::vector<LoggedRtcpPacketLossNotification>& loss_notifications(
+ PacketDirection direction) {
+ if (direction == kIncomingPacket) {
+ return incoming_loss_notification_;
+ } else {
+ return outgoing_loss_notification_;
+ }
+ }
+
+ const std::vector<LoggedGenericPacketReceived>& generic_packets_received()
+ const {
+ return generic_packets_received_;
+ }
+ const std::vector<LoggedGenericPacketSent>& generic_packets_sent() const {
+ return generic_packets_sent_;
+ }
+
+ const std::vector<LoggedGenericAckReceived>& generic_acks_received() const {
+ return generic_acks_received_;
+ }
+
+ // Media
+ const std::map<uint32_t, std::vector<LoggedFrameDecoded>>& decoded_frames()
+ const {
+ return decoded_frames_;
+ }
+
+ Timestamp first_timestamp() const { return first_timestamp_; }
+ Timestamp last_timestamp() const { return last_timestamp_; }
+
+ const LogSegment& first_log_segment() const { return first_log_segment_; }
+
+ std::vector<LoggedPacketInfo> GetPacketInfos(PacketDirection direction) const;
+ std::vector<LoggedPacketInfo> GetIncomingPacketInfos() const {
+ return GetPacketInfos(kIncomingPacket);
+ }
+ std::vector<LoggedPacketInfo> GetOutgoingPacketInfos() const {
+ return GetPacketInfos(kOutgoingPacket);
+ }
+ std::vector<LoggedIceCandidatePairConfig> GetIceCandidates() const;
+ std::vector<LoggedIceEvent> GetIceEvents() const;
+
+ std::vector<InferredRouteChangeEvent> GetRouteChanges() const;
+
+ private:
+ ABSL_MUST_USE_RESULT ParseStatus ParseStreamInternal(absl::string_view s);
+ ABSL_MUST_USE_RESULT ParseStatus ParseStreamInternalV3(absl::string_view s);
+
+ ABSL_MUST_USE_RESULT ParseStatus
+ StoreParsedLegacyEvent(const rtclog::Event& event);
+
+ template <typename T>
+ void StoreFirstAndLastTimestamp(const std::vector<T>& v);
+
+ // Returns: a pointer to a header extensions map acquired from parsing
+ // corresponding Audio/Video Sender/Receiver config events.
+ // Warning: if the same SSRC is reused by both video and audio streams during
+ // call, extensions maps may be incorrect (the last one would be returned).
+ const RtpHeaderExtensionMap* GetRtpHeaderExtensionMap(bool incoming,
+ uint32_t ssrc);
+
+ // Reads packet, direction and packet length from the RTCP event at `index`,
+ // and stores the values in the corresponding output parameters.
+ // Each output parameter can be set to nullptr if that value isn't needed.
+ // NB: The packet must have space for at least IP_PACKET_SIZE bytes.
+ ParseStatus GetRtcpPacket(const rtclog::Event& event,
+ PacketDirection* incoming,
+ std::vector<uint8_t>* packet) const;
+
+ ParseStatusOr<rtclog::StreamConfig> GetVideoReceiveConfig(
+ const rtclog::Event& event) const;
+ ParseStatusOr<rtclog::StreamConfig> GetVideoSendConfig(
+ const rtclog::Event& event) const;
+ ParseStatusOr<rtclog::StreamConfig> GetAudioReceiveConfig(
+ const rtclog::Event& event) const;
+ ParseStatusOr<rtclog::StreamConfig> GetAudioSendConfig(
+ const rtclog::Event& event) const;
+
+ ParsedRtcEventLog::ParseStatusOr<LoggedAudioPlayoutEvent> GetAudioPlayout(
+ const rtclog::Event& event) const;
+
+ ParsedRtcEventLog::ParseStatusOr<LoggedBweLossBasedUpdate>
+ GetLossBasedBweUpdate(const rtclog::Event& event) const;
+
+ ParsedRtcEventLog::ParseStatusOr<LoggedBweDelayBasedUpdate>
+ GetDelayBasedBweUpdate(const rtclog::Event& event) const;
+
+ ParsedRtcEventLog::ParseStatusOr<LoggedAudioNetworkAdaptationEvent>
+ GetAudioNetworkAdaptation(const rtclog::Event& event) const;
+
+ ParsedRtcEventLog::ParseStatusOr<LoggedBweProbeClusterCreatedEvent>
+ GetBweProbeClusterCreated(const rtclog::Event& event) const;
+
+ ParsedRtcEventLog::ParseStatusOr<LoggedBweProbeFailureEvent>
+ GetBweProbeFailure(const rtclog::Event& event) const;
+
+ ParsedRtcEventLog::ParseStatusOr<LoggedBweProbeSuccessEvent>
+ GetBweProbeSuccess(const rtclog::Event& event) const;
+
+ ParsedRtcEventLog::ParseStatusOr<LoggedAlrStateEvent> GetAlrState(
+ const rtclog::Event& event) const;
+
+ ParsedRtcEventLog::ParseStatusOr<LoggedIceCandidatePairConfig>
+ GetIceCandidatePairConfig(const rtclog::Event& event) const;
+
+ ParsedRtcEventLog::ParseStatusOr<LoggedIceCandidatePairEvent>
+ GetIceCandidatePairEvent(const rtclog::Event& event) const;
+
+ ParsedRtcEventLog::ParseStatusOr<LoggedRemoteEstimateEvent>
+ GetRemoteEstimateEvent(const rtclog::Event& event) const;
+
+ // Parsing functions for new format.
+ ParseStatus StoreAlrStateEvent(const rtclog2::AlrState& proto);
+ ParseStatus StoreAudioNetworkAdaptationEvent(
+ const rtclog2::AudioNetworkAdaptations& proto);
+ ParseStatus StoreAudioPlayoutEvent(const rtclog2::AudioPlayoutEvents& proto);
+ ParseStatus StoreAudioRecvConfig(const rtclog2::AudioRecvStreamConfig& proto);
+ ParseStatus StoreAudioSendConfig(const rtclog2::AudioSendStreamConfig& proto);
+ ParseStatus StoreBweDelayBasedUpdate(
+ const rtclog2::DelayBasedBweUpdates& proto);
+ ParseStatus StoreBweLossBasedUpdate(
+ const rtclog2::LossBasedBweUpdates& proto);
+ ParseStatus StoreBweProbeClusterCreated(
+ const rtclog2::BweProbeCluster& proto);
+ ParseStatus StoreBweProbeFailureEvent(
+ const rtclog2::BweProbeResultFailure& proto);
+ ParseStatus StoreBweProbeSuccessEvent(
+ const rtclog2::BweProbeResultSuccess& proto);
+ ParseStatus StoreDtlsTransportState(
+ const rtclog2::DtlsTransportStateEvent& proto);
+ ParseStatus StoreDtlsWritableState(const rtclog2::DtlsWritableState& proto);
+ ParsedRtcEventLog::ParseStatus StoreFrameDecodedEvents(
+ const rtclog2::FrameDecodedEvents& proto);
+ ParseStatus StoreGenericAckReceivedEvent(
+ const rtclog2::GenericAckReceived& proto);
+ ParseStatus StoreGenericPacketReceivedEvent(
+ const rtclog2::GenericPacketReceived& proto);
+ ParseStatus StoreGenericPacketSentEvent(
+ const rtclog2::GenericPacketSent& proto);
+ ParseStatus StoreIceCandidateEvent(
+ const rtclog2::IceCandidatePairEvent& proto);
+ ParseStatus StoreIceCandidatePairConfig(
+ const rtclog2::IceCandidatePairConfig& proto);
+ ParseStatus StoreIncomingRtcpPackets(
+ const rtclog2::IncomingRtcpPackets& proto);
+ ParseStatus StoreIncomingRtpPackets(const rtclog2::IncomingRtpPackets& proto);
+ ParseStatus StoreNetEqSetMinimumDelay(
+ const rtclog2::NetEqSetMinimumDelay& proto);
+ ParseStatus StoreOutgoingRtcpPackets(
+ const rtclog2::OutgoingRtcpPackets& proto);
+ ParseStatus StoreOutgoingRtpPackets(const rtclog2::OutgoingRtpPackets& proto);
+ ParseStatus StoreParsedNewFormatEvent(const rtclog2::EventStream& event);
+ ParseStatus StoreRouteChangeEvent(const rtclog2::RouteChange& proto);
+ ParseStatus StoreRemoteEstimateEvent(const rtclog2::RemoteEstimates& proto);
+ ParseStatus StoreStartEvent(const rtclog2::BeginLogEvent& proto);
+ ParseStatus StoreStopEvent(const rtclog2::EndLogEvent& proto);
+ ParseStatus StoreVideoRecvConfig(const rtclog2::VideoRecvStreamConfig& proto);
+ ParseStatus StoreVideoSendConfig(const rtclog2::VideoSendStreamConfig& proto);
+ // End of new parsing functions.
+
+ struct Stream {
+ Stream(uint32_t ssrc,
+ MediaType media_type,
+ PacketDirection direction,
+ webrtc::RtpHeaderExtensionMap map)
+ : ssrc(ssrc),
+ media_type(media_type),
+ direction(direction),
+ rtp_extensions_map(map) {}
+ uint32_t ssrc;
+ MediaType media_type;
+ PacketDirection direction;
+ webrtc::RtpHeaderExtensionMap rtp_extensions_map;
+ };
+
+ const UnconfiguredHeaderExtensions parse_unconfigured_header_extensions_;
+ const bool allow_incomplete_logs_;
+
+ // Make a default extension map for streams without configuration information.
+ // TODO(ivoc): Once configuration of audio streams is stored in the event log,
+ // this can be removed. Tracking bug: webrtc:6399
+ RtpHeaderExtensionMap default_extension_map_;
+
+ // Tracks what each stream is configured for. Note that a single SSRC can be
+ // in several sets. For example, the SSRC used for sending video over RTX
+ // will appear in both video_ssrcs_ and rtx_ssrcs_. In the unlikely case that
+ // an SSRC is reconfigured to a different media type mid-call, it will also
+ // appear in multiple sets.
+ std::set<uint32_t> incoming_rtx_ssrcs_;
+ std::set<uint32_t> incoming_video_ssrcs_;
+ std::set<uint32_t> incoming_audio_ssrcs_;
+ std::set<uint32_t> outgoing_rtx_ssrcs_;
+ std::set<uint32_t> outgoing_video_ssrcs_;
+ std::set<uint32_t> outgoing_audio_ssrcs_;
+
+ // Maps an SSRC to the parsed RTP headers in that stream. Header extensions
+ // are parsed if the stream has been configured. This is only used for
+ // grouping the events by SSRC during parsing; the events are moved to
+ // incoming_rtp_packets_by_ssrc_ once the parsing is done.
+ std::map<uint32_t, std::vector<LoggedRtpPacketIncoming>>
+ incoming_rtp_packets_map_;
+ std::map<uint32_t, std::vector<LoggedRtpPacketOutgoing>>
+ outgoing_rtp_packets_map_;
+
+ // RTP headers.
+ std::vector<LoggedRtpStreamIncoming> incoming_rtp_packets_by_ssrc_;
+ std::vector<LoggedRtpStreamOutgoing> outgoing_rtp_packets_by_ssrc_;
+ std::vector<LoggedRtpStreamView> incoming_rtp_packet_views_by_ssrc_;
+ std::vector<LoggedRtpStreamView> outgoing_rtp_packet_views_by_ssrc_;
+
+ // Raw RTCP packets.
+ std::vector<LoggedRtcpPacketIncoming> incoming_rtcp_packets_;
+ std::vector<LoggedRtcpPacketOutgoing> outgoing_rtcp_packets_;
+
+ // Parsed RTCP messages. Currently not separated based on SSRC.
+ std::vector<LoggedRtcpPacketReceiverReport> incoming_rr_;
+ std::vector<LoggedRtcpPacketReceiverReport> outgoing_rr_;
+ std::vector<LoggedRtcpPacketSenderReport> incoming_sr_;
+ std::vector<LoggedRtcpPacketSenderReport> outgoing_sr_;
+ std::vector<LoggedRtcpPacketExtendedReports> incoming_xr_;
+ std::vector<LoggedRtcpPacketExtendedReports> outgoing_xr_;
+ std::vector<LoggedRtcpPacketNack> incoming_nack_;
+ std::vector<LoggedRtcpPacketNack> outgoing_nack_;
+ std::vector<LoggedRtcpPacketRemb> incoming_remb_;
+ std::vector<LoggedRtcpPacketRemb> outgoing_remb_;
+ std::vector<LoggedRtcpPacketFir> incoming_fir_;
+ std::vector<LoggedRtcpPacketFir> outgoing_fir_;
+ std::vector<LoggedRtcpPacketPli> incoming_pli_;
+ std::vector<LoggedRtcpPacketPli> outgoing_pli_;
+ std::vector<LoggedRtcpPacketBye> incoming_bye_;
+ std::vector<LoggedRtcpPacketBye> outgoing_bye_;
+ std::vector<LoggedRtcpPacketTransportFeedback> incoming_transport_feedback_;
+ std::vector<LoggedRtcpPacketTransportFeedback> outgoing_transport_feedback_;
+ std::vector<LoggedRtcpPacketLossNotification> incoming_loss_notification_;
+ std::vector<LoggedRtcpPacketLossNotification> outgoing_loss_notification_;
+
+ std::vector<LoggedStartEvent> start_log_events_;
+ std::vector<LoggedStopEvent> stop_log_events_;
+
+ std::vector<LoggedAlrStateEvent> alr_state_events_;
+
+ std::map<uint32_t, std::vector<LoggedAudioPlayoutEvent>>
+ audio_playout_events_;
+ std::map<uint32_t, std::vector<LoggedNetEqSetMinimumDelayEvent>>
+ neteq_set_minimum_delay_events_;
+
+ std::vector<LoggedAudioNetworkAdaptationEvent>
+ audio_network_adaptation_events_;
+
+ std::vector<LoggedBweProbeClusterCreatedEvent>
+ bwe_probe_cluster_created_events_;
+
+ std::vector<LoggedBweProbeFailureEvent> bwe_probe_failure_events_;
+ std::vector<LoggedBweProbeSuccessEvent> bwe_probe_success_events_;
+
+ std::vector<LoggedBweDelayBasedUpdate> bwe_delay_updates_;
+ std::vector<LoggedBweLossBasedUpdate> bwe_loss_updates_;
+
+ std::vector<LoggedDtlsTransportState> dtls_transport_states_;
+ std::vector<LoggedDtlsWritableState> dtls_writable_states_;
+
+ std::map<uint32_t, std::vector<LoggedFrameDecoded>> decoded_frames_;
+
+ std::vector<LoggedIceCandidatePairConfig> ice_candidate_pair_configs_;
+ std::vector<LoggedIceCandidatePairEvent> ice_candidate_pair_events_;
+
+ std::vector<LoggedAudioRecvConfig> audio_recv_configs_;
+ std::vector<LoggedAudioSendConfig> audio_send_configs_;
+ 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_;
+
+ std::vector<LoggedRouteChangeEvent> route_change_events_;
+ std::vector<LoggedRemoteEstimateEvent> remote_estimate_events_;
+
+ std::vector<uint8_t> last_incoming_rtcp_packet_;
+
+ Timestamp first_timestamp_ = Timestamp::PlusInfinity();
+ Timestamp last_timestamp_ = Timestamp::MinusInfinity();
+
+ LogSegment first_log_segment_ =
+ LogSegment(0, std::numeric_limits<int64_t>::max());
+
+ // The extension maps are mutable to allow us to insert the default
+ // configuration when parsing an RTP header for an unconfigured stream.
+ // TODO(terelius): This is only used for the legacy format. Remove once we've
+ // fully transitioned to the new format.
+ mutable std::map<uint32_t, webrtc::RtpHeaderExtensionMap>
+ incoming_rtp_extensions_maps_;
+ mutable std::map<uint32_t, webrtc::RtpHeaderExtensionMap>
+ outgoing_rtp_extensions_maps_;
+};
+
+struct MatchedSendArrivalTimes {
+ static constexpr int64_t kNotReceived = -1;
+
+ MatchedSendArrivalTimes(int64_t fb, int64_t tx, int64_t rx, int64_t ps)
+ : feedback_arrival_time_ms(fb),
+ send_time_ms(tx),
+ arrival_time_ms(rx),
+ payload_size(ps) {}
+
+ int64_t feedback_arrival_time_ms;
+ int64_t send_time_ms;
+ int64_t arrival_time_ms; // kNotReceived for lost packets.
+ int64_t payload_size;
+};
+const std::vector<MatchedSendArrivalTimes> GetNetworkTrace(
+ const ParsedRtcEventLog& parsed_log);
+
+} // namespace webrtc
+
+#endif // LOGGING_RTC_EVENT_LOG_RTC_EVENT_LOG_PARSER_H_
diff --git a/third_party/libwebrtc/logging/rtc_event_log/rtc_event_log_unittest.cc b/third_party/libwebrtc/logging/rtc_event_log/rtc_event_log_unittest.cc
new file mode 100644
index 0000000000..314bfd90e9
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/rtc_event_log_unittest.cc
@@ -0,0 +1,1050 @@
+/*
+ * Copyright (c) 2015 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 "api/rtc_event_log/rtc_event_log.h"
+
+#include <algorithm>
+#include <limits>
+#include <map>
+#include <memory>
+#include <string>
+#include <tuple>
+#include <utility>
+#include <vector>
+
+#include "api/rtc_event_log/rtc_event_log_factory.h"
+#include "api/task_queue/default_task_queue_factory.h"
+#include "logging/rtc_event_log/events/rtc_event_audio_network_adaptation.h"
+#include "logging/rtc_event_log/events/rtc_event_audio_playout.h"
+#include "logging/rtc_event_log/events/rtc_event_audio_receive_stream_config.h"
+#include "logging/rtc_event_log/events/rtc_event_audio_send_stream_config.h"
+#include "logging/rtc_event_log/events/rtc_event_bwe_update_delay_based.h"
+#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"
+#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"
+#include "logging/rtc_event_log/events/rtc_event_rtp_packet_outgoing.h"
+#include "logging/rtc_event_log/events/rtc_event_video_receive_stream_config.h"
+#include "logging/rtc_event_log/events/rtc_event_video_send_stream_config.h"
+#include "logging/rtc_event_log/rtc_event_log_parser.h"
+#include "logging/rtc_event_log/rtc_event_log_unittest_helper.h"
+#include "logging/rtc_event_log/rtc_stream_config.h"
+#include "modules/rtp_rtcp/include/rtp_header_extension_map.h"
+#include "modules/rtp_rtcp/source/rtp_header_extensions.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/fake_clock.h"
+#include "rtc_base/random.h"
+#include "test/gtest.h"
+#include "test/logging/memory_log_writer.h"
+#include "test/testsupport/file_utils.h"
+
+namespace webrtc {
+
+namespace {
+
+struct EventCounts {
+ size_t audio_send_streams = 0;
+ size_t audio_recv_streams = 0;
+ 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;
+ size_t bwe_delay_events = 0;
+ size_t dtls_transport_states = 0;
+ size_t dtls_writable_states = 0;
+ size_t frame_decoded_events = 0;
+ size_t probe_creations = 0;
+ size_t probe_successes = 0;
+ size_t probe_failures = 0;
+ size_t ice_configs = 0;
+ size_t ice_events = 0;
+ size_t incoming_rtp_packets = 0;
+ 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 + route_changes + audio_playouts + ana_configs +
+ bwe_loss_events + bwe_delay_events + dtls_transport_states +
+ dtls_writable_states + frame_decoded_events + 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 {
+ return audio_send_streams + audio_recv_streams + video_send_streams +
+ video_recv_streams;
+ }
+
+ size_t total_events() const {
+ return total_nonconfig_events() + total_config_events();
+ }
+};
+
+class RtcEventLogSession
+ : public ::testing::TestWithParam<
+ std::tuple<uint64_t, int64_t, RtcEventLog::EncodingType>> {
+ public:
+ RtcEventLogSession()
+ : seed_(std::get<0>(GetParam())),
+ prng_(seed_),
+ output_period_ms_(std::get<1>(GetParam())),
+ encoding_type_(std::get<2>(GetParam())),
+ gen_(seed_ * 880001UL),
+ verifier_(encoding_type_),
+ log_storage_(),
+ log_output_factory_(log_storage_.CreateFactory()) {
+ clock_.SetTime(Timestamp::Micros(prng_.Rand<uint32_t>()));
+ // Find the name of the current test, in order to use it as a temporary
+ // filename.
+ auto test_info = ::testing::UnitTest::GetInstance()->current_test_info();
+ std::string test_name =
+ std::string(test_info->test_case_name()) + "_" + test_info->name();
+ std::replace(test_name.begin(), test_name.end(), '/', '_');
+ temp_filename_ = test::OutputPath() + test_name;
+ }
+
+ // Create and buffer the config events and `num_events_before_log_start`
+ // randomized non-config events. Then call StartLogging and finally create and
+ // write the remaining non-config events.
+ 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);
+ void WriteVideoRecvConfigs(size_t video_recv_streams, RtcEventLog* event_log);
+ void WriteVideoSendConfigs(size_t video_send_streams, RtcEventLog* event_log);
+
+ std::vector<std::pair<uint32_t, RtpHeaderExtensionMap>> incoming_extensions_;
+ std::vector<std::pair<uint32_t, RtpHeaderExtensionMap>> outgoing_extensions_;
+
+ // Config events.
+ std::vector<std::unique_ptr<RtcEventAudioSendStreamConfig>>
+ audio_send_config_list_;
+ std::vector<std::unique_ptr<RtcEventAudioReceiveStreamConfig>>
+ audio_recv_config_list_;
+ std::vector<std::unique_ptr<RtcEventVideoSendStreamConfig>>
+ video_send_config_list_;
+ std::vector<std::unique_ptr<RtcEventVideoReceiveStreamConfig>>
+ video_recv_config_list_;
+
+ // Regular events.
+ std::vector<std::unique_ptr<RtcEventAlrState>> alr_state_list_;
+ std::map<uint32_t, std::vector<std::unique_ptr<RtcEventAudioPlayout>>>
+ audio_playout_map_; // Groups audio by SSRC.
+ std::vector<std::unique_ptr<RtcEventAudioNetworkAdaptation>>
+ ana_configs_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::map<uint32_t, std::vector<std::unique_ptr<RtcEventFrameDecoded>>>
+ frame_decoded_event_map_;
+ 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<RtcEventProbeResultFailure>> probe_failure_list_;
+ std::vector<std::unique_ptr<RtcEventProbeResultSuccess>> probe_success_list_;
+ std::vector<std::unique_ptr<RtcEventRouteChange>> route_change_list_;
+ std::vector<std::unique_ptr<RtcEventRemoteEstimate>> remote_estimate_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.
+
+ int64_t start_time_us_;
+ int64_t utc_start_time_us_;
+ int64_t stop_time_us_;
+
+ int64_t first_timestamp_ms_ = std::numeric_limits<int64_t>::max();
+ int64_t last_timestamp_ms_ = std::numeric_limits<int64_t>::min();
+
+ const uint64_t seed_;
+ Random prng_;
+ const int64_t output_period_ms_;
+ const RtcEventLog::EncodingType encoding_type_;
+ test::EventGenerator gen_;
+ test::EventVerifier verifier_;
+ rtc::ScopedFakeClock clock_;
+ std::string temp_filename_;
+ MemoryLogStorage log_storage_;
+ std::unique_ptr<LogWriterFactoryInterface> log_output_factory_;
+};
+
+bool SsrcUsed(
+ uint32_t ssrc,
+ const std::vector<std::pair<uint32_t, RtpHeaderExtensionMap>>& streams) {
+ for (const auto& kv : streams) {
+ if (kv.first == ssrc)
+ return true;
+ }
+ return false;
+}
+
+void RtcEventLogSession::WriteAudioRecvConfigs(size_t audio_recv_streams,
+ RtcEventLog* event_log) {
+ RTC_CHECK(event_log != nullptr);
+ uint32_t ssrc;
+ for (size_t i = 0; i < audio_recv_streams; i++) {
+ clock_.AdvanceTime(TimeDelta::Millis(prng_.Rand(20)));
+ do {
+ ssrc = prng_.Rand<uint32_t>();
+ } while (SsrcUsed(ssrc, incoming_extensions_));
+ RtpHeaderExtensionMap extensions = gen_.NewRtpHeaderExtensionMap();
+ incoming_extensions_.emplace_back(ssrc, extensions);
+ auto event = gen_.NewAudioReceiveStreamConfig(ssrc, extensions);
+ event_log->Log(event->Copy());
+ audio_recv_config_list_.push_back(std::move(event));
+ }
+}
+
+void RtcEventLogSession::WriteAudioSendConfigs(size_t audio_send_streams,
+ RtcEventLog* event_log) {
+ RTC_CHECK(event_log != nullptr);
+ uint32_t ssrc;
+ for (size_t i = 0; i < audio_send_streams; i++) {
+ clock_.AdvanceTime(TimeDelta::Millis(prng_.Rand(20)));
+ do {
+ ssrc = prng_.Rand<uint32_t>();
+ } while (SsrcUsed(ssrc, outgoing_extensions_));
+ RtpHeaderExtensionMap extensions = gen_.NewRtpHeaderExtensionMap();
+ outgoing_extensions_.emplace_back(ssrc, extensions);
+ auto event = gen_.NewAudioSendStreamConfig(ssrc, extensions);
+ event_log->Log(event->Copy());
+ audio_send_config_list_.push_back(std::move(event));
+ }
+}
+
+void RtcEventLogSession::WriteVideoRecvConfigs(size_t video_recv_streams,
+ RtcEventLog* event_log) {
+ RTC_CHECK(event_log != nullptr);
+ RTC_CHECK_GE(video_recv_streams, 1);
+
+ // Force least one stream to use all header extensions, to ensure
+ // (statistically) that every extension is tested in packet creation.
+ RtpHeaderExtensionMap all_extensions =
+ ParsedRtcEventLog::GetDefaultHeaderExtensionMap();
+
+ clock_.AdvanceTime(TimeDelta::Millis(prng_.Rand(20)));
+ uint32_t ssrc = prng_.Rand<uint32_t>();
+ incoming_extensions_.emplace_back(ssrc, all_extensions);
+ auto event = gen_.NewVideoReceiveStreamConfig(ssrc, all_extensions);
+ event_log->Log(event->Copy());
+ video_recv_config_list_.push_back(std::move(event));
+ for (size_t i = 1; i < video_recv_streams; i++) {
+ clock_.AdvanceTime(TimeDelta::Millis(prng_.Rand(20)));
+ do {
+ ssrc = prng_.Rand<uint32_t>();
+ } while (SsrcUsed(ssrc, incoming_extensions_));
+ RtpHeaderExtensionMap extensions = gen_.NewRtpHeaderExtensionMap();
+ incoming_extensions_.emplace_back(ssrc, extensions);
+ auto new_event = gen_.NewVideoReceiveStreamConfig(ssrc, extensions);
+ event_log->Log(new_event->Copy());
+ video_recv_config_list_.push_back(std::move(new_event));
+ }
+}
+
+void RtcEventLogSession::WriteVideoSendConfigs(size_t video_send_streams,
+ RtcEventLog* event_log) {
+ RTC_CHECK(event_log != nullptr);
+ RTC_CHECK_GE(video_send_streams, 1);
+
+ // Force least one stream to use all header extensions, to ensure
+ // (statistically) that every extension is tested in packet creation.
+ RtpHeaderExtensionMap all_extensions =
+ ParsedRtcEventLog::GetDefaultHeaderExtensionMap();
+
+ clock_.AdvanceTime(TimeDelta::Millis(prng_.Rand(20)));
+ uint32_t ssrc = prng_.Rand<uint32_t>();
+ outgoing_extensions_.emplace_back(ssrc, all_extensions);
+ auto event = gen_.NewVideoSendStreamConfig(ssrc, all_extensions);
+ event_log->Log(event->Copy());
+ video_send_config_list_.push_back(std::move(event));
+ for (size_t i = 1; i < video_send_streams; i++) {
+ clock_.AdvanceTime(TimeDelta::Millis(prng_.Rand(20)));
+ do {
+ ssrc = prng_.Rand<uint32_t>();
+ } while (SsrcUsed(ssrc, outgoing_extensions_));
+ RtpHeaderExtensionMap extensions = gen_.NewRtpHeaderExtensionMap();
+ outgoing_extensions_.emplace_back(ssrc, extensions);
+ auto event = gen_.NewVideoSendStreamConfig(ssrc, extensions);
+ event_log->Log(event->Copy());
+ video_send_config_list_.push_back(std::move(event));
+ }
+}
+
+void RtcEventLogSession::WriteLog(EventCounts count,
+ size_t num_events_before_start) {
+ // TODO(terelius): Allow test to run with either a real or a fake clock_.
+ // Maybe always use the ScopedFakeClock, but conditionally SleepMs()?
+
+ auto task_queue_factory = CreateDefaultTaskQueueFactory();
+ RtcEventLogFactory rtc_event_log_factory(task_queue_factory.get());
+ // The log will be flushed to output when the event_log goes out of scope.
+ std::unique_ptr<RtcEventLog> event_log =
+ rtc_event_log_factory.CreateRtcEventLog(encoding_type_);
+
+ // We can't send or receive packets without configured streams.
+ RTC_CHECK_GE(count.video_recv_streams, 1);
+ RTC_CHECK_GE(count.video_send_streams, 1);
+
+ WriteAudioRecvConfigs(count.audio_recv_streams, event_log.get());
+ WriteAudioSendConfigs(count.audio_send_streams, event_log.get());
+ WriteVideoRecvConfigs(count.video_recv_streams, event_log.get());
+ WriteVideoSendConfigs(count.video_send_streams, event_log.get());
+
+ size_t remaining_events = count.total_nonconfig_events();
+ ASSERT_LE(num_events_before_start, remaining_events);
+ size_t remaining_events_at_start = remaining_events - num_events_before_start;
+ for (; remaining_events > 0; remaining_events--) {
+ if (remaining_events == remaining_events_at_start) {
+ clock_.AdvanceTime(TimeDelta::Millis(prng_.Rand(20)));
+ event_log->StartLogging(log_output_factory_->Create(temp_filename_),
+ output_period_ms_);
+ start_time_us_ = rtc::TimeMicros();
+ utc_start_time_us_ = rtc::TimeUTCMicros();
+ }
+
+ clock_.AdvanceTime(TimeDelta::Millis(prng_.Rand(20)));
+ size_t selection = prng_.Rand(remaining_events - 1);
+ first_timestamp_ms_ = std::min(first_timestamp_ms_, rtc::TimeMillis());
+ last_timestamp_ms_ = std::max(last_timestamp_ms_, rtc::TimeMillis());
+
+ if (selection < count.alr_states) {
+ auto event = gen_.NewAlrState();
+ event_log->Log(event->Copy());
+ alr_state_list_.push_back(std::move(event));
+ count.alr_states--;
+ continue;
+ }
+ 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.
+ uint32_t ssrc = incoming_extensions_[stream].first;
+ auto event = gen_.NewAudioPlayout(ssrc);
+ event_log->Log(event->Copy());
+ audio_playout_map_[ssrc].push_back(std::move(event));
+ count.audio_playouts--;
+ continue;
+ }
+ selection -= count.audio_playouts;
+
+ if (selection < count.ana_configs) {
+ auto event = gen_.NewAudioNetworkAdaptation();
+ event_log->Log(event->Copy());
+ ana_configs_list_.push_back(std::move(event));
+ count.ana_configs--;
+ continue;
+ }
+ selection -= count.ana_configs;
+
+ if (selection < count.bwe_loss_events) {
+ auto event = gen_.NewBweUpdateLossBased();
+ event_log->Log(event->Copy());
+ bwe_loss_list_.push_back(std::move(event));
+ count.bwe_loss_events--;
+ continue;
+ }
+ selection -= count.bwe_loss_events;
+
+ if (selection < count.bwe_delay_events) {
+ auto event = gen_.NewBweUpdateDelayBased();
+ event_log->Log(event->Copy());
+ bwe_delay_list_.push_back(std::move(event));
+ count.bwe_delay_events--;
+ continue;
+ }
+ selection -= count.bwe_delay_events;
+
+ if (selection < count.probe_creations) {
+ auto event = gen_.NewProbeClusterCreated();
+ event_log->Log(event->Copy());
+ probe_creation_list_.push_back(std::move(event));
+ count.probe_creations--;
+ continue;
+ }
+ selection -= count.probe_creations;
+
+ if (selection < count.probe_successes) {
+ auto event = gen_.NewProbeResultSuccess();
+ event_log->Log(event->Copy());
+ probe_success_list_.push_back(std::move(event));
+ count.probe_successes--;
+ continue;
+ }
+ selection -= count.probe_successes;
+
+ if (selection < count.probe_failures) {
+ auto event = gen_.NewProbeResultFailure();
+ event_log->Log(event->Copy());
+ probe_failure_list_.push_back(std::move(event));
+ count.probe_failures--;
+ continue;
+ }
+ selection -= count.probe_failures;
+
+ if (selection < count.dtls_transport_states) {
+ auto event = gen_.NewDtlsTransportState();
+ event_log->Log(event->Copy());
+ dtls_transport_state_list_.push_back(std::move(event));
+ count.dtls_transport_states--;
+ continue;
+ }
+ selection -= count.dtls_transport_states;
+
+ if (selection < count.dtls_writable_states) {
+ auto event = gen_.NewDtlsWritableState();
+ event_log->Log(event->Copy());
+ dtls_writable_state_list_.push_back(std::move(event));
+ count.dtls_writable_states--;
+ continue;
+ }
+ selection -= count.dtls_writable_states;
+
+ if (selection < count.frame_decoded_events) {
+ size_t stream = prng_.Rand(incoming_extensions_.size() - 1);
+ // This might be an audio SSRC, but that won't affect the parser.
+ uint32_t ssrc = incoming_extensions_[stream].first;
+ auto event = gen_.NewFrameDecodedEvent(ssrc);
+ event_log->Log(event->Copy());
+ frame_decoded_event_map_[ssrc].push_back(std::move(event));
+ count.frame_decoded_events--;
+ continue;
+ }
+ selection -= count.frame_decoded_events;
+
+ if (selection < count.ice_configs) {
+ auto event = gen_.NewIceCandidatePairConfig();
+ event_log->Log(event->Copy());
+ ice_config_list_.push_back(std::move(event));
+ count.ice_configs--;
+ continue;
+ }
+ selection -= count.ice_configs;
+
+ if (selection < count.ice_events) {
+ auto event = gen_.NewIceCandidatePair();
+ event_log->Log(event->Copy());
+ ice_event_list_.push_back(std::move(event));
+ count.ice_events--;
+ continue;
+ }
+ selection -= count.ice_events;
+
+ if (selection < count.incoming_rtp_packets) {
+ size_t stream = prng_.Rand(incoming_extensions_.size() - 1);
+ uint32_t ssrc = incoming_extensions_[stream].first;
+ auto event =
+ gen_.NewRtpPacketIncoming(ssrc, incoming_extensions_[stream].second);
+ event_log->Log(event->Copy());
+ incoming_rtp_map_[ssrc].push_back(std::move(event));
+ count.incoming_rtp_packets--;
+ continue;
+ }
+ selection -= count.incoming_rtp_packets;
+
+ if (selection < count.outgoing_rtp_packets) {
+ size_t stream = prng_.Rand(outgoing_extensions_.size() - 1);
+ uint32_t ssrc = outgoing_extensions_[stream].first;
+ auto event =
+ gen_.NewRtpPacketOutgoing(ssrc, outgoing_extensions_[stream].second);
+ event_log->Log(event->Copy());
+ outgoing_rtp_map_[ssrc].push_back(std::move(event));
+ count.outgoing_rtp_packets--;
+ continue;
+ }
+ selection -= count.outgoing_rtp_packets;
+
+ if (selection < count.incoming_rtcp_packets) {
+ auto event = gen_.NewRtcpPacketIncoming();
+ event_log->Log(event->Copy());
+ incoming_rtcp_list_.push_back(std::move(event));
+ count.incoming_rtcp_packets--;
+ continue;
+ }
+ selection -= count.incoming_rtcp_packets;
+
+ if (selection < count.outgoing_rtcp_packets) {
+ auto event = gen_.NewRtcpPacketOutgoing();
+ event_log->Log(event->Copy());
+ outgoing_rtcp_list_.push_back(std::move(event));
+ count.outgoing_rtcp_packets--;
+ continue;
+ }
+ 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_DCHECK_NOTREACHED();
+ }
+
+ event_log->StopLogging();
+ stop_time_us_ = rtc::TimeMicros();
+
+ ASSERT_EQ(count.total_nonconfig_events(), static_cast<size_t>(0));
+}
+
+// Read the log and verify that what we read back from the event log is the
+// same as what we wrote down.
+void RtcEventLogSession::ReadAndVerifyLog() {
+ // Read the generated log from memory.
+ ParsedRtcEventLog parsed_log;
+ auto it = log_storage_.logs().find(temp_filename_);
+ ASSERT_TRUE(it != log_storage_.logs().end());
+ ASSERT_TRUE(parsed_log.ParseString(it->second).ok());
+
+ // Start and stop events.
+ auto& parsed_start_log_events = parsed_log.start_log_events();
+ ASSERT_EQ(parsed_start_log_events.size(), static_cast<size_t>(1));
+ verifier_.VerifyLoggedStartEvent(start_time_us_, utc_start_time_us_,
+ parsed_start_log_events[0]);
+
+ auto& parsed_stop_log_events = parsed_log.stop_log_events();
+ ASSERT_EQ(parsed_stop_log_events.size(), static_cast<size_t>(1));
+ verifier_.VerifyLoggedStopEvent(stop_time_us_, parsed_stop_log_events[0]);
+
+ auto& parsed_alr_state_events = parsed_log.alr_state_events();
+ ASSERT_EQ(parsed_alr_state_events.size(), alr_state_list_.size());
+ for (size_t i = 0; i < parsed_alr_state_events.size(); i++) {
+ 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());
+ for (const auto& kv : parsed_audio_playout_map) {
+ uint32_t ssrc = kv.first;
+ const auto& parsed_audio_playout_stream = kv.second;
+ const auto& audio_playout_stream = audio_playout_map_[ssrc];
+ ASSERT_EQ(parsed_audio_playout_stream.size(), audio_playout_stream.size());
+ for (size_t i = 0; i < audio_playout_stream.size(); i++) {
+ verifier_.VerifyLoggedAudioPlayoutEvent(*audio_playout_stream[i],
+ parsed_audio_playout_stream[i]);
+ }
+ }
+
+ auto& parsed_audio_network_adaptation_events =
+ parsed_log.audio_network_adaptation_events();
+ ASSERT_EQ(parsed_audio_network_adaptation_events.size(),
+ ana_configs_list_.size());
+ for (size_t i = 0; i < parsed_audio_network_adaptation_events.size(); i++) {
+ verifier_.VerifyLoggedAudioNetworkAdaptationEvent(
+ *ana_configs_list_[i], parsed_audio_network_adaptation_events[i]);
+ }
+
+ auto& parsed_bwe_delay_updates = parsed_log.bwe_delay_updates();
+ ASSERT_EQ(parsed_bwe_delay_updates.size(), bwe_delay_list_.size());
+ for (size_t i = 0; i < parsed_bwe_delay_updates.size(); i++) {
+ verifier_.VerifyLoggedBweDelayBasedUpdate(*bwe_delay_list_[i],
+ parsed_bwe_delay_updates[i]);
+ }
+
+ auto& parsed_bwe_loss_updates = parsed_log.bwe_loss_updates();
+ ASSERT_EQ(parsed_bwe_loss_updates.size(), bwe_loss_list_.size());
+ for (size_t i = 0; i < parsed_bwe_loss_updates.size(); i++) {
+ verifier_.VerifyLoggedBweLossBasedUpdate(*bwe_loss_list_[i],
+ parsed_bwe_loss_updates[i]);
+ }
+
+ auto& parsed_bwe_probe_cluster_created_events =
+ parsed_log.bwe_probe_cluster_created_events();
+ ASSERT_EQ(parsed_bwe_probe_cluster_created_events.size(),
+ probe_creation_list_.size());
+ for (size_t i = 0; i < parsed_bwe_probe_cluster_created_events.size(); i++) {
+ verifier_.VerifyLoggedBweProbeClusterCreatedEvent(
+ *probe_creation_list_[i], parsed_bwe_probe_cluster_created_events[i]);
+ }
+
+ auto& parsed_bwe_probe_failure_events = parsed_log.bwe_probe_failure_events();
+ ASSERT_EQ(parsed_bwe_probe_failure_events.size(), probe_failure_list_.size());
+ for (size_t i = 0; i < parsed_bwe_probe_failure_events.size(); i++) {
+ verifier_.VerifyLoggedBweProbeFailureEvent(
+ *probe_failure_list_[i], parsed_bwe_probe_failure_events[i]);
+ }
+
+ auto& parsed_bwe_probe_success_events = parsed_log.bwe_probe_success_events();
+ ASSERT_EQ(parsed_bwe_probe_success_events.size(), probe_success_list_.size());
+ for (size_t i = 0; i < parsed_bwe_probe_success_events.size(); i++) {
+ verifier_.VerifyLoggedBweProbeSuccessEvent(
+ *probe_success_list_[i], parsed_bwe_probe_success_events[i]);
+ }
+
+ auto& parsed_dtls_transport_states = parsed_log.dtls_transport_states();
+ ASSERT_EQ(parsed_dtls_transport_states.size(),
+ dtls_transport_state_list_.size());
+ for (size_t i = 0; i < parsed_dtls_transport_states.size(); i++) {
+ verifier_.VerifyLoggedDtlsTransportState(*dtls_transport_state_list_[i],
+ parsed_dtls_transport_states[i]);
+ }
+
+ auto& parsed_dtls_writable_states = parsed_log.dtls_writable_states();
+ ASSERT_EQ(parsed_dtls_writable_states.size(),
+ dtls_writable_state_list_.size());
+ for (size_t i = 0; i < parsed_dtls_writable_states.size(); i++) {
+ verifier_.VerifyLoggedDtlsWritableState(*dtls_writable_state_list_[i],
+ parsed_dtls_writable_states[i]);
+ }
+
+ const auto& parsed_frame_decoded_map = parsed_log.decoded_frames();
+ ASSERT_EQ(parsed_frame_decoded_map.size(), frame_decoded_event_map_.size());
+ for (const auto& kv : parsed_frame_decoded_map) {
+ uint32_t ssrc = kv.first;
+ const auto& parsed_decoded_frames = kv.second;
+ const auto& decoded_frames = frame_decoded_event_map_[ssrc];
+ ASSERT_EQ(parsed_decoded_frames.size(), decoded_frames.size());
+ for (size_t i = 0; i < decoded_frames.size(); i++) {
+ verifier_.VerifyLoggedFrameDecoded(*decoded_frames[i],
+ parsed_decoded_frames[i]);
+ }
+ }
+
+ auto& parsed_ice_candidate_pair_configs =
+ parsed_log.ice_candidate_pair_configs();
+ ASSERT_EQ(parsed_ice_candidate_pair_configs.size(), ice_config_list_.size());
+ for (size_t i = 0; i < parsed_ice_candidate_pair_configs.size(); i++) {
+ verifier_.VerifyLoggedIceCandidatePairConfig(
+ *ice_config_list_[i], parsed_ice_candidate_pair_configs[i]);
+ }
+
+ auto& parsed_ice_candidate_pair_events =
+ parsed_log.ice_candidate_pair_events();
+ ASSERT_EQ(parsed_ice_candidate_pair_events.size(),
+ parsed_ice_candidate_pair_events.size());
+ for (size_t i = 0; i < parsed_ice_candidate_pair_events.size(); i++) {
+ verifier_.VerifyLoggedIceCandidatePairEvent(
+ *ice_event_list_[i], parsed_ice_candidate_pair_events[i]);
+ }
+
+ auto& parsed_incoming_rtp_packets_by_ssrc =
+ parsed_log.incoming_rtp_packets_by_ssrc();
+ ASSERT_EQ(parsed_incoming_rtp_packets_by_ssrc.size(),
+ incoming_rtp_map_.size());
+ for (const auto& kv : parsed_incoming_rtp_packets_by_ssrc) {
+ uint32_t ssrc = kv.ssrc;
+ const auto& parsed_rtp_stream = kv.incoming_packets;
+ const auto& rtp_stream = incoming_rtp_map_[ssrc];
+ ASSERT_EQ(parsed_rtp_stream.size(), rtp_stream.size());
+ for (size_t i = 0; i < parsed_rtp_stream.size(); i++) {
+ verifier_.VerifyLoggedRtpPacketIncoming(*rtp_stream[i],
+ parsed_rtp_stream[i]);
+ }
+ }
+
+ auto& parsed_outgoing_rtp_packets_by_ssrc =
+ parsed_log.outgoing_rtp_packets_by_ssrc();
+ ASSERT_EQ(parsed_outgoing_rtp_packets_by_ssrc.size(),
+ outgoing_rtp_map_.size());
+ for (const auto& kv : parsed_outgoing_rtp_packets_by_ssrc) {
+ uint32_t ssrc = kv.ssrc;
+ const auto& parsed_rtp_stream = kv.outgoing_packets;
+ const auto& rtp_stream = outgoing_rtp_map_[ssrc];
+ ASSERT_EQ(parsed_rtp_stream.size(), rtp_stream.size());
+ for (size_t i = 0; i < parsed_rtp_stream.size(); i++) {
+ verifier_.VerifyLoggedRtpPacketOutgoing(*rtp_stream[i],
+ parsed_rtp_stream[i]);
+ }
+ }
+
+ auto& parsed_incoming_rtcp_packets = parsed_log.incoming_rtcp_packets();
+ ASSERT_EQ(parsed_incoming_rtcp_packets.size(), incoming_rtcp_list_.size());
+ for (size_t i = 0; i < parsed_incoming_rtcp_packets.size(); i++) {
+ verifier_.VerifyLoggedRtcpPacketIncoming(*incoming_rtcp_list_[i],
+ parsed_incoming_rtcp_packets[i]);
+ }
+
+ auto& parsed_outgoing_rtcp_packets = parsed_log.outgoing_rtcp_packets();
+ ASSERT_EQ(parsed_outgoing_rtcp_packets.size(), outgoing_rtcp_list_.size());
+ for (size_t i = 0; i < parsed_outgoing_rtcp_packets.size(); i++) {
+ verifier_.VerifyLoggedRtcpPacketOutgoing(*outgoing_rtcp_list_[i],
+ parsed_outgoing_rtcp_packets[i]);
+ }
+ auto& parsed_audio_recv_configs = parsed_log.audio_recv_configs();
+ ASSERT_EQ(parsed_audio_recv_configs.size(), audio_recv_config_list_.size());
+ for (size_t i = 0; i < parsed_audio_recv_configs.size(); i++) {
+ verifier_.VerifyLoggedAudioRecvConfig(*audio_recv_config_list_[i],
+ parsed_audio_recv_configs[i]);
+ }
+ auto& parsed_audio_send_configs = parsed_log.audio_send_configs();
+ ASSERT_EQ(parsed_audio_send_configs.size(), audio_send_config_list_.size());
+ for (size_t i = 0; i < parsed_audio_send_configs.size(); i++) {
+ verifier_.VerifyLoggedAudioSendConfig(*audio_send_config_list_[i],
+ parsed_audio_send_configs[i]);
+ }
+ auto& parsed_video_recv_configs = parsed_log.video_recv_configs();
+ ASSERT_EQ(parsed_video_recv_configs.size(), video_recv_config_list_.size());
+ for (size_t i = 0; i < parsed_video_recv_configs.size(); i++) {
+ verifier_.VerifyLoggedVideoRecvConfig(*video_recv_config_list_[i],
+ parsed_video_recv_configs[i]);
+ }
+ auto& parsed_video_send_configs = parsed_log.video_send_configs();
+ ASSERT_EQ(parsed_video_send_configs.size(), video_send_config_list_.size());
+ for (size_t i = 0; i < parsed_video_send_configs.size(); i++) {
+ verifier_.VerifyLoggedVideoSendConfig(*video_send_config_list_[i],
+ 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().ms());
+ EXPECT_EQ(last_timestamp_ms_, parsed_log.last_timestamp().ms());
+
+ EXPECT_EQ(parsed_log.first_log_segment().start_time_ms(),
+ std::min(start_time_us_ / 1000, first_timestamp_ms_));
+ EXPECT_EQ(parsed_log.first_log_segment().stop_time_ms(),
+ stop_time_us_ / 1000);
+}
+
+} // namespace
+
+TEST_P(RtcEventLogSession, StartLoggingFromBeginning) {
+ EventCounts count;
+ count.audio_send_streams = 2;
+ count.audio_recv_streams = 2;
+ count.video_send_streams = 3;
+ count.video_recv_streams = 4;
+ count.alr_states = 4;
+ count.audio_playouts = 100;
+ count.ana_configs = 3;
+ count.bwe_loss_events = 20;
+ count.bwe_delay_events = 20;
+ count.probe_creations = 4;
+ count.probe_successes = 2;
+ count.probe_failures = 2;
+ count.ice_configs = 3;
+ count.ice_events = 10;
+ count.incoming_rtp_packets = 100;
+ count.outgoing_rtp_packets = 100;
+ count.incoming_rtcp_packets = 20;
+ count.outgoing_rtcp_packets = 20;
+ if (IsNewFormat()) {
+ count.dtls_transport_states = 4;
+ count.dtls_writable_states = 2;
+ count.frame_decoded_events = 50;
+ count.generic_packets_sent = 100;
+ count.generic_packets_received = 100;
+ count.generic_acks_received = 20;
+ count.route_changes = 4;
+ }
+
+ WriteLog(count, 0);
+ ReadAndVerifyLog();
+}
+
+TEST_P(RtcEventLogSession, StartLoggingInTheMiddle) {
+ EventCounts count;
+ count.audio_send_streams = 3;
+ count.audio_recv_streams = 4;
+ count.video_send_streams = 5;
+ count.video_recv_streams = 6;
+ count.alr_states = 10;
+ count.audio_playouts = 500;
+ count.ana_configs = 10;
+ count.bwe_loss_events = 50;
+ count.bwe_delay_events = 50;
+ count.probe_creations = 10;
+ count.probe_successes = 5;
+ count.probe_failures = 5;
+ count.ice_configs = 10;
+ count.ice_events = 20;
+ count.incoming_rtp_packets = 500;
+ count.outgoing_rtp_packets = 500;
+ count.incoming_rtcp_packets = 50;
+ count.outgoing_rtcp_packets = 50;
+ if (IsNewFormat()) {
+ count.dtls_transport_states = 4;
+ count.dtls_writable_states = 5;
+ count.frame_decoded_events = 250;
+ count.generic_packets_sent = 500;
+ count.generic_packets_received = 500;
+ count.generic_acks_received = 50;
+ count.route_changes = 10;
+ }
+
+ WriteLog(count, 500);
+ ReadAndVerifyLog();
+}
+
+INSTANTIATE_TEST_SUITE_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()),
+ verifier_(encoding_type_),
+ log_storage_(),
+ log_output_factory_(log_storage_.CreateFactory()) {}
+ const RtcEventLog::EncodingType encoding_type_;
+ const test::EventVerifier verifier_;
+ MemoryLogStorage log_storage_;
+ std::unique_ptr<LogWriterFactoryInterface> log_output_factory_;
+};
+
+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;
+ constexpr int64_t kStartTimeSeconds = 1;
+ constexpr int32_t kStartBitrate = 1000000;
+
+ auto test_info = ::testing::UnitTest::GetInstance()->current_test_info();
+ std::string test_name =
+ std::string(test_info->test_case_name()) + "_" + test_info->name();
+ std::replace(test_name.begin(), test_name.end(), '/', '_');
+ const std::string temp_filename = test::OutputPath() + test_name;
+
+ std::unique_ptr<rtc::ScopedFakeClock> fake_clock =
+ std::make_unique<rtc::ScopedFakeClock>();
+ fake_clock->SetTime(Timestamp::Seconds(kStartTimeSeconds));
+
+ // Create a scope for the TQ and event log factories.
+ // This way, we make sure that task queue instances that may rely on a clock
+ // have been torn down before we run the verification steps at the end of
+ // the test.
+ int64_t start_time_us, utc_start_time_us, stop_time_us;
+
+ {
+ auto task_queue_factory = CreateDefaultTaskQueueFactory();
+ RtcEventLogFactory rtc_event_log_factory(task_queue_factory.get());
+ // When `log` goes out of scope, the contents are flushed
+ // to the output.
+ std::unique_ptr<RtcEventLog> log =
+ rtc_event_log_factory.CreateRtcEventLog(encoding_type_);
+
+ for (size_t i = 0; i < kNumEvents; i++) {
+ // The purpose of the test is to verify that the log can handle
+ // more events than what fits in the internal circular buffer. The exact
+ // type of events does not matter so we chose ProbeSuccess events for
+ // simplicity.
+ // We base the various values on the index. We use this for some basic
+ // consistency checks when we read back.
+ log->Log(std::make_unique<RtcEventProbeResultSuccess>(
+ i, kStartBitrate + i * 1000));
+ fake_clock->AdvanceTime(TimeDelta::Millis(10));
+ }
+ start_time_us = rtc::TimeMicros();
+ utc_start_time_us = rtc::TimeUTCMicros();
+ log->StartLogging(log_output_factory_->Create(temp_filename),
+ RtcEventLog::kImmediateOutput);
+ fake_clock->AdvanceTime(TimeDelta::Millis(10));
+ stop_time_us = rtc::TimeMicros();
+ log->StopLogging();
+ }
+
+ // Read the generated log from memory.
+ ParsedRtcEventLog parsed_log;
+ auto it = log_storage_.logs().find(temp_filename);
+ ASSERT_TRUE(it != log_storage_.logs().end());
+ ASSERT_TRUE(parsed_log.ParseString(it->second).ok());
+
+ const auto& start_log_events = parsed_log.start_log_events();
+ ASSERT_EQ(start_log_events.size(), 1u);
+ verifier_.VerifyLoggedStartEvent(start_time_us, utc_start_time_us,
+ start_log_events[0]);
+
+ const auto& stop_log_events = parsed_log.stop_log_events();
+ ASSERT_EQ(stop_log_events.size(), 1u);
+ verifier_.VerifyLoggedStopEvent(stop_time_us, stop_log_events[0]);
+
+ const auto& probe_success_events = parsed_log.bwe_probe_success_events();
+ // If the following fails, it probably means that kNumEvents isn't larger
+ // than the size of the cyclic buffer in the event log. Try increasing
+ // kNumEvents.
+ EXPECT_LT(probe_success_events.size(), kNumEvents);
+
+ ASSERT_GT(probe_success_events.size(), 1u);
+ int64_t first_timestamp_ms = probe_success_events[0].timestamp.ms();
+ uint32_t first_id = probe_success_events[0].id;
+ int32_t first_bitrate_bps = probe_success_events[0].bitrate_bps;
+ // We want to reset the time to what we used when generating the events, but
+ // the fake clock implementation DCHECKS if time moves backwards. We therefore
+ // recreate the clock. However we must ensure that the old fake_clock is
+ // destroyed before the new one is created, so we have to reset() first.
+ fake_clock.reset();
+ fake_clock = std::make_unique<rtc::ScopedFakeClock>();
+ fake_clock->SetTime(Timestamp::Millis(first_timestamp_ms));
+ for (size_t i = 1; i < probe_success_events.size(); i++) {
+ fake_clock->AdvanceTime(TimeDelta::Millis(10));
+ verifier_.VerifyLoggedBweProbeSuccessEvent(
+ RtcEventProbeResultSuccess(first_id + i, first_bitrate_bps + i * 1000),
+ probe_success_events[i]);
+ }
+}
+
+INSTANTIATE_TEST_SUITE_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.
+
+TEST(DereferencingVectorTest, NonConstVector) {
+ std::vector<int> v{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+ DereferencingVector<int> even;
+ EXPECT_TRUE(even.empty());
+ EXPECT_EQ(even.size(), 0u);
+ EXPECT_EQ(even.begin(), even.end());
+ for (size_t i = 0; i < v.size(); i += 2) {
+ even.push_back(&v[i]);
+ }
+ EXPECT_FALSE(even.empty());
+ EXPECT_EQ(even.size(), 5u);
+ EXPECT_NE(even.begin(), even.end());
+
+ // Test direct access.
+ for (size_t i = 0; i < even.size(); i++) {
+ EXPECT_EQ(even[i], 2 * static_cast<int>(i));
+ }
+
+ // Test iterator.
+ for (int val : even) {
+ EXPECT_EQ(val % 2, 0);
+ }
+
+ // Test modification through iterator.
+ for (int& val : even) {
+ val = val * 2;
+ EXPECT_EQ(val % 2, 0);
+ }
+
+ // Backing vector should have been modified.
+ std::vector<int> expected{0, 1, 4, 3, 8, 5, 12, 7, 16, 9};
+ for (size_t i = 0; i < v.size(); i++) {
+ EXPECT_EQ(v[i], expected[i]);
+ }
+}
+
+TEST(DereferencingVectorTest, ConstVector) {
+ std::vector<int> v{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+ DereferencingVector<const int> odd;
+ EXPECT_TRUE(odd.empty());
+ EXPECT_EQ(odd.size(), 0u);
+ EXPECT_EQ(odd.begin(), odd.end());
+ for (size_t i = 1; i < v.size(); i += 2) {
+ odd.push_back(&v[i]);
+ }
+ EXPECT_FALSE(odd.empty());
+ EXPECT_EQ(odd.size(), 5u);
+ EXPECT_NE(odd.begin(), odd.end());
+
+ // Test direct access.
+ for (size_t i = 0; i < odd.size(); i++) {
+ EXPECT_EQ(odd[i], 2 * static_cast<int>(i) + 1);
+ }
+
+ // Test iterator.
+ for (int val : odd) {
+ EXPECT_EQ(val % 2, 1);
+ }
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/logging/rtc_event_log/rtc_event_log_unittest_helper.cc b/third_party/libwebrtc/logging/rtc_event_log/rtc_event_log_unittest_helper.cc
new file mode 100644
index 0000000000..43b6fc81dc
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/rtc_event_log_unittest_helper.cc
@@ -0,0 +1,1369 @@
+/*
+ * Copyright (c) 2016 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/rtc_event_log_unittest_helper.h"
+
+#include <string.h> // memcmp
+
+#include <cmath>
+#include <cstdint>
+#include <limits>
+#include <memory>
+#include <numeric>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "api/network_state_predictor.h"
+#include "api/rtp_headers.h"
+#include "api/rtp_parameters.h"
+#include "api/units/time_delta.h"
+#include "api/units/timestamp.h"
+#include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor_config.h"
+#include "modules/rtp_rtcp/include/rtp_cvo.h"
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/dlrr.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/rrtr.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/target_bitrate.h"
+#include "modules/rtp_rtcp/source/rtp_header_extensions.h"
+#include "modules/rtp_rtcp/source/rtp_packet_received.h"
+#include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
+#include "rtc_base/buffer.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/time_utils.h"
+#include "system_wrappers/include/ntp_time.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+
+namespace test {
+
+namespace {
+
+struct ExtensionPair {
+ RTPExtensionType type;
+ const char* name;
+};
+
+constexpr int kMaxCsrcs = 3;
+
+// Maximum serialized size of a header extension, including 1 byte ID.
+constexpr int kMaxExtensionSizeBytes = 4;
+constexpr int kMaxNumExtensions = 5;
+
+constexpr ExtensionPair kExtensions[kMaxNumExtensions] = {
+ {RTPExtensionType::kRtpExtensionTransmissionTimeOffset,
+ RtpExtension::kTimestampOffsetUri},
+ {RTPExtensionType::kRtpExtensionAbsoluteSendTime,
+ RtpExtension::kAbsSendTimeUri},
+ {RTPExtensionType::kRtpExtensionTransportSequenceNumber,
+ RtpExtension::kTransportSequenceNumberUri},
+ {RTPExtensionType::kRtpExtensionAudioLevel, RtpExtension::kAudioLevelUri},
+ {RTPExtensionType::kRtpExtensionVideoRotation,
+ RtpExtension::kVideoRotationUri}};
+
+template <typename T>
+void ShuffleInPlace(Random* prng, rtc::ArrayView<T> array) {
+ RTC_DCHECK_LE(array.size(), std::numeric_limits<uint32_t>::max());
+ for (uint32_t i = 0; i + 1 < array.size(); i++) {
+ uint32_t other = prng->Rand(i, static_cast<uint32_t>(array.size() - 1));
+ std::swap(array[i], array[other]);
+ }
+}
+
+absl::optional<int> GetExtensionId(const std::vector<RtpExtension>& extensions,
+ absl::string_view uri) {
+ for (const auto& extension : extensions) {
+ if (extension.uri == uri)
+ return extension.id;
+ }
+ return absl::nullopt;
+}
+
+} // namespace
+
+std::unique_ptr<RtcEventAlrState> EventGenerator::NewAlrState() {
+ return std::make_unique<RtcEventAlrState>(prng_.Rand<bool>());
+}
+
+std::unique_ptr<RtcEventAudioPlayout> EventGenerator::NewAudioPlayout(
+ uint32_t ssrc) {
+ return std::make_unique<RtcEventAudioPlayout>(ssrc);
+}
+
+std::unique_ptr<RtcEventAudioNetworkAdaptation>
+EventGenerator::NewAudioNetworkAdaptation() {
+ std::unique_ptr<AudioEncoderRuntimeConfig> config =
+ std::make_unique<AudioEncoderRuntimeConfig>();
+
+ config->bitrate_bps = prng_.Rand(0, 3000000);
+ config->enable_fec = prng_.Rand<bool>();
+ config->enable_dtx = prng_.Rand<bool>();
+ config->frame_length_ms = prng_.Rand(10, 120);
+ config->num_channels = prng_.Rand(1, 2);
+ config->uplink_packet_loss_fraction = prng_.Rand<float>();
+
+ return std::make_unique<RtcEventAudioNetworkAdaptation>(std::move(config));
+}
+
+std::unique_ptr<RtcEventNetEqSetMinimumDelay>
+EventGenerator::NewNetEqSetMinimumDelay(uint32_t ssrc) {
+ return std::make_unique<RtcEventNetEqSetMinimumDelay>(
+ ssrc, prng_.Rand(std::numeric_limits<int>::max()));
+}
+
+std::unique_ptr<RtcEventBweUpdateDelayBased>
+EventGenerator::NewBweUpdateDelayBased() {
+ constexpr int32_t kMaxBweBps = 20000000;
+ int32_t bitrate_bps = prng_.Rand(0, kMaxBweBps);
+ BandwidthUsage state = static_cast<BandwidthUsage>(
+ prng_.Rand(static_cast<uint32_t>(BandwidthUsage::kLast) - 1));
+ return std::make_unique<RtcEventBweUpdateDelayBased>(bitrate_bps, state);
+}
+
+std::unique_ptr<RtcEventBweUpdateLossBased>
+EventGenerator::NewBweUpdateLossBased() {
+ constexpr int32_t kMaxBweBps = 20000000;
+ constexpr int32_t kMaxPackets = 1000;
+ int32_t bitrate_bps = prng_.Rand(0, kMaxBweBps);
+ uint8_t fraction_lost = prng_.Rand<uint8_t>();
+ int32_t total_packets = prng_.Rand(1, kMaxPackets);
+
+ return std::make_unique<RtcEventBweUpdateLossBased>(
+ bitrate_bps, fraction_lost, total_packets);
+}
+
+std::unique_ptr<RtcEventDtlsTransportState>
+EventGenerator::NewDtlsTransportState() {
+ DtlsTransportState state = static_cast<DtlsTransportState>(
+ prng_.Rand(static_cast<uint32_t>(DtlsTransportState::kNumValues) - 1));
+
+ return std::make_unique<RtcEventDtlsTransportState>(state);
+}
+
+std::unique_ptr<RtcEventDtlsWritableState>
+EventGenerator::NewDtlsWritableState() {
+ bool writable = prng_.Rand<bool>();
+ return std::make_unique<RtcEventDtlsWritableState>(writable);
+}
+
+std::unique_ptr<RtcEventFrameDecoded> EventGenerator::NewFrameDecodedEvent(
+ uint32_t ssrc) {
+ constexpr int kMinRenderDelayMs = 1;
+ constexpr int kMaxRenderDelayMs = 2000000;
+ constexpr int kMaxWidth = 15360;
+ constexpr int kMaxHeight = 8640;
+ constexpr int kMinWidth = 16;
+ constexpr int kMinHeight = 16;
+ constexpr int kNumCodecTypes = 5;
+
+ constexpr VideoCodecType kCodecList[kNumCodecTypes] = {
+ kVideoCodecGeneric, kVideoCodecVP8, kVideoCodecVP9, kVideoCodecAV1,
+ kVideoCodecH264};
+ const int64_t render_time_ms =
+ rtc::TimeMillis() + prng_.Rand(kMinRenderDelayMs, kMaxRenderDelayMs);
+ const int width = prng_.Rand(kMinWidth, kMaxWidth);
+ const int height = prng_.Rand(kMinHeight, kMaxHeight);
+ const VideoCodecType codec = kCodecList[prng_.Rand(0, kNumCodecTypes - 1)];
+ const uint8_t qp = prng_.Rand<uint8_t>();
+ return std::make_unique<RtcEventFrameDecoded>(render_time_ms, ssrc, width,
+ height, codec, qp);
+}
+
+std::unique_ptr<RtcEventProbeClusterCreated>
+EventGenerator::NewProbeClusterCreated() {
+ constexpr int kMaxBweBps = 20000000;
+ constexpr int kMaxNumProbes = 10000;
+ int id = prng_.Rand(1, kMaxNumProbes);
+ int bitrate_bps = prng_.Rand(0, kMaxBweBps);
+ int min_probes = prng_.Rand(5, 50);
+ int min_bytes = prng_.Rand(500, 50000);
+
+ return std::make_unique<RtcEventProbeClusterCreated>(id, bitrate_bps,
+ min_probes, min_bytes);
+}
+
+std::unique_ptr<RtcEventProbeResultFailure>
+EventGenerator::NewProbeResultFailure() {
+ constexpr int kMaxNumProbes = 10000;
+ int id = prng_.Rand(1, kMaxNumProbes);
+ ProbeFailureReason reason = static_cast<ProbeFailureReason>(
+ prng_.Rand(static_cast<uint32_t>(ProbeFailureReason::kLast) - 1));
+
+ return std::make_unique<RtcEventProbeResultFailure>(id, reason);
+}
+
+std::unique_ptr<RtcEventProbeResultSuccess>
+EventGenerator::NewProbeResultSuccess() {
+ constexpr int kMaxBweBps = 20000000;
+ constexpr int kMaxNumProbes = 10000;
+ int id = prng_.Rand(1, kMaxNumProbes);
+ int bitrate_bps = prng_.Rand(0, kMaxBweBps);
+
+ return std::make_unique<RtcEventProbeResultSuccess>(id, bitrate_bps);
+}
+
+std::unique_ptr<RtcEventIceCandidatePairConfig>
+EventGenerator::NewIceCandidatePairConfig() {
+ IceCandidateType local_candidate_type = static_cast<IceCandidateType>(
+ prng_.Rand(static_cast<uint32_t>(IceCandidateType::kNumValues) - 1));
+ IceCandidateNetworkType local_network_type =
+ static_cast<IceCandidateNetworkType>(prng_.Rand(
+ static_cast<uint32_t>(IceCandidateNetworkType::kNumValues) - 1));
+ IceCandidatePairAddressFamily local_address_family =
+ static_cast<IceCandidatePairAddressFamily>(prng_.Rand(
+ static_cast<uint32_t>(IceCandidatePairAddressFamily::kNumValues) -
+ 1));
+ IceCandidateType remote_candidate_type = static_cast<IceCandidateType>(
+ prng_.Rand(static_cast<uint32_t>(IceCandidateType::kNumValues) - 1));
+ IceCandidatePairAddressFamily remote_address_family =
+ static_cast<IceCandidatePairAddressFamily>(prng_.Rand(
+ static_cast<uint32_t>(IceCandidatePairAddressFamily::kNumValues) -
+ 1));
+ IceCandidatePairProtocol protocol_type =
+ static_cast<IceCandidatePairProtocol>(prng_.Rand(
+ static_cast<uint32_t>(IceCandidatePairProtocol::kNumValues) - 1));
+
+ IceCandidatePairDescription desc;
+ desc.local_candidate_type = local_candidate_type;
+ desc.local_relay_protocol = protocol_type;
+ desc.local_network_type = local_network_type;
+ desc.local_address_family = local_address_family;
+ desc.remote_candidate_type = remote_candidate_type;
+ desc.remote_address_family = remote_address_family;
+ desc.candidate_pair_protocol = protocol_type;
+
+ IceCandidatePairConfigType type =
+ static_cast<IceCandidatePairConfigType>(prng_.Rand(
+ static_cast<uint32_t>(IceCandidatePairConfigType::kNumValues) - 1));
+ uint32_t pair_id = prng_.Rand<uint32_t>();
+ return std::make_unique<RtcEventIceCandidatePairConfig>(type, pair_id, desc);
+}
+
+std::unique_ptr<RtcEventIceCandidatePair>
+EventGenerator::NewIceCandidatePair() {
+ IceCandidatePairEventType type =
+ static_cast<IceCandidatePairEventType>(prng_.Rand(
+ static_cast<uint32_t>(IceCandidatePairEventType::kNumValues) - 1));
+ uint32_t pair_id = prng_.Rand<uint32_t>();
+ uint32_t transaction_id = prng_.Rand<uint32_t>();
+
+ return std::make_unique<RtcEventIceCandidatePair>(type, pair_id,
+ transaction_id);
+}
+
+rtcp::ReportBlock EventGenerator::NewReportBlock() {
+ rtcp::ReportBlock report_block;
+ report_block.SetMediaSsrc(prng_.Rand<uint32_t>());
+ report_block.SetFractionLost(prng_.Rand<uint8_t>());
+ // cumulative_lost is a 3-byte signed value.
+ RTC_DCHECK(report_block.SetCumulativeLost(
+ prng_.Rand(-(1 << 23) + 1, (1 << 23) - 1)));
+ report_block.SetExtHighestSeqNum(prng_.Rand<uint32_t>());
+ report_block.SetJitter(prng_.Rand<uint32_t>());
+ report_block.SetLastSr(prng_.Rand<uint32_t>());
+ report_block.SetDelayLastSr(prng_.Rand<uint32_t>());
+ return report_block;
+}
+
+rtcp::SenderReport EventGenerator::NewSenderReport() {
+ rtcp::SenderReport sender_report;
+ sender_report.SetSenderSsrc(prng_.Rand<uint32_t>());
+ sender_report.SetNtp(NtpTime(prng_.Rand<uint32_t>(), prng_.Rand<uint32_t>()));
+ sender_report.SetRtpTimestamp(prng_.Rand<uint32_t>());
+ sender_report.SetPacketCount(prng_.Rand<uint32_t>());
+ sender_report.SetOctetCount(prng_.Rand<uint32_t>());
+ sender_report.AddReportBlock(NewReportBlock());
+ return sender_report;
+}
+
+rtcp::ReceiverReport EventGenerator::NewReceiverReport() {
+ rtcp::ReceiverReport receiver_report;
+ receiver_report.SetSenderSsrc(prng_.Rand<uint32_t>());
+ receiver_report.AddReportBlock(NewReportBlock());
+ return receiver_report;
+}
+
+rtcp::ExtendedReports EventGenerator::NewExtendedReports() {
+ rtcp::ExtendedReports extended_report;
+ extended_report.SetSenderSsrc(prng_.Rand<uint32_t>());
+
+ rtcp::Rrtr rrtr;
+ rrtr.SetNtp(NtpTime(prng_.Rand<uint32_t>(), prng_.Rand<uint32_t>()));
+ extended_report.SetRrtr(rrtr);
+
+ rtcp::ReceiveTimeInfo time_info(
+ prng_.Rand<uint32_t>(), prng_.Rand<uint32_t>(), prng_.Rand<uint32_t>());
+ extended_report.AddDlrrItem(time_info);
+
+ rtcp::TargetBitrate target_bitrate;
+ target_bitrate.AddTargetBitrate(/*spatial layer*/ prng_.Rand(0, 3),
+ /*temporal layer*/ prng_.Rand(0, 3),
+ /*bitrate kbps*/ prng_.Rand(0, 50000));
+ target_bitrate.AddTargetBitrate(/*spatial layer*/ prng_.Rand(4, 7),
+ /*temporal layer*/ prng_.Rand(4, 7),
+ /*bitrate kbps*/ prng_.Rand(0, 50000));
+ extended_report.SetTargetBitrate(target_bitrate);
+ return extended_report;
+}
+
+rtcp::Nack EventGenerator::NewNack() {
+ rtcp::Nack nack;
+ uint16_t base_seq_no = prng_.Rand<uint16_t>();
+ std::vector<uint16_t> nack_list;
+ nack_list.push_back(base_seq_no);
+ for (uint16_t i = 1u; i < 10u; i++) {
+ if (prng_.Rand<bool>())
+ nack_list.push_back(base_seq_no + i);
+ }
+ nack.SetPacketIds(nack_list);
+ return nack;
+}
+
+rtcp::Fir EventGenerator::NewFir() {
+ rtcp::Fir fir;
+ fir.SetSenderSsrc(prng_.Rand<uint32_t>());
+ fir.AddRequestTo(/*ssrc*/ prng_.Rand<uint32_t>(),
+ /*seq num*/ prng_.Rand<uint8_t>());
+ fir.AddRequestTo(/*ssrc*/ prng_.Rand<uint32_t>(),
+ /*seq num*/ prng_.Rand<uint8_t>());
+ return fir;
+}
+
+rtcp::Pli EventGenerator::NewPli() {
+ rtcp::Pli pli;
+ pli.SetSenderSsrc(prng_.Rand<uint32_t>());
+ pli.SetMediaSsrc(prng_.Rand<uint32_t>());
+ return pli;
+}
+
+rtcp::Bye EventGenerator::NewBye() {
+ rtcp::Bye bye;
+ bye.SetSenderSsrc(prng_.Rand<uint32_t>());
+ std::vector<uint32_t> csrcs{prng_.Rand<uint32_t>(), prng_.Rand<uint32_t>()};
+ bye.SetCsrcs(csrcs);
+ if (prng_.Rand(0, 2)) {
+ bye.SetReason("foo");
+ } else {
+ bye.SetReason("bar");
+ }
+ return bye;
+}
+
+rtcp::TransportFeedback EventGenerator::NewTransportFeedback() {
+ rtcp::TransportFeedback transport_feedback;
+ uint16_t base_seq_no = prng_.Rand<uint16_t>();
+ Timestamp base_time = Timestamp::Micros(prng_.Rand<uint32_t>());
+ transport_feedback.SetBase(base_seq_no, base_time);
+ transport_feedback.AddReceivedPacket(base_seq_no, base_time);
+ Timestamp time = base_time;
+ for (uint16_t i = 1u; i < 10u; i++) {
+ time += TimeDelta::Micros(prng_.Rand(0, 100'000));
+ if (prng_.Rand<bool>()) {
+ transport_feedback.AddReceivedPacket(base_seq_no + i, time);
+ }
+ }
+ return transport_feedback;
+}
+
+rtcp::Remb EventGenerator::NewRemb() {
+ rtcp::Remb remb;
+ // The remb bitrate is transported as a 16-bit mantissa and an 8-bit exponent.
+ uint64_t bitrate_bps = prng_.Rand(0, (1 << 16) - 1) << prng_.Rand(7);
+ std::vector<uint32_t> ssrcs{prng_.Rand<uint32_t>(), prng_.Rand<uint32_t>()};
+ remb.SetSsrcs(ssrcs);
+ remb.SetBitrateBps(bitrate_bps);
+ return remb;
+}
+
+rtcp::LossNotification EventGenerator::NewLossNotification() {
+ rtcp::LossNotification loss_notification;
+ const uint16_t last_decoded = prng_.Rand<uint16_t>();
+ const uint16_t last_received =
+ last_decoded + (prng_.Rand<uint16_t>() & 0x7fff);
+ const bool decodability_flag = prng_.Rand<bool>();
+ EXPECT_TRUE(
+ loss_notification.Set(last_decoded, last_received, decodability_flag));
+ return loss_notification;
+}
+
+std::unique_ptr<RtcEventRouteChange> EventGenerator::NewRouteChange() {
+ return std::make_unique<RtcEventRouteChange>(prng_.Rand<bool>(),
+ prng_.Rand(0, 128));
+}
+
+std::unique_ptr<RtcEventRemoteEstimate> EventGenerator::NewRemoteEstimate() {
+ return std::make_unique<RtcEventRemoteEstimate>(
+ DataRate::KilobitsPerSec(prng_.Rand(0, 100000)),
+ DataRate::KilobitsPerSec(prng_.Rand(0, 100000)));
+}
+
+std::unique_ptr<RtcEventRtcpPacketIncoming>
+EventGenerator::NewRtcpPacketIncoming() {
+ enum class SupportedRtcpTypes {
+ kSenderReport = 0,
+ kReceiverReport,
+ kExtendedReports,
+ kFir,
+ kPli,
+ kNack,
+ kRemb,
+ kBye,
+ kTransportFeedback,
+ kNumValues
+ };
+ SupportedRtcpTypes type = static_cast<SupportedRtcpTypes>(
+ prng_.Rand(0, static_cast<int>(SupportedRtcpTypes::kNumValues) - 1));
+ switch (type) {
+ case SupportedRtcpTypes::kSenderReport: {
+ rtcp::SenderReport sender_report = NewSenderReport();
+ rtc::Buffer buffer = sender_report.Build();
+ return std::make_unique<RtcEventRtcpPacketIncoming>(buffer);
+ }
+ case SupportedRtcpTypes::kReceiverReport: {
+ rtcp::ReceiverReport receiver_report = NewReceiverReport();
+ rtc::Buffer buffer = receiver_report.Build();
+ return std::make_unique<RtcEventRtcpPacketIncoming>(buffer);
+ }
+ case SupportedRtcpTypes::kExtendedReports: {
+ rtcp::ExtendedReports extended_report = NewExtendedReports();
+ rtc::Buffer buffer = extended_report.Build();
+ return std::make_unique<RtcEventRtcpPacketIncoming>(buffer);
+ }
+ case SupportedRtcpTypes::kFir: {
+ rtcp::Fir fir = NewFir();
+ rtc::Buffer buffer = fir.Build();
+ return std::make_unique<RtcEventRtcpPacketIncoming>(buffer);
+ }
+ case SupportedRtcpTypes::kPli: {
+ rtcp::Pli pli = NewPli();
+ rtc::Buffer buffer = pli.Build();
+ return std::make_unique<RtcEventRtcpPacketIncoming>(buffer);
+ }
+ case SupportedRtcpTypes::kNack: {
+ rtcp::Nack nack = NewNack();
+ rtc::Buffer buffer = nack.Build();
+ return std::make_unique<RtcEventRtcpPacketIncoming>(buffer);
+ }
+ case SupportedRtcpTypes::kRemb: {
+ rtcp::Remb remb = NewRemb();
+ rtc::Buffer buffer = remb.Build();
+ return std::make_unique<RtcEventRtcpPacketIncoming>(buffer);
+ }
+ case SupportedRtcpTypes::kBye: {
+ rtcp::Bye bye = NewBye();
+ rtc::Buffer buffer = bye.Build();
+ return std::make_unique<RtcEventRtcpPacketIncoming>(buffer);
+ }
+ case SupportedRtcpTypes::kTransportFeedback: {
+ rtcp::TransportFeedback transport_feedback = NewTransportFeedback();
+ rtc::Buffer buffer = transport_feedback.Build();
+ return std::make_unique<RtcEventRtcpPacketIncoming>(buffer);
+ }
+ default:
+ RTC_DCHECK_NOTREACHED();
+ rtc::Buffer buffer;
+ return std::make_unique<RtcEventRtcpPacketIncoming>(buffer);
+ }
+}
+
+std::unique_ptr<RtcEventRtcpPacketOutgoing>
+EventGenerator::NewRtcpPacketOutgoing() {
+ enum class SupportedRtcpTypes {
+ kSenderReport = 0,
+ kReceiverReport,
+ kExtendedReports,
+ kFir,
+ kPli,
+ kNack,
+ kRemb,
+ kBye,
+ kTransportFeedback,
+ kNumValues
+ };
+ SupportedRtcpTypes type = static_cast<SupportedRtcpTypes>(
+ prng_.Rand(0, static_cast<int>(SupportedRtcpTypes::kNumValues) - 1));
+ switch (type) {
+ case SupportedRtcpTypes::kSenderReport: {
+ rtcp::SenderReport sender_report = NewSenderReport();
+ rtc::Buffer buffer = sender_report.Build();
+ return std::make_unique<RtcEventRtcpPacketOutgoing>(buffer);
+ }
+ case SupportedRtcpTypes::kReceiverReport: {
+ rtcp::ReceiverReport receiver_report = NewReceiverReport();
+ rtc::Buffer buffer = receiver_report.Build();
+ return std::make_unique<RtcEventRtcpPacketOutgoing>(buffer);
+ }
+ case SupportedRtcpTypes::kExtendedReports: {
+ rtcp::ExtendedReports extended_report = NewExtendedReports();
+ rtc::Buffer buffer = extended_report.Build();
+ return std::make_unique<RtcEventRtcpPacketOutgoing>(buffer);
+ }
+ case SupportedRtcpTypes::kFir: {
+ rtcp::Fir fir = NewFir();
+ rtc::Buffer buffer = fir.Build();
+ return std::make_unique<RtcEventRtcpPacketOutgoing>(buffer);
+ }
+ case SupportedRtcpTypes::kPli: {
+ rtcp::Pli pli = NewPli();
+ rtc::Buffer buffer = pli.Build();
+ return std::make_unique<RtcEventRtcpPacketOutgoing>(buffer);
+ }
+ case SupportedRtcpTypes::kNack: {
+ rtcp::Nack nack = NewNack();
+ rtc::Buffer buffer = nack.Build();
+ return std::make_unique<RtcEventRtcpPacketOutgoing>(buffer);
+ }
+ case SupportedRtcpTypes::kRemb: {
+ rtcp::Remb remb = NewRemb();
+ rtc::Buffer buffer = remb.Build();
+ return std::make_unique<RtcEventRtcpPacketOutgoing>(buffer);
+ }
+ case SupportedRtcpTypes::kBye: {
+ rtcp::Bye bye = NewBye();
+ rtc::Buffer buffer = bye.Build();
+ return std::make_unique<RtcEventRtcpPacketOutgoing>(buffer);
+ }
+ case SupportedRtcpTypes::kTransportFeedback: {
+ rtcp::TransportFeedback transport_feedback = NewTransportFeedback();
+ rtc::Buffer buffer = transport_feedback.Build();
+ return std::make_unique<RtcEventRtcpPacketOutgoing>(buffer);
+ }
+ default:
+ RTC_DCHECK_NOTREACHED();
+ rtc::Buffer buffer;
+ return std::make_unique<RtcEventRtcpPacketOutgoing>(buffer);
+ }
+}
+
+std::unique_ptr<RtcEventGenericPacketSent>
+EventGenerator::NewGenericPacketSent() {
+ return std::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 std::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,
+ uint32_t ssrc,
+ const RtpHeaderExtensionMap& extension_map,
+ RtpPacket* rtp_packet,
+ bool all_configured_exts) {
+ constexpr int kMaxPayloadType = 127;
+ rtp_packet->SetPayloadType(prng_.Rand(kMaxPayloadType));
+ rtp_packet->SetMarker(prng_.Rand<bool>());
+ rtp_packet->SetSequenceNumber(prng_.Rand<uint16_t>());
+ rtp_packet->SetSsrc(ssrc);
+ rtp_packet->SetTimestamp(prng_.Rand<uint32_t>());
+
+ uint32_t csrcs_count = prng_.Rand(0, kMaxCsrcs);
+ std::vector<uint32_t> csrcs;
+ for (size_t i = 0; i < csrcs_count; i++) {
+ csrcs.push_back(prng_.Rand<uint32_t>());
+ }
+ rtp_packet->SetCsrcs(csrcs);
+
+ if (extension_map.IsRegistered(TransmissionOffset::kId) &&
+ (all_configured_exts || prng_.Rand<bool>())) {
+ rtp_packet->SetExtension<TransmissionOffset>(prng_.Rand(0x00ffffff));
+ }
+
+ if (extension_map.IsRegistered(AudioLevel::kId) &&
+ (all_configured_exts || prng_.Rand<bool>())) {
+ rtp_packet->SetExtension<AudioLevel>(prng_.Rand<bool>(), prng_.Rand(127));
+ }
+
+ if (extension_map.IsRegistered(AbsoluteSendTime::kId) &&
+ (all_configured_exts || prng_.Rand<bool>())) {
+ rtp_packet->SetExtension<AbsoluteSendTime>(prng_.Rand(0x00ffffff));
+ }
+
+ if (extension_map.IsRegistered(VideoOrientation::kId) &&
+ (all_configured_exts || prng_.Rand<bool>())) {
+ rtp_packet->SetExtension<VideoOrientation>(prng_.Rand(3));
+ }
+
+ if (extension_map.IsRegistered(TransportSequenceNumber::kId) &&
+ (all_configured_exts || prng_.Rand<bool>())) {
+ rtp_packet->SetExtension<TransportSequenceNumber>(prng_.Rand<uint16_t>());
+ }
+
+ RTC_CHECK_LE(rtp_packet->headers_size() + payload_size, IP_PACKET_SIZE);
+
+ uint8_t* payload = rtp_packet->AllocatePayload(payload_size);
+ RTC_DCHECK(payload != nullptr);
+ for (size_t i = 0; i < payload_size; i++) {
+ payload[i] = prng_.Rand<uint8_t>();
+ }
+ RTC_CHECK(rtp_packet->SetPadding(padding_size));
+}
+
+std::unique_ptr<RtcEventRtpPacketIncoming> EventGenerator::NewRtpPacketIncoming(
+ uint32_t ssrc,
+ const RtpHeaderExtensionMap& extension_map,
+ bool all_configured_exts) {
+ constexpr size_t kMaxPaddingLength = 224;
+ const bool padding = prng_.Rand(0, 9) == 0; // Let padding be 10% probable.
+ const size_t padding_size = !padding ? 0u : prng_.Rand(0u, kMaxPaddingLength);
+
+ // 12 bytes RTP header, 4 bytes for 0xBEDE + alignment, 4 bytes per CSRC.
+ constexpr size_t kMaxHeaderSize =
+ 16 + 4 * kMaxCsrcs + kMaxExtensionSizeBytes * kMaxNumExtensions;
+
+ // In principle, a packet can contain both padding and other payload.
+ // Currently, RTC eventlog encoder-parser can only maintain padding length if
+ // packet is full padding.
+ // TODO(webrtc:9730): Remove the deterministic logic for padding_size > 0.
+ size_t payload_size =
+ padding_size > 0 ? 0
+ : prng_.Rand(0u, static_cast<uint32_t>(IP_PACKET_SIZE -
+ 1 - padding_size -
+ kMaxHeaderSize));
+
+ RtpPacketReceived rtp_packet(&extension_map);
+ RandomizeRtpPacket(payload_size, padding_size, ssrc, extension_map,
+ &rtp_packet, all_configured_exts);
+
+ return std::make_unique<RtcEventRtpPacketIncoming>(rtp_packet);
+}
+
+std::unique_ptr<RtcEventRtpPacketOutgoing> EventGenerator::NewRtpPacketOutgoing(
+ uint32_t ssrc,
+ const RtpHeaderExtensionMap& extension_map,
+ bool all_configured_exts) {
+ constexpr size_t kMaxPaddingLength = 224;
+ const bool padding = prng_.Rand(0, 9) == 0; // Let padding be 10% probable.
+ const size_t padding_size = !padding ? 0u : prng_.Rand(0u, kMaxPaddingLength);
+
+ // 12 bytes RTP header, 4 bytes for 0xBEDE + alignment, 4 bytes per CSRC.
+ constexpr size_t kMaxHeaderSize =
+ 16 + 4 * kMaxCsrcs + kMaxExtensionSizeBytes * kMaxNumExtensions;
+
+ // In principle,a packet can contain both padding and other payload.
+ // Currently, RTC eventlog encoder-parser can only maintain padding length if
+ // packet is full padding.
+ // TODO(webrtc:9730): Remove the deterministic logic for padding_size > 0.
+ size_t payload_size =
+ padding_size > 0 ? 0
+ : prng_.Rand(0u, static_cast<uint32_t>(IP_PACKET_SIZE -
+ 1 - padding_size -
+ kMaxHeaderSize));
+
+ RtpPacketToSend rtp_packet(&extension_map,
+ kMaxHeaderSize + payload_size + padding_size);
+ RandomizeRtpPacket(payload_size, padding_size, ssrc, extension_map,
+ &rtp_packet, all_configured_exts);
+
+ int probe_cluster_id = prng_.Rand(0, 100000);
+ return std::make_unique<RtcEventRtpPacketOutgoing>(rtp_packet,
+ probe_cluster_id);
+}
+
+RtpHeaderExtensionMap EventGenerator::NewRtpHeaderExtensionMap(
+ bool configure_all) {
+ RtpHeaderExtensionMap extension_map;
+ std::vector<int> id(RtpExtension::kOneByteHeaderExtensionMaxId -
+ RtpExtension::kMinId + 1);
+ std::iota(id.begin(), id.end(), RtpExtension::kMinId);
+ ShuffleInPlace(&prng_, rtc::ArrayView<int>(id));
+
+ if (configure_all || prng_.Rand<bool>()) {
+ extension_map.Register<AudioLevel>(id[0]);
+ }
+ if (configure_all || prng_.Rand<bool>()) {
+ extension_map.Register<TransmissionOffset>(id[1]);
+ }
+ if (configure_all || prng_.Rand<bool>()) {
+ extension_map.Register<AbsoluteSendTime>(id[2]);
+ }
+ if (configure_all || prng_.Rand<bool>()) {
+ extension_map.Register<VideoOrientation>(id[3]);
+ }
+ if (configure_all || prng_.Rand<bool>()) {
+ extension_map.Register<TransportSequenceNumber>(id[4]);
+ }
+
+ return extension_map;
+}
+
+std::unique_ptr<RtcEventAudioReceiveStreamConfig>
+EventGenerator::NewAudioReceiveStreamConfig(
+ uint32_t ssrc,
+ const RtpHeaderExtensionMap& extensions) {
+ auto config = std::make_unique<rtclog::StreamConfig>();
+ // Add SSRCs for the stream.
+ config->remote_ssrc = ssrc;
+ config->local_ssrc = prng_.Rand<uint32_t>();
+ // Add header extensions.
+ for (size_t i = 0; i < kMaxNumExtensions; i++) {
+ uint8_t id = extensions.GetId(kExtensions[i].type);
+ if (id != RtpHeaderExtensionMap::kInvalidId) {
+ config->rtp_extensions.emplace_back(kExtensions[i].name, id);
+ }
+ }
+
+ return std::make_unique<RtcEventAudioReceiveStreamConfig>(std::move(config));
+}
+
+std::unique_ptr<RtcEventAudioSendStreamConfig>
+EventGenerator::NewAudioSendStreamConfig(
+ uint32_t ssrc,
+ const RtpHeaderExtensionMap& extensions) {
+ auto config = std::make_unique<rtclog::StreamConfig>();
+ // Add SSRC to the stream.
+ config->local_ssrc = ssrc;
+ // Add header extensions.
+ for (size_t i = 0; i < kMaxNumExtensions; i++) {
+ uint8_t id = extensions.GetId(kExtensions[i].type);
+ if (id != RtpHeaderExtensionMap::kInvalidId) {
+ config->rtp_extensions.emplace_back(kExtensions[i].name, id);
+ }
+ }
+ return std::make_unique<RtcEventAudioSendStreamConfig>(std::move(config));
+}
+
+std::unique_ptr<RtcEventVideoReceiveStreamConfig>
+EventGenerator::NewVideoReceiveStreamConfig(
+ uint32_t ssrc,
+ const RtpHeaderExtensionMap& extensions) {
+ auto config = std::make_unique<rtclog::StreamConfig>();
+
+ // Add SSRCs for the stream.
+ config->remote_ssrc = ssrc;
+ config->local_ssrc = prng_.Rand<uint32_t>();
+ // Add extensions and settings for RTCP.
+ config->rtcp_mode =
+ prng_.Rand<bool>() ? RtcpMode::kCompound : RtcpMode::kReducedSize;
+ config->remb = prng_.Rand<bool>();
+ config->rtx_ssrc = prng_.Rand<uint32_t>();
+ config->codecs.emplace_back(prng_.Rand<bool>() ? "VP8" : "H264",
+ prng_.Rand(127), prng_.Rand(127));
+ // Add header extensions.
+ for (size_t i = 0; i < kMaxNumExtensions; i++) {
+ uint8_t id = extensions.GetId(kExtensions[i].type);
+ if (id != RtpHeaderExtensionMap::kInvalidId) {
+ config->rtp_extensions.emplace_back(kExtensions[i].name, id);
+ }
+ }
+ return std::make_unique<RtcEventVideoReceiveStreamConfig>(std::move(config));
+}
+
+std::unique_ptr<RtcEventVideoSendStreamConfig>
+EventGenerator::NewVideoSendStreamConfig(
+ uint32_t ssrc,
+ const RtpHeaderExtensionMap& extensions) {
+ auto config = std::make_unique<rtclog::StreamConfig>();
+
+ config->codecs.emplace_back(prng_.Rand<bool>() ? "VP8" : "H264",
+ prng_.Rand(127), prng_.Rand(127));
+ config->local_ssrc = ssrc;
+ config->rtx_ssrc = prng_.Rand<uint32_t>();
+ // Add header extensions.
+ for (size_t i = 0; i < kMaxNumExtensions; i++) {
+ uint8_t id = extensions.GetId(kExtensions[i].type);
+ if (id != RtpHeaderExtensionMap::kInvalidId) {
+ config->rtp_extensions.emplace_back(kExtensions[i].name, id);
+ }
+ }
+ return std::make_unique<RtcEventVideoSendStreamConfig>(std::move(config));
+}
+
+void EventVerifier::VerifyLoggedAlrStateEvent(
+ const RtcEventAlrState& original_event,
+ const LoggedAlrStateEvent& logged_event) const {
+ EXPECT_EQ(original_event.timestamp_ms(), logged_event.log_time_ms());
+ EXPECT_EQ(original_event.in_alr(), logged_event.in_alr);
+}
+
+void EventVerifier::VerifyLoggedAudioPlayoutEvent(
+ const RtcEventAudioPlayout& original_event,
+ const LoggedAudioPlayoutEvent& logged_event) const {
+ EXPECT_EQ(original_event.timestamp_ms(), logged_event.log_time_ms());
+ EXPECT_EQ(original_event.ssrc(), logged_event.ssrc);
+}
+
+void EventVerifier::VerifyLoggedAudioNetworkAdaptationEvent(
+ const RtcEventAudioNetworkAdaptation& original_event,
+ const LoggedAudioNetworkAdaptationEvent& logged_event) const {
+ EXPECT_EQ(original_event.timestamp_ms(), logged_event.log_time_ms());
+
+ EXPECT_EQ(original_event.config().bitrate_bps,
+ logged_event.config.bitrate_bps);
+ EXPECT_EQ(original_event.config().enable_dtx, logged_event.config.enable_dtx);
+ EXPECT_EQ(original_event.config().enable_fec, logged_event.config.enable_fec);
+ EXPECT_EQ(original_event.config().frame_length_ms,
+ logged_event.config.frame_length_ms);
+ EXPECT_EQ(original_event.config().num_channels,
+ logged_event.config.num_channels);
+
+ // uplink_packet_loss_fraction
+ ASSERT_EQ(original_event.config().uplink_packet_loss_fraction.has_value(),
+ logged_event.config.uplink_packet_loss_fraction.has_value());
+ if (original_event.config().uplink_packet_loss_fraction.has_value()) {
+ const float original =
+ original_event.config().uplink_packet_loss_fraction.value();
+ const float logged =
+ logged_event.config.uplink_packet_loss_fraction.value();
+ const float uplink_packet_loss_fraction_delta = std::abs(original - logged);
+ EXPECT_LE(uplink_packet_loss_fraction_delta, 0.0001f);
+ }
+}
+
+void EventVerifier::VerifyLoggedBweDelayBasedUpdate(
+ const RtcEventBweUpdateDelayBased& original_event,
+ const LoggedBweDelayBasedUpdate& logged_event) const {
+ EXPECT_EQ(original_event.timestamp_ms(), logged_event.log_time_ms());
+ EXPECT_EQ(original_event.bitrate_bps(), logged_event.bitrate_bps);
+ EXPECT_EQ(original_event.detector_state(), logged_event.detector_state);
+}
+
+void EventVerifier::VerifyLoggedBweLossBasedUpdate(
+ const RtcEventBweUpdateLossBased& original_event,
+ const LoggedBweLossBasedUpdate& logged_event) const {
+ EXPECT_EQ(original_event.timestamp_ms(), logged_event.log_time_ms());
+ EXPECT_EQ(original_event.bitrate_bps(), logged_event.bitrate_bps);
+ EXPECT_EQ(original_event.fraction_loss(), logged_event.fraction_lost);
+ EXPECT_EQ(original_event.total_packets(), logged_event.expected_packets);
+}
+
+void EventVerifier::VerifyLoggedBweProbeClusterCreatedEvent(
+ const RtcEventProbeClusterCreated& original_event,
+ const LoggedBweProbeClusterCreatedEvent& logged_event) const {
+ EXPECT_EQ(original_event.timestamp_ms(), logged_event.log_time_ms());
+ EXPECT_EQ(original_event.id(), logged_event.id);
+ EXPECT_EQ(original_event.bitrate_bps(), logged_event.bitrate_bps);
+ EXPECT_EQ(original_event.min_probes(), logged_event.min_packets);
+ EXPECT_EQ(original_event.min_bytes(), logged_event.min_bytes);
+}
+
+void EventVerifier::VerifyLoggedBweProbeFailureEvent(
+ const RtcEventProbeResultFailure& original_event,
+ const LoggedBweProbeFailureEvent& logged_event) const {
+ EXPECT_EQ(original_event.timestamp_ms(), logged_event.log_time_ms());
+ EXPECT_EQ(original_event.id(), logged_event.id);
+ EXPECT_EQ(original_event.failure_reason(), logged_event.failure_reason);
+}
+
+void EventVerifier::VerifyLoggedBweProbeSuccessEvent(
+ const RtcEventProbeResultSuccess& original_event,
+ const LoggedBweProbeSuccessEvent& logged_event) const {
+ EXPECT_EQ(original_event.timestamp_ms(), logged_event.log_time_ms());
+ EXPECT_EQ(original_event.id(), logged_event.id);
+ EXPECT_EQ(original_event.bitrate_bps(), logged_event.bitrate_bps);
+}
+
+void EventVerifier::VerifyLoggedDtlsTransportState(
+ const RtcEventDtlsTransportState& original_event,
+ const LoggedDtlsTransportState& logged_event) const {
+ EXPECT_EQ(original_event.timestamp_ms(), logged_event.log_time_ms());
+ EXPECT_EQ(original_event.dtls_transport_state(),
+ logged_event.dtls_transport_state);
+}
+
+void EventVerifier::VerifyLoggedDtlsWritableState(
+ const RtcEventDtlsWritableState& original_event,
+ const LoggedDtlsWritableState& logged_event) const {
+ EXPECT_EQ(original_event.timestamp_ms(), logged_event.log_time_ms());
+ EXPECT_EQ(original_event.writable(), logged_event.writable);
+}
+
+void EventVerifier::VerifyLoggedFrameDecoded(
+ const RtcEventFrameDecoded& original_event,
+ const LoggedFrameDecoded& logged_event) const {
+ EXPECT_EQ(original_event.timestamp_ms(), logged_event.log_time_ms());
+ EXPECT_EQ(original_event.ssrc(), logged_event.ssrc);
+ EXPECT_EQ(original_event.render_time_ms(), logged_event.render_time_ms);
+ EXPECT_EQ(original_event.width(), logged_event.width);
+ EXPECT_EQ(original_event.height(), logged_event.height);
+ EXPECT_EQ(original_event.codec(), logged_event.codec);
+ EXPECT_EQ(original_event.qp(), logged_event.qp);
+}
+
+void EventVerifier::VerifyLoggedIceCandidatePairConfig(
+ const RtcEventIceCandidatePairConfig& original_event,
+ const LoggedIceCandidatePairConfig& logged_event) const {
+ EXPECT_EQ(original_event.timestamp_ms(), logged_event.log_time_ms());
+
+ EXPECT_EQ(original_event.type(), logged_event.type);
+ EXPECT_EQ(original_event.candidate_pair_id(), logged_event.candidate_pair_id);
+ EXPECT_EQ(original_event.candidate_pair_desc().local_candidate_type,
+ logged_event.local_candidate_type);
+ EXPECT_EQ(original_event.candidate_pair_desc().local_relay_protocol,
+ logged_event.local_relay_protocol);
+ EXPECT_EQ(original_event.candidate_pair_desc().local_network_type,
+ logged_event.local_network_type);
+ EXPECT_EQ(original_event.candidate_pair_desc().local_address_family,
+ logged_event.local_address_family);
+ EXPECT_EQ(original_event.candidate_pair_desc().remote_candidate_type,
+ logged_event.remote_candidate_type);
+ EXPECT_EQ(original_event.candidate_pair_desc().remote_address_family,
+ logged_event.remote_address_family);
+ EXPECT_EQ(original_event.candidate_pair_desc().candidate_pair_protocol,
+ logged_event.candidate_pair_protocol);
+}
+
+void EventVerifier::VerifyLoggedIceCandidatePairEvent(
+ const RtcEventIceCandidatePair& original_event,
+ const LoggedIceCandidatePairEvent& logged_event) const {
+ EXPECT_EQ(original_event.timestamp_ms(), logged_event.log_time_ms());
+
+ EXPECT_EQ(original_event.type(), logged_event.type);
+ EXPECT_EQ(original_event.candidate_pair_id(), logged_event.candidate_pair_id);
+ if (encoding_type_ == RtcEventLog::EncodingType::NewFormat) {
+ EXPECT_EQ(original_event.transaction_id(), logged_event.transaction_id);
+ }
+}
+
+template <typename Event>
+void VerifyLoggedRtpHeader(const Event& original_header,
+ const RTPHeader& logged_header) {
+ // Standard RTP header.
+ EXPECT_EQ(original_header.Marker(), logged_header.markerBit);
+ EXPECT_EQ(original_header.PayloadType(), logged_header.payloadType);
+ EXPECT_EQ(original_header.SequenceNumber(), logged_header.sequenceNumber);
+ EXPECT_EQ(original_header.Timestamp(), logged_header.timestamp);
+ EXPECT_EQ(original_header.Ssrc(), logged_header.ssrc);
+
+ EXPECT_EQ(original_header.header_length(), logged_header.headerLength);
+
+ // TransmissionOffset header extension.
+ ASSERT_EQ(original_header.template HasExtension<TransmissionOffset>(),
+ logged_header.extension.hasTransmissionTimeOffset);
+ if (logged_header.extension.hasTransmissionTimeOffset) {
+ int32_t offset;
+ ASSERT_TRUE(
+ original_header.template GetExtension<TransmissionOffset>(&offset));
+ EXPECT_EQ(offset, logged_header.extension.transmissionTimeOffset);
+ }
+
+ // AbsoluteSendTime header extension.
+ ASSERT_EQ(original_header.template HasExtension<AbsoluteSendTime>(),
+ logged_header.extension.hasAbsoluteSendTime);
+ if (logged_header.extension.hasAbsoluteSendTime) {
+ uint32_t sendtime;
+ ASSERT_TRUE(
+ original_header.template GetExtension<AbsoluteSendTime>(&sendtime));
+ EXPECT_EQ(sendtime, logged_header.extension.absoluteSendTime);
+ }
+
+ // TransportSequenceNumber header extension.
+ ASSERT_EQ(original_header.template HasExtension<TransportSequenceNumber>(),
+ logged_header.extension.hasTransportSequenceNumber);
+ if (logged_header.extension.hasTransportSequenceNumber) {
+ uint16_t seqnum;
+ ASSERT_TRUE(original_header.template GetExtension<TransportSequenceNumber>(
+ &seqnum));
+ EXPECT_EQ(seqnum, logged_header.extension.transportSequenceNumber);
+ }
+
+ // AudioLevel header extension.
+ ASSERT_EQ(original_header.template HasExtension<AudioLevel>(),
+ logged_header.extension.hasAudioLevel);
+ if (logged_header.extension.hasAudioLevel) {
+ bool voice_activity;
+ uint8_t audio_level;
+ ASSERT_TRUE(original_header.template GetExtension<AudioLevel>(
+ &voice_activity, &audio_level));
+ EXPECT_EQ(voice_activity, logged_header.extension.voiceActivity);
+ EXPECT_EQ(audio_level, logged_header.extension.audioLevel);
+ }
+
+ // VideoOrientation header extension.
+ ASSERT_EQ(original_header.template HasExtension<VideoOrientation>(),
+ logged_header.extension.hasVideoRotation);
+ if (logged_header.extension.hasVideoRotation) {
+ uint8_t rotation;
+ ASSERT_TRUE(
+ original_header.template GetExtension<VideoOrientation>(&rotation));
+ EXPECT_EQ(ConvertCVOByteToVideoRotation(rotation),
+ logged_header.extension.videoRotation);
+ }
+}
+
+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::VerifyLoggedRemoteEstimateEvent(
+ const RtcEventRemoteEstimate& original_event,
+ const LoggedRemoteEstimateEvent& logged_event) const {
+ EXPECT_EQ(original_event.timestamp_ms(), logged_event.log_time_ms());
+ EXPECT_EQ(original_event.link_capacity_lower_,
+ logged_event.link_capacity_lower);
+ EXPECT_EQ(original_event.link_capacity_upper_,
+ logged_event.link_capacity_upper);
+}
+
+void EventVerifier::VerifyLoggedRtpPacketIncoming(
+ const RtcEventRtpPacketIncoming& original_event,
+ const LoggedRtpPacketIncoming& logged_event) const {
+ EXPECT_EQ(original_event.timestamp_ms(), logged_event.log_time_ms());
+
+ EXPECT_EQ(original_event.header_length(), logged_event.rtp.header_length);
+
+ EXPECT_EQ(original_event.packet_length(), logged_event.rtp.total_length);
+
+ // Currently, RTC eventlog encoder-parser can only maintain padding length
+ // if packet is full padding.
+ EXPECT_EQ(original_event.padding_length(),
+ logged_event.rtp.header.paddingLength);
+
+ VerifyLoggedRtpHeader(original_event, logged_event.rtp.header);
+}
+
+void EventVerifier::VerifyLoggedRtpPacketOutgoing(
+ const RtcEventRtpPacketOutgoing& original_event,
+ const LoggedRtpPacketOutgoing& logged_event) const {
+ EXPECT_EQ(original_event.timestamp_ms(), logged_event.log_time_ms());
+
+ EXPECT_EQ(original_event.header_length(), logged_event.rtp.header_length);
+
+ EXPECT_EQ(original_event.packet_length(), logged_event.rtp.total_length);
+
+ // Currently, RTC eventlog encoder-parser can only maintain padding length
+ // if packet is full padding.
+ EXPECT_EQ(original_event.padding_length(),
+ logged_event.rtp.header.paddingLength);
+
+ // TODO(terelius): Probe cluster ID isn't parsed, used or tested. Unless
+ // someone has a strong reason to keep it, it'll be removed.
+
+ VerifyLoggedRtpHeader(original_event, 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 {
+ EXPECT_EQ(original_event.timestamp_ms(), logged_event.log_time_ms());
+
+ ASSERT_EQ(original_event.packet().size(), logged_event.rtcp.raw_data.size());
+ EXPECT_EQ(
+ memcmp(original_event.packet().data(), logged_event.rtcp.raw_data.data(),
+ original_event.packet().size()),
+ 0);
+}
+
+void EventVerifier::VerifyLoggedRtcpPacketOutgoing(
+ const RtcEventRtcpPacketOutgoing& original_event,
+ const LoggedRtcpPacketOutgoing& logged_event) const {
+ EXPECT_EQ(original_event.timestamp_ms(), logged_event.log_time_ms());
+
+ ASSERT_EQ(original_event.packet().size(), logged_event.rtcp.raw_data.size());
+ EXPECT_EQ(
+ memcmp(original_event.packet().data(), logged_event.rtcp.raw_data.data(),
+ original_event.packet().size()),
+ 0);
+}
+
+void EventVerifier::VerifyReportBlock(
+ const rtcp::ReportBlock& original_report_block,
+ const rtcp::ReportBlock& logged_report_block) {
+ EXPECT_EQ(original_report_block.source_ssrc(),
+ logged_report_block.source_ssrc());
+ EXPECT_EQ(original_report_block.fraction_lost(),
+ logged_report_block.fraction_lost());
+ EXPECT_EQ(original_report_block.cumulative_lost_signed(),
+ logged_report_block.cumulative_lost_signed());
+ EXPECT_EQ(original_report_block.extended_high_seq_num(),
+ logged_report_block.extended_high_seq_num());
+ EXPECT_EQ(original_report_block.jitter(), logged_report_block.jitter());
+ EXPECT_EQ(original_report_block.last_sr(), logged_report_block.last_sr());
+ EXPECT_EQ(original_report_block.delay_since_last_sr(),
+ logged_report_block.delay_since_last_sr());
+}
+
+void EventVerifier::VerifyLoggedSenderReport(
+ int64_t log_time_ms,
+ const rtcp::SenderReport& original_sr,
+ const LoggedRtcpPacketSenderReport& logged_sr) {
+ EXPECT_EQ(log_time_ms, logged_sr.log_time_ms());
+ EXPECT_EQ(original_sr.sender_ssrc(), logged_sr.sr.sender_ssrc());
+ EXPECT_EQ(original_sr.ntp(), logged_sr.sr.ntp());
+ EXPECT_EQ(original_sr.rtp_timestamp(), logged_sr.sr.rtp_timestamp());
+ EXPECT_EQ(original_sr.sender_packet_count(),
+ logged_sr.sr.sender_packet_count());
+ EXPECT_EQ(original_sr.sender_octet_count(),
+ logged_sr.sr.sender_octet_count());
+ ASSERT_EQ(original_sr.report_blocks().size(),
+ logged_sr.sr.report_blocks().size());
+ for (size_t i = 0; i < original_sr.report_blocks().size(); i++) {
+ VerifyReportBlock(original_sr.report_blocks()[i],
+ logged_sr.sr.report_blocks()[i]);
+ }
+}
+
+void EventVerifier::VerifyLoggedReceiverReport(
+ int64_t log_time_ms,
+ const rtcp::ReceiverReport& original_rr,
+ const LoggedRtcpPacketReceiverReport& logged_rr) {
+ EXPECT_EQ(log_time_ms, logged_rr.log_time_ms());
+ EXPECT_EQ(original_rr.sender_ssrc(), logged_rr.rr.sender_ssrc());
+ ASSERT_EQ(original_rr.report_blocks().size(),
+ logged_rr.rr.report_blocks().size());
+ for (size_t i = 0; i < original_rr.report_blocks().size(); i++) {
+ VerifyReportBlock(original_rr.report_blocks()[i],
+ logged_rr.rr.report_blocks()[i]);
+ }
+}
+
+void EventVerifier::VerifyLoggedExtendedReports(
+ int64_t log_time_ms,
+ const rtcp::ExtendedReports& original_xr,
+ const LoggedRtcpPacketExtendedReports& logged_xr) {
+ EXPECT_EQ(log_time_ms, logged_xr.log_time_ms());
+ EXPECT_EQ(original_xr.sender_ssrc(), logged_xr.xr.sender_ssrc());
+
+ EXPECT_EQ(original_xr.rrtr().has_value(), logged_xr.xr.rrtr().has_value());
+ if (original_xr.rrtr().has_value() && logged_xr.xr.rrtr().has_value()) {
+ EXPECT_EQ(original_xr.rrtr()->ntp(), logged_xr.xr.rrtr()->ntp());
+ }
+
+ const auto& original_subblocks = original_xr.dlrr().sub_blocks();
+ const auto& logged_subblocks = logged_xr.xr.dlrr().sub_blocks();
+ ASSERT_EQ(original_subblocks.size(), logged_subblocks.size());
+ for (size_t i = 0; i < original_subblocks.size(); i++) {
+ EXPECT_EQ(original_subblocks[i].ssrc, logged_subblocks[i].ssrc);
+ EXPECT_EQ(original_subblocks[i].last_rr, logged_subblocks[i].last_rr);
+ EXPECT_EQ(original_subblocks[i].delay_since_last_rr,
+ logged_subblocks[i].delay_since_last_rr);
+ }
+
+ EXPECT_EQ(original_xr.target_bitrate().has_value(),
+ logged_xr.xr.target_bitrate().has_value());
+ if (original_xr.target_bitrate().has_value() &&
+ logged_xr.xr.target_bitrate().has_value()) {
+ const auto& original_bitrates =
+ original_xr.target_bitrate()->GetTargetBitrates();
+ const auto& logged_bitrates =
+ logged_xr.xr.target_bitrate()->GetTargetBitrates();
+ ASSERT_EQ(original_bitrates.size(), logged_bitrates.size());
+ for (size_t i = 0; i < original_bitrates.size(); i++) {
+ EXPECT_EQ(original_bitrates[i].spatial_layer,
+ logged_bitrates[i].spatial_layer);
+ EXPECT_EQ(original_bitrates[i].temporal_layer,
+ logged_bitrates[i].temporal_layer);
+ EXPECT_EQ(original_bitrates[i].target_bitrate_kbps,
+ logged_bitrates[i].target_bitrate_kbps);
+ }
+ }
+}
+
+void EventVerifier::VerifyLoggedFir(int64_t log_time_ms,
+ const rtcp::Fir& original_fir,
+ const LoggedRtcpPacketFir& logged_fir) {
+ EXPECT_EQ(log_time_ms, logged_fir.log_time_ms());
+ EXPECT_EQ(original_fir.sender_ssrc(), logged_fir.fir.sender_ssrc());
+ const auto& original_requests = original_fir.requests();
+ const auto& logged_requests = logged_fir.fir.requests();
+ ASSERT_EQ(original_requests.size(), logged_requests.size());
+ for (size_t i = 0; i < original_requests.size(); i++) {
+ EXPECT_EQ(original_requests[i].ssrc, logged_requests[i].ssrc);
+ EXPECT_EQ(original_requests[i].seq_nr, logged_requests[i].seq_nr);
+ }
+}
+
+void EventVerifier::VerifyLoggedPli(int64_t log_time_ms,
+ const rtcp::Pli& original_pli,
+ const LoggedRtcpPacketPli& logged_pli) {
+ EXPECT_EQ(log_time_ms, logged_pli.log_time_ms());
+ EXPECT_EQ(original_pli.sender_ssrc(), logged_pli.pli.sender_ssrc());
+ EXPECT_EQ(original_pli.media_ssrc(), logged_pli.pli.media_ssrc());
+}
+
+void EventVerifier::VerifyLoggedBye(int64_t log_time_ms,
+ const rtcp::Bye& original_bye,
+ const LoggedRtcpPacketBye& logged_bye) {
+ EXPECT_EQ(log_time_ms, logged_bye.log_time_ms());
+ EXPECT_EQ(original_bye.sender_ssrc(), logged_bye.bye.sender_ssrc());
+ EXPECT_EQ(original_bye.csrcs(), logged_bye.bye.csrcs());
+ EXPECT_EQ(original_bye.reason(), logged_bye.bye.reason());
+}
+
+void EventVerifier::VerifyLoggedNack(int64_t log_time_ms,
+ const rtcp::Nack& original_nack,
+ const LoggedRtcpPacketNack& logged_nack) {
+ EXPECT_EQ(log_time_ms, logged_nack.log_time_ms());
+ EXPECT_EQ(original_nack.packet_ids(), logged_nack.nack.packet_ids());
+}
+
+void EventVerifier::VerifyLoggedTransportFeedback(
+ int64_t log_time_ms,
+ const rtcp::TransportFeedback& original_transport_feedback,
+ const LoggedRtcpPacketTransportFeedback& logged_transport_feedback) {
+ EXPECT_EQ(log_time_ms, logged_transport_feedback.log_time_ms());
+ ASSERT_EQ(
+ original_transport_feedback.GetReceivedPackets().size(),
+ logged_transport_feedback.transport_feedback.GetReceivedPackets().size());
+ for (size_t i = 0;
+ i < original_transport_feedback.GetReceivedPackets().size(); i++) {
+ EXPECT_EQ(
+ original_transport_feedback.GetReceivedPackets()[i].sequence_number(),
+ logged_transport_feedback.transport_feedback.GetReceivedPackets()[i]
+ .sequence_number());
+ EXPECT_EQ(
+ original_transport_feedback.GetReceivedPackets()[i].delta(),
+ logged_transport_feedback.transport_feedback.GetReceivedPackets()[i]
+ .delta());
+ }
+}
+
+void EventVerifier::VerifyLoggedRemb(int64_t log_time_ms,
+ const rtcp::Remb& original_remb,
+ const LoggedRtcpPacketRemb& logged_remb) {
+ EXPECT_EQ(log_time_ms, logged_remb.log_time_ms());
+ EXPECT_EQ(original_remb.ssrcs(), logged_remb.remb.ssrcs());
+ EXPECT_EQ(original_remb.bitrate_bps(), logged_remb.remb.bitrate_bps());
+}
+
+void EventVerifier::VerifyLoggedLossNotification(
+ int64_t log_time_ms,
+ const rtcp::LossNotification& original_loss_notification,
+ const LoggedRtcpPacketLossNotification& logged_loss_notification) {
+ EXPECT_EQ(log_time_ms, logged_loss_notification.log_time_ms());
+ EXPECT_EQ(original_loss_notification.last_decoded(),
+ logged_loss_notification.loss_notification.last_decoded());
+ EXPECT_EQ(original_loss_notification.last_received(),
+ logged_loss_notification.loss_notification.last_received());
+ EXPECT_EQ(original_loss_notification.decodability_flag(),
+ logged_loss_notification.loss_notification.decodability_flag());
+}
+
+void EventVerifier::VerifyLoggedStartEvent(
+ int64_t start_time_us,
+ int64_t utc_start_time_us,
+ const LoggedStartEvent& logged_event) const {
+ EXPECT_EQ(start_time_us / 1000, logged_event.log_time_ms());
+ if (encoding_type_ == RtcEventLog::EncodingType::NewFormat) {
+ EXPECT_EQ(utc_start_time_us / 1000, logged_event.utc_start_time.ms());
+ }
+}
+
+void EventVerifier::VerifyLoggedStopEvent(
+ int64_t stop_time_us,
+ const LoggedStopEvent& logged_event) const {
+ EXPECT_EQ(stop_time_us / 1000, logged_event.log_time_ms());
+}
+
+void VerifyLoggedStreamConfig(const rtclog::StreamConfig& original_config,
+ const rtclog::StreamConfig& logged_config) {
+ EXPECT_EQ(original_config.local_ssrc, logged_config.local_ssrc);
+ EXPECT_EQ(original_config.remote_ssrc, logged_config.remote_ssrc);
+ EXPECT_EQ(original_config.rtx_ssrc, logged_config.rtx_ssrc);
+
+ EXPECT_EQ(original_config.rtp_extensions.size(),
+ logged_config.rtp_extensions.size());
+ size_t recognized_extensions = 0;
+ for (size_t i = 0; i < kMaxNumExtensions; i++) {
+ auto original_id =
+ GetExtensionId(original_config.rtp_extensions, kExtensions[i].name);
+ auto logged_id =
+ GetExtensionId(logged_config.rtp_extensions, kExtensions[i].name);
+ EXPECT_EQ(original_id, logged_id)
+ << "IDs for " << kExtensions[i].name << " don't match. Original ID "
+ << original_id.value_or(-1) << ". Parsed ID " << logged_id.value_or(-1)
+ << ".";
+ if (original_id) {
+ recognized_extensions++;
+ }
+ }
+ EXPECT_EQ(recognized_extensions, original_config.rtp_extensions.size());
+}
+
+void EventVerifier::VerifyLoggedAudioRecvConfig(
+ const RtcEventAudioReceiveStreamConfig& original_event,
+ const LoggedAudioRecvConfig& logged_event) const {
+ EXPECT_EQ(original_event.timestamp_ms(), logged_event.log_time_ms());
+ VerifyLoggedStreamConfig(original_event.config(), logged_event.config);
+}
+
+void EventVerifier::VerifyLoggedAudioSendConfig(
+ const RtcEventAudioSendStreamConfig& original_event,
+ const LoggedAudioSendConfig& logged_event) const {
+ EXPECT_EQ(original_event.timestamp_ms(), logged_event.log_time_ms());
+ VerifyLoggedStreamConfig(original_event.config(), logged_event.config);
+}
+
+void EventVerifier::VerifyLoggedVideoRecvConfig(
+ const RtcEventVideoReceiveStreamConfig& original_event,
+ const LoggedVideoRecvConfig& logged_event) const {
+ EXPECT_EQ(original_event.timestamp_ms(), logged_event.log_time_ms());
+ VerifyLoggedStreamConfig(original_event.config(), logged_event.config);
+}
+
+void EventVerifier::VerifyLoggedVideoSendConfig(
+ const RtcEventVideoSendStreamConfig& original_event,
+ const LoggedVideoSendConfig& logged_event) const {
+ EXPECT_EQ(original_event.timestamp_ms(), logged_event.log_time_ms());
+ VerifyLoggedStreamConfig(original_event.config(), logged_event.config);
+}
+
+void EventVerifier::VerifyLoggedNetEqSetMinimumDelay(
+ const RtcEventNetEqSetMinimumDelay& original_event,
+ const LoggedNetEqSetMinimumDelayEvent& logged_event) const {
+ EXPECT_EQ(original_event.timestamp_ms(), logged_event.timestamp.ms());
+ EXPECT_EQ(original_event.remote_ssrc(), logged_event.remote_ssrc);
+ EXPECT_EQ(original_event.minimum_delay_ms(), logged_event.minimum_delay_ms);
+}
+
+} // namespace test
+} // namespace webrtc
diff --git a/third_party/libwebrtc/logging/rtc_event_log/rtc_event_log_unittest_helper.h b/third_party/libwebrtc/logging/rtc_event_log/rtc_event_log_unittest_helper.h
new file mode 100644
index 0000000000..7b863fd8a0
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/rtc_event_log_unittest_helper.h
@@ -0,0 +1,336 @@
+/*
+ * Copyright (c) 2016 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_RTC_EVENT_LOG_UNITTEST_HELPER_H_
+#define LOGGING_RTC_EVENT_LOG_RTC_EVENT_LOG_UNITTEST_HELPER_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <memory>
+
+#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"
+#include "logging/rtc_event_log/events/rtc_event_audio_receive_stream_config.h"
+#include "logging/rtc_event_log/events/rtc_event_audio_send_stream_config.h"
+#include "logging/rtc_event_log/events/rtc_event_bwe_update_delay_based.h"
+#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_frame_decoded.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"
+#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_remote_estimate.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"
+#include "logging/rtc_event_log/events/rtc_event_rtp_packet_outgoing.h"
+#include "logging/rtc_event_log/events/rtc_event_video_receive_stream_config.h"
+#include "logging/rtc_event_log/events/rtc_event_video_send_stream_config.h"
+#include "logging/rtc_event_log/rtc_event_log_parser.h"
+#include "logging/rtc_event_log/rtc_stream_config.h"
+#include "modules/rtp_rtcp/include/rtp_header_extension_map.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/bye.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/extended_reports.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/fir.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/loss_notification.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/nack.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/pli.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/receiver_report.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/remb.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/report_block.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/sender_report.h"
+#include "modules/rtp_rtcp/source/rtp_packet.h"
+#include "rtc_base/random.h"
+
+namespace webrtc {
+
+namespace test {
+
+class EventGenerator {
+ public:
+ explicit EventGenerator(uint64_t seed) : prng_(seed) {}
+
+ std::unique_ptr<RtcEventAlrState> NewAlrState();
+ 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<RtcEventFrameDecoded> NewFrameDecodedEvent(uint32_t ssrc);
+ 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<RtcEventNetEqSetMinimumDelay> NewNetEqSetMinimumDelay(
+ uint32_t ssrc);
+ std::unique_ptr<RtcEventProbeClusterCreated> NewProbeClusterCreated();
+ std::unique_ptr<RtcEventProbeResultFailure> NewProbeResultFailure();
+ std::unique_ptr<RtcEventProbeResultSuccess> NewProbeResultSuccess();
+ std::unique_ptr<RtcEventRouteChange> NewRouteChange();
+ std::unique_ptr<RtcEventRemoteEstimate> NewRemoteEstimate();
+ std::unique_ptr<RtcEventRtcpPacketIncoming> NewRtcpPacketIncoming();
+ std::unique_ptr<RtcEventRtcpPacketOutgoing> NewRtcpPacketOutgoing();
+
+ rtcp::SenderReport NewSenderReport();
+ rtcp::ReceiverReport NewReceiverReport();
+ rtcp::ExtendedReports NewExtendedReports();
+ rtcp::Nack NewNack();
+ rtcp::Remb NewRemb();
+ rtcp::Fir NewFir();
+ rtcp::Pli NewPli();
+ rtcp::Bye NewBye();
+ rtcp::TransportFeedback NewTransportFeedback();
+ rtcp::LossNotification NewLossNotification();
+
+ // `all_configured_exts` determines whether the RTP packet exhibits all
+ // configured extensions, or a random subset thereof.
+ void RandomizeRtpPacket(size_t payload_size,
+ size_t padding_size,
+ uint32_t ssrc,
+ const RtpHeaderExtensionMap& extension_map,
+ RtpPacket* rtp_packet,
+ bool all_configured_exts);
+
+ // `all_configured_exts` determines whether the RTP packet exhibits all
+ // configured extensions, or a random subset thereof.
+ std::unique_ptr<RtcEventRtpPacketIncoming> NewRtpPacketIncoming(
+ uint32_t ssrc,
+ const RtpHeaderExtensionMap& extension_map,
+ bool all_configured_exts = true);
+
+ // `all_configured_exts` determines whether the RTP packet exhibits all
+ // configured extensions, or a random subset thereof.
+ std::unique_ptr<RtcEventRtpPacketOutgoing> NewRtpPacketOutgoing(
+ uint32_t ssrc,
+ const RtpHeaderExtensionMap& extension_map,
+ bool all_configured_exts = true);
+
+ // `configure_all` determines whether all supported extensions are configured,
+ // or a random subset.
+ RtpHeaderExtensionMap NewRtpHeaderExtensionMap(bool configure_all = false);
+
+ std::unique_ptr<RtcEventAudioReceiveStreamConfig> NewAudioReceiveStreamConfig(
+ uint32_t ssrc,
+ const RtpHeaderExtensionMap& extensions);
+
+ std::unique_ptr<RtcEventAudioSendStreamConfig> NewAudioSendStreamConfig(
+ uint32_t ssrc,
+ const RtpHeaderExtensionMap& extensions);
+
+ std::unique_ptr<RtcEventVideoReceiveStreamConfig> NewVideoReceiveStreamConfig(
+ uint32_t ssrc,
+ const RtpHeaderExtensionMap& extensions);
+
+ std::unique_ptr<RtcEventVideoSendStreamConfig> NewVideoSendStreamConfig(
+ uint32_t ssrc,
+ const RtpHeaderExtensionMap& extensions);
+
+ private:
+ rtcp::ReportBlock NewReportBlock();
+ int sent_packet_number_ = 0;
+ int received_packet_number_ = 0;
+
+ Random prng_;
+};
+
+class EventVerifier {
+ public:
+ explicit EventVerifier(RtcEventLog::EncodingType encoding_type)
+ : encoding_type_(encoding_type) {}
+
+ void VerifyLoggedAlrStateEvent(const RtcEventAlrState& original_event,
+ const LoggedAlrStateEvent& logged_event) const;
+
+ void VerifyLoggedAudioPlayoutEvent(
+ const RtcEventAudioPlayout& original_event,
+ const LoggedAudioPlayoutEvent& logged_event) const;
+
+ void VerifyLoggedAudioNetworkAdaptationEvent(
+ const RtcEventAudioNetworkAdaptation& original_event,
+ const LoggedAudioNetworkAdaptationEvent& logged_event) const;
+
+ void VerifyLoggedBweDelayBasedUpdate(
+ const RtcEventBweUpdateDelayBased& original_event,
+ const LoggedBweDelayBasedUpdate& logged_event) const;
+
+ void VerifyLoggedBweLossBasedUpdate(
+ const RtcEventBweUpdateLossBased& original_event,
+ const LoggedBweLossBasedUpdate& logged_event) const;
+
+ void VerifyLoggedBweProbeClusterCreatedEvent(
+ const RtcEventProbeClusterCreated& original_event,
+ const LoggedBweProbeClusterCreatedEvent& logged_event) const;
+
+ void VerifyLoggedBweProbeFailureEvent(
+ const RtcEventProbeResultFailure& original_event,
+ const LoggedBweProbeFailureEvent& logged_event) const;
+
+ void VerifyLoggedBweProbeSuccessEvent(
+ const RtcEventProbeResultSuccess& original_event,
+ const LoggedBweProbeSuccessEvent& logged_event) const;
+
+ void VerifyLoggedDtlsTransportState(
+ const RtcEventDtlsTransportState& original_event,
+ const LoggedDtlsTransportState& logged_event) const;
+
+ void VerifyLoggedDtlsWritableState(
+ const RtcEventDtlsWritableState& original_event,
+ const LoggedDtlsWritableState& logged_event) const;
+
+ void VerifyLoggedFrameDecoded(const RtcEventFrameDecoded& original_event,
+ const LoggedFrameDecoded& logged_event) const;
+
+ void VerifyLoggedIceCandidatePairConfig(
+ const RtcEventIceCandidatePairConfig& original_event,
+ const LoggedIceCandidatePairConfig& logged_event) const;
+
+ void VerifyLoggedIceCandidatePairEvent(
+ const RtcEventIceCandidatePair& original_event,
+ const LoggedIceCandidatePairEvent& logged_event) const;
+
+ void VerifyLoggedRouteChangeEvent(
+ const RtcEventRouteChange& original_event,
+ const LoggedRouteChangeEvent& logged_event) const;
+
+ void VerifyLoggedRemoteEstimateEvent(
+ const RtcEventRemoteEstimate& original_event,
+ const LoggedRemoteEstimateEvent& logged_event) const;
+
+ void VerifyLoggedRtpPacketIncoming(
+ const RtcEventRtpPacketIncoming& original_event,
+ const LoggedRtpPacketIncoming& logged_event) const;
+
+ void VerifyLoggedRtpPacketOutgoing(
+ 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) {
+ static_assert(sizeof(ParsedType) == 0,
+ "You have to use one of the two defined template "
+ "specializations of VerifyLoggedRtpPacket");
+ }
+
+ template <>
+ void VerifyLoggedRtpPacket(const RtcEventRtpPacketIncoming& original_event,
+ const LoggedRtpPacketIncoming& logged_event) {
+ VerifyLoggedRtpPacketIncoming(original_event, logged_event);
+ }
+
+ template <>
+ void VerifyLoggedRtpPacket(const RtcEventRtpPacketOutgoing& original_event,
+ const LoggedRtpPacketOutgoing& logged_event) {
+ VerifyLoggedRtpPacketOutgoing(original_event, logged_event);
+ }
+
+ void VerifyLoggedRtcpPacketIncoming(
+ const RtcEventRtcpPacketIncoming& original_event,
+ const LoggedRtcpPacketIncoming& logged_event) const;
+
+ void VerifyLoggedRtcpPacketOutgoing(
+ const RtcEventRtcpPacketOutgoing& original_event,
+ const LoggedRtcpPacketOutgoing& logged_event) const;
+
+ void VerifyLoggedSenderReport(int64_t log_time_ms,
+ const rtcp::SenderReport& original_sr,
+ const LoggedRtcpPacketSenderReport& logged_sr);
+ void VerifyLoggedReceiverReport(
+ int64_t log_time_ms,
+ const rtcp::ReceiverReport& original_rr,
+ const LoggedRtcpPacketReceiverReport& logged_rr);
+ void VerifyLoggedExtendedReports(
+ int64_t log_time_ms,
+ const rtcp::ExtendedReports& original_xr,
+ const LoggedRtcpPacketExtendedReports& logged_xr);
+ void VerifyLoggedFir(int64_t log_time_ms,
+ const rtcp::Fir& original_fir,
+ const LoggedRtcpPacketFir& logged_fir);
+ void VerifyLoggedPli(int64_t log_time_ms,
+ const rtcp::Pli& original_pli,
+ const LoggedRtcpPacketPli& logged_pli);
+ void VerifyLoggedBye(int64_t log_time_ms,
+ const rtcp::Bye& original_bye,
+ const LoggedRtcpPacketBye& logged_bye);
+ void VerifyLoggedNack(int64_t log_time_ms,
+ const rtcp::Nack& original_nack,
+ const LoggedRtcpPacketNack& logged_nack);
+ void VerifyLoggedTransportFeedback(
+ int64_t log_time_ms,
+ const rtcp::TransportFeedback& original_transport_feedback,
+ const LoggedRtcpPacketTransportFeedback& logged_transport_feedback);
+ void VerifyLoggedRemb(int64_t log_time_ms,
+ const rtcp::Remb& original_remb,
+ const LoggedRtcpPacketRemb& logged_remb);
+ void VerifyLoggedLossNotification(
+ int64_t log_time_ms,
+ const rtcp::LossNotification& original_loss_notification,
+ const LoggedRtcpPacketLossNotification& logged_loss_notification);
+
+ void VerifyLoggedStartEvent(int64_t start_time_us,
+ int64_t utc_start_time_us,
+ const LoggedStartEvent& logged_event) const;
+ void VerifyLoggedStopEvent(int64_t stop_time_us,
+ const LoggedStopEvent& logged_event) const;
+
+ void VerifyLoggedAudioRecvConfig(
+ const RtcEventAudioReceiveStreamConfig& original_event,
+ const LoggedAudioRecvConfig& logged_event) const;
+
+ void VerifyLoggedAudioSendConfig(
+ const RtcEventAudioSendStreamConfig& original_event,
+ const LoggedAudioSendConfig& logged_event) const;
+
+ void VerifyLoggedVideoRecvConfig(
+ const RtcEventVideoReceiveStreamConfig& original_event,
+ const LoggedVideoRecvConfig& logged_event) const;
+
+ void VerifyLoggedVideoSendConfig(
+ const RtcEventVideoSendStreamConfig& original_event,
+ const LoggedVideoSendConfig& logged_event) const;
+
+ void VerifyLoggedNetEqSetMinimumDelay(
+ const RtcEventNetEqSetMinimumDelay& original_event,
+ const LoggedNetEqSetMinimumDelayEvent& logged_event) const;
+
+ private:
+ void VerifyReportBlock(const rtcp::ReportBlock& original_report_block,
+ const rtcp::ReportBlock& logged_report_block);
+
+ RtcEventLog::EncodingType encoding_type_;
+};
+
+} // namespace test
+} // namespace webrtc
+
+#endif // LOGGING_RTC_EVENT_LOG_RTC_EVENT_LOG_UNITTEST_HELPER_H_
diff --git a/third_party/libwebrtc/logging/rtc_event_log/rtc_event_processor.cc b/third_party/libwebrtc/logging/rtc_event_log/rtc_event_processor.cc
new file mode 100644
index 0000000000..e6a9983b6f
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/rtc_event_processor.cc
@@ -0,0 +1,41 @@
+/*
+ * Copyright 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/rtc_event_processor.h"
+
+namespace webrtc {
+
+RtcEventProcessor::RtcEventProcessor() = default;
+
+RtcEventProcessor::~RtcEventProcessor() = default;
+void RtcEventProcessor::ProcessEventsInOrder() {
+ // `event_lists_` is a min-heap of lists ordered by the timestamp of the
+ // first element in the list. We therefore process the first element of the
+ // first list, then reinsert the remainder of that list into the heap
+ // if the list still contains unprocessed elements.
+ while (!event_lists_.empty()) {
+ event_lists_.front()->ProcessNext();
+ std::pop_heap(event_lists_.begin(), event_lists_.end(), Cmp);
+ if (event_lists_.back()->IsEmpty()) {
+ event_lists_.pop_back();
+ } else {
+ std::push_heap(event_lists_.begin(), event_lists_.end(), Cmp);
+ }
+ }
+}
+
+bool RtcEventProcessor::Cmp(const RtcEventProcessor::ListPtrType& a,
+ const RtcEventProcessor::ListPtrType& b) {
+ int64_t time_diff = a->GetNextTime() - b->GetNextTime();
+ if (time_diff == 0)
+ return a->GetTieBreaker() > b->GetTieBreaker();
+ return time_diff > 0;
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/logging/rtc_event_log/rtc_event_processor.h b/third_party/libwebrtc/logging/rtc_event_log/rtc_event_processor.h
new file mode 100644
index 0000000000..9bf4c9c5db
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/rtc_event_processor.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2018 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_RTC_EVENT_PROCESSOR_H_
+#define LOGGING_RTC_EVENT_LOG_RTC_EVENT_PROCESSOR_H_
+
+#include <stdint.h>
+
+#include <algorithm>
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "api/function_view.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+// This file contains helper class used to process the elements of two or more
+// sorted lists in timestamp order. The effect is the same as doing a merge step
+// in the merge-sort algorithm but without copying the elements or modifying the
+// lists.
+
+namespace event_processor_impl {
+// Interface to allow "merging" lists of different types. ProcessNext()
+// processes the next unprocesses element in the list. IsEmpty() checks if all
+// elements have been processed. GetNextTime returns the timestamp of the next
+// unprocessed element.
+class ProcessableEventListInterface {
+ public:
+ virtual ~ProcessableEventListInterface() = default;
+ virtual void ProcessNext() = 0;
+ virtual bool IsEmpty() const = 0;
+ virtual int64_t GetNextTime() const = 0;
+ virtual int GetTieBreaker() const = 0;
+};
+
+// ProcessableEventList encapsulates a list of events and a function that will
+// be applied to each element of the list.
+template <typename Iterator, typename T>
+class ProcessableEventList : public ProcessableEventListInterface {
+ public:
+ ProcessableEventList(Iterator begin,
+ Iterator end,
+ std::function<void(const T&)> f,
+ int tie_breaker)
+ : begin_(begin), end_(end), f_(f), tie_breaker_(tie_breaker) {}
+
+ void ProcessNext() override {
+ RTC_DCHECK(!IsEmpty());
+ f_(*begin_);
+ ++begin_;
+ }
+
+ bool IsEmpty() const override { return begin_ == end_; }
+
+ int64_t GetNextTime() const override {
+ RTC_DCHECK(!IsEmpty());
+ return begin_->log_time_us();
+ }
+ int GetTieBreaker() const override { return tie_breaker_; }
+
+ private:
+ Iterator begin_;
+ Iterator end_;
+ std::function<void(const T&)> f_;
+ int tie_breaker_;
+};
+} // namespace event_processor_impl
+
+// Helper class used to "merge" two or more lists of ordered RtcEventLog events
+// so that they can be treated as a single ordered list. Since the individual
+// lists may have different types, we need to access the lists via pointers to
+// the common base class.
+//
+// Usage example:
+// ParsedRtcEventLogNew log;
+// auto incoming_handler = [] (LoggedRtcpPacketIncoming elem) { ... };
+// auto outgoing_handler = [] (LoggedRtcpPacketOutgoing elem) { ... };
+//
+// RtcEventProcessor processor;
+// processor.AddEvents(log.incoming_rtcp_packets(),
+// incoming_handler);
+// processor.AddEvents(log.outgoing_rtcp_packets(),
+// outgoing_handler);
+// processor.ProcessEventsInOrder();
+class RtcEventProcessor {
+ public:
+ RtcEventProcessor();
+ ~RtcEventProcessor();
+ // The elements of each list is processed in the index order. To process all
+ // elements in all lists in timestamp order, each list needs to be sorted in
+ // timestamp order prior to insertion.
+ // N.B. `iterable` is not owned by RtcEventProcessor. The caller must ensure
+ // that the iterable outlives RtcEventProcessor and it must not be modified
+ // until processing has finished.
+ template <typename Iterable>
+ void AddEvents(
+ const Iterable& iterable,
+ std::function<void(const typename Iterable::value_type&)> handler) {
+ if (iterable.begin() == iterable.end())
+ return;
+ event_lists_.push_back(
+ std::make_unique<event_processor_impl::ProcessableEventList<
+ typename Iterable::const_iterator, typename Iterable::value_type>>(
+ iterable.begin(), iterable.end(), handler,
+ insertion_order_index_++));
+ std::push_heap(event_lists_.begin(), event_lists_.end(), Cmp);
+ }
+
+ void ProcessEventsInOrder();
+
+ private:
+ using ListPtrType =
+ std::unique_ptr<event_processor_impl::ProcessableEventListInterface>;
+ int insertion_order_index_ = 0;
+ std::vector<ListPtrType> event_lists_;
+ // Comparison function to make `event_lists_` into a min heap.
+ static bool Cmp(const ListPtrType& a, const ListPtrType& b);
+};
+
+} // namespace webrtc
+
+#endif // LOGGING_RTC_EVENT_LOG_RTC_EVENT_PROCESSOR_H_
diff --git a/third_party/libwebrtc/logging/rtc_event_log/rtc_event_processor_unittest.cc b/third_party/libwebrtc/logging/rtc_event_log/rtc_event_processor_unittest.cc
new file mode 100644
index 0000000000..b0cec25f1f
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/rtc_event_processor_unittest.cc
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2018 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/rtc_event_processor.h"
+
+#include <stddef.h>
+
+#include <cstdint>
+#include <initializer_list>
+#include <numeric>
+
+#include "absl/memory/memory.h"
+#include "logging/rtc_event_log/rtc_event_log_parser.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/random.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+
+namespace {
+std::vector<LoggedStartEvent> CreateEventList(
+ std::initializer_list<int64_t> timestamp_list) {
+ std::vector<LoggedStartEvent> v;
+ for (int64_t timestamp_ms : timestamp_list) {
+ v.emplace_back(Timestamp::Millis(timestamp_ms));
+ }
+ return v;
+}
+
+std::vector<std::vector<LoggedStartEvent>>
+CreateRandomEventLists(size_t num_lists, size_t num_elements, uint64_t seed) {
+ Random prng(seed);
+ std::vector<std::vector<LoggedStartEvent>> lists(num_lists);
+ for (size_t elem = 0; elem < num_elements; elem++) {
+ uint32_t i = prng.Rand(0u, num_lists - 1);
+ int64_t timestamp_ms = elem;
+ lists[i].emplace_back(Timestamp::Millis(timestamp_ms));
+ }
+ return lists;
+}
+} // namespace
+
+TEST(RtcEventProcessor, NoList) {
+ RtcEventProcessor processor;
+ processor.ProcessEventsInOrder(); // Don't crash but do nothing.
+}
+
+TEST(RtcEventProcessor, EmptyList) {
+ auto not_called = [](LoggedStartEvent /*elem*/) { EXPECT_TRUE(false); };
+ std::vector<LoggedStartEvent> events;
+ RtcEventProcessor processor;
+
+ processor.AddEvents(events, not_called);
+ processor.ProcessEventsInOrder(); // Don't crash but do nothing.
+}
+
+TEST(RtcEventProcessor, OneList) {
+ std::vector<LoggedStartEvent> result;
+ auto f = [&result](LoggedStartEvent elem) { result.push_back(elem); };
+
+ std::vector<LoggedStartEvent> events(CreateEventList({1, 2, 3, 4}));
+ RtcEventProcessor processor;
+ processor.AddEvents(events, f);
+ processor.ProcessEventsInOrder();
+
+ std::vector<int64_t> expected_results{1, 2, 3, 4};
+ ASSERT_EQ(result.size(), expected_results.size());
+ for (size_t i = 0; i < expected_results.size(); i++) {
+ EXPECT_EQ(result[i].log_time_ms(), expected_results[i]);
+ }
+}
+
+TEST(RtcEventProcessor, MergeTwoLists) {
+ std::vector<LoggedStartEvent> result;
+ auto f = [&result](LoggedStartEvent elem) { result.push_back(elem); };
+
+ std::vector<LoggedStartEvent> events1(CreateEventList({1, 2, 4, 7, 8, 9}));
+ std::vector<LoggedStartEvent> events2(CreateEventList({3, 5, 6, 10}));
+ RtcEventProcessor processor;
+ processor.AddEvents(events1, f);
+ processor.AddEvents(events2, f);
+ processor.ProcessEventsInOrder();
+
+ std::vector<int64_t> expected_results{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+ ASSERT_EQ(result.size(), expected_results.size());
+ for (size_t i = 0; i < expected_results.size(); i++) {
+ EXPECT_EQ(result[i].log_time_ms(), expected_results[i]);
+ }
+}
+
+TEST(RtcEventProcessor, MergeTwoListsWithDuplicatedElements) {
+ std::vector<LoggedStartEvent> result;
+ auto f = [&result](LoggedStartEvent elem) { result.push_back(elem); };
+
+ std::vector<LoggedStartEvent> events1(CreateEventList({1, 2, 2, 3, 5, 5}));
+ std::vector<LoggedStartEvent> events2(CreateEventList({1, 3, 4, 4}));
+ RtcEventProcessor processor;
+ processor.AddEvents(events1, f);
+ processor.AddEvents(events2, f);
+ processor.ProcessEventsInOrder();
+
+ std::vector<int64_t> expected_results{1, 1, 2, 2, 3, 3, 4, 4, 5, 5};
+ ASSERT_EQ(result.size(), expected_results.size());
+ for (size_t i = 0; i < expected_results.size(); i++) {
+ EXPECT_EQ(result[i].log_time_ms(), expected_results[i]);
+ }
+}
+
+TEST(RtcEventProcessor, MergeManyLists) {
+ std::vector<LoggedStartEvent> result;
+ auto f = [&result](LoggedStartEvent elem) { result.push_back(elem); };
+
+ constexpr size_t kNumLists = 5;
+ constexpr size_t kNumElems = 30;
+ constexpr uint64_t kSeed = 0xF3C6B91F;
+ std::vector<std::vector<LoggedStartEvent>> lists(
+ CreateRandomEventLists(kNumLists, kNumElems, kSeed));
+ RTC_DCHECK_EQ(lists.size(), kNumLists);
+ RtcEventProcessor processor;
+ for (const auto& list : lists) {
+ processor.AddEvents(list, f);
+ }
+ processor.ProcessEventsInOrder();
+
+ std::vector<int64_t> expected_results(kNumElems);
+ std::iota(expected_results.begin(), expected_results.end(), 0);
+ ASSERT_EQ(result.size(), expected_results.size());
+ for (size_t i = 0; i < expected_results.size(); i++) {
+ EXPECT_EQ(result[i].log_time_ms(), expected_results[i]);
+ }
+}
+
+TEST(RtcEventProcessor, DifferentTypes) {
+ std::vector<int64_t> result;
+ auto f1 = [&result](LoggedStartEvent elem) {
+ result.push_back(elem.log_time_ms());
+ };
+ auto f2 = [&result](LoggedStopEvent elem) {
+ result.push_back(elem.log_time_ms());
+ };
+
+ std::vector<LoggedStartEvent> events1{LoggedStartEvent(Timestamp::Millis(2))};
+ std::vector<LoggedStopEvent> events2{LoggedStopEvent(Timestamp::Millis(1))};
+ RtcEventProcessor processor;
+ processor.AddEvents(events1, f1);
+ processor.AddEvents(events2, f2);
+ processor.ProcessEventsInOrder();
+
+ std::vector<int64_t> expected_results{1, 2};
+ ASSERT_EQ(result.size(), expected_results.size());
+ for (size_t i = 0; i < expected_results.size(); i++) {
+ EXPECT_EQ(result[i], expected_results[i]);
+ }
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/logging/rtc_event_log/rtc_stream_config.cc b/third_party/libwebrtc/logging/rtc_event_log/rtc_stream_config.cc
new file mode 100644
index 0000000000..aa107c80bc
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/rtc_stream_config.cc
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2017 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/rtc_stream_config.h"
+
+#include "absl/strings/string_view.h"
+
+namespace webrtc {
+namespace rtclog {
+
+StreamConfig::StreamConfig() {}
+
+StreamConfig::~StreamConfig() {}
+
+StreamConfig::StreamConfig(const StreamConfig& other) = default;
+
+bool StreamConfig::operator==(const StreamConfig& other) const {
+ return local_ssrc == other.local_ssrc && remote_ssrc == other.remote_ssrc &&
+ rtx_ssrc == other.rtx_ssrc && rsid == other.rsid &&
+ remb == other.remb && rtcp_mode == other.rtcp_mode &&
+ rtp_extensions == other.rtp_extensions && codecs == other.codecs;
+}
+
+bool StreamConfig::operator!=(const StreamConfig& other) const {
+ return !(*this == other);
+}
+
+StreamConfig::Codec::Codec(absl::string_view payload_name,
+ int payload_type,
+ int rtx_payload_type)
+ : payload_name(payload_name),
+ payload_type(payload_type),
+ rtx_payload_type(rtx_payload_type) {}
+
+bool StreamConfig::Codec::operator==(const Codec& other) const {
+ return payload_name == other.payload_name &&
+ payload_type == other.payload_type &&
+ rtx_payload_type == other.rtx_payload_type;
+}
+
+} // namespace rtclog
+} // namespace webrtc
diff --git a/third_party/libwebrtc/logging/rtc_event_log/rtc_stream_config.h b/third_party/libwebrtc/logging/rtc_event_log/rtc_stream_config.h
new file mode 100644
index 0000000000..d114332d34
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_log/rtc_stream_config.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2017 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_RTC_STREAM_CONFIG_H_
+#define LOGGING_RTC_EVENT_LOG_RTC_STREAM_CONFIG_H_
+
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/rtp_headers.h"
+#include "api/rtp_parameters.h"
+
+namespace webrtc {
+namespace rtclog {
+
+struct StreamConfig {
+ StreamConfig();
+ StreamConfig(const StreamConfig& other);
+ ~StreamConfig();
+
+ bool operator==(const StreamConfig& other) const;
+ bool operator!=(const StreamConfig& other) const;
+
+ uint32_t local_ssrc = 0;
+ uint32_t remote_ssrc = 0;
+ uint32_t rtx_ssrc = 0;
+ std::string rsid;
+
+ bool remb = false;
+ std::vector<RtpExtension> rtp_extensions;
+
+ RtcpMode rtcp_mode = RtcpMode::kReducedSize;
+
+ struct Codec {
+ Codec(absl::string_view payload_name,
+ int payload_type,
+ int rtx_payload_type);
+
+ bool operator==(const Codec& other) const;
+
+ std::string payload_name;
+ int payload_type;
+ int rtx_payload_type;
+ };
+
+ std::vector<Codec> codecs;
+};
+
+} // namespace rtclog
+} // namespace webrtc
+
+#endif // LOGGING_RTC_EVENT_LOG_RTC_STREAM_CONFIG_H_
diff --git a/third_party/libwebrtc/logging/rtc_event_number_encodings_gn/moz.build b/third_party/libwebrtc/logging/rtc_event_number_encodings_gn/moz.build
new file mode 100644
index 0000000000..ad1c261545
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_number_encodings_gn/moz.build
@@ -0,0 +1,223 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+ ### This moz.build was AUTOMATICALLY GENERATED from a GN config, ###
+ ### DO NOT edit it by hand. ###
+
+COMPILE_FLAGS["OS_INCLUDES"] = []
+AllowCompilerWarnings()
+
+DEFINES["ABSL_ALLOCATOR_NOTHROW"] = "1"
+DEFINES["RTC_DAV1D_IN_INTERNAL_DECODER_FACTORY"] = True
+DEFINES["RTC_ENABLE_VP9"] = True
+DEFINES["WEBRTC_ENABLE_PROTOBUF"] = "0"
+DEFINES["WEBRTC_LIBRARY_IMPL"] = True
+DEFINES["WEBRTC_MOZILLA_BUILD"] = True
+DEFINES["WEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS"] = "0"
+DEFINES["WEBRTC_STRICT_FIELD_TRIALS"] = "0"
+
+FINAL_LIBRARY = "webrtc"
+
+
+LOCAL_INCLUDES += [
+ "!/ipc/ipdl/_ipdlheaders",
+ "!/third_party/libwebrtc/gen",
+ "/ipc/chromium/src",
+ "/third_party/libwebrtc/",
+ "/third_party/libwebrtc/third_party/abseil-cpp/",
+ "/tools/profiler/public"
+]
+
+UNIFIED_SOURCES += [
+ "/third_party/libwebrtc/logging/rtc_event_log/encoder/bit_writer.cc",
+ "/third_party/libwebrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder_common.cc",
+ "/third_party/libwebrtc/logging/rtc_event_log/encoder/var_int.cc"
+]
+
+if not CONFIG["MOZ_DEBUG"]:
+
+ DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "0"
+ DEFINES["NDEBUG"] = True
+ DEFINES["NVALGRIND"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1":
+
+ DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "1"
+
+if CONFIG["OS_TARGET"] == "Android":
+
+ DEFINES["ANDROID"] = True
+ DEFINES["ANDROID_NDK_VERSION_ROLL"] = "r22_1"
+ DEFINES["HAVE_SYS_UIO_H"] = True
+ DEFINES["WEBRTC_ANDROID"] = True
+ DEFINES["WEBRTC_ANDROID_OPENSLES"] = True
+ DEFINES["WEBRTC_LINUX"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_GNU_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+ OS_LIBS += [
+ "log"
+ ]
+
+if CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["WEBRTC_MAC"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_LIBCPP_HAS_NO_ALIGNED_ALLOCATION"] = True
+ DEFINES["__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES"] = "0"
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["USE_AURA"] = "1"
+ DEFINES["USE_GLIB"] = "1"
+ DEFINES["USE_NSS_CERTS"] = "1"
+ DEFINES["USE_OZONE"] = "1"
+ DEFINES["USE_UDEV"] = True
+ DEFINES["WEBRTC_LINUX"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+ DEFINES["_LARGEFILE64_SOURCE"] = True
+ DEFINES["_LARGEFILE_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "OpenBSD":
+
+ DEFINES["USE_GLIB"] = "1"
+ DEFINES["USE_OZONE"] = "1"
+ DEFINES["USE_X11"] = "1"
+ DEFINES["WEBRTC_BSD"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+ DEFINES["_LARGEFILE64_SOURCE"] = True
+ DEFINES["_LARGEFILE_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "WINNT":
+
+ DEFINES["CERT_CHAIN_PARA_HAS_EXTRA_FIELDS"] = True
+ DEFINES["NOMINMAX"] = True
+ DEFINES["NTDDI_VERSION"] = "0x0A000000"
+ DEFINES["PSAPI_VERSION"] = "2"
+ DEFINES["UNICODE"] = True
+ DEFINES["USE_AURA"] = "1"
+ DEFINES["WEBRTC_WIN"] = True
+ DEFINES["WIN32"] = True
+ DEFINES["WIN32_LEAN_AND_MEAN"] = True
+ DEFINES["WINAPI_FAMILY"] = "WINAPI_FAMILY_DESKTOP_APP"
+ DEFINES["WINVER"] = "0x0A00"
+ DEFINES["_ATL_NO_OPENGL"] = True
+ DEFINES["_CRT_RAND_S"] = True
+ DEFINES["_CRT_SECURE_NO_DEPRECATE"] = True
+ DEFINES["_ENABLE_EXTENDED_ALIGNED_STORAGE"] = True
+ DEFINES["_HAS_EXCEPTIONS"] = "0"
+ DEFINES["_HAS_NODISCARD"] = True
+ DEFINES["_SCL_SECURE_NO_DEPRECATE"] = True
+ DEFINES["_SECURE_ATL"] = True
+ DEFINES["_UNICODE"] = True
+ DEFINES["_WIN32_WINNT"] = "0x0A00"
+ DEFINES["_WINDOWS"] = True
+ DEFINES["__STD_C"] = True
+
+if CONFIG["CPU_ARCH"] == "aarch64":
+
+ DEFINES["WEBRTC_ARCH_ARM64"] = True
+ DEFINES["WEBRTC_HAS_NEON"] = True
+
+if CONFIG["CPU_ARCH"] == "arm":
+
+ CXXFLAGS += [
+ "-mfpu=neon"
+ ]
+
+ DEFINES["WEBRTC_ARCH_ARM"] = True
+ DEFINES["WEBRTC_ARCH_ARM_V7"] = True
+ DEFINES["WEBRTC_HAS_NEON"] = True
+
+if CONFIG["CPU_ARCH"] == "mips32":
+
+ DEFINES["MIPS32_LE"] = True
+ DEFINES["MIPS_FPU_LE"] = True
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "mips64":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86":
+
+ DEFINES["WEBRTC_ENABLE_AVX2"] = True
+
+if CONFIG["CPU_ARCH"] == "x86_64":
+
+ DEFINES["WEBRTC_ENABLE_AVX2"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Android":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "OpenBSD":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "WINNT":
+
+ DEFINES["_HAS_ITERATOR_DEBUGGING"] = "0"
+
+if CONFIG["MOZ_X11"] == "1" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["USE_X11"] = "1"
+
+if CONFIG["CPU_ARCH"] == "arm" and CONFIG["OS_TARGET"] == "Android":
+
+ OS_LIBS += [
+ "android_support",
+ "unwind"
+ ]
+
+if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Android":
+
+ CXXFLAGS += [
+ "-msse2"
+ ]
+
+ OS_LIBS += [
+ "android_support"
+ ]
+
+if CONFIG["CPU_ARCH"] == "aarch64" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "arm" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Linux":
+
+ CXXFLAGS += [
+ "-msse2"
+ ]
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86_64" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+Library("rtc_event_number_encodings_gn")
diff --git a/third_party/libwebrtc/logging/rtc_event_pacing_gn/moz.build b/third_party/libwebrtc/logging/rtc_event_pacing_gn/moz.build
new file mode 100644
index 0000000000..a920e8d643
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_pacing_gn/moz.build
@@ -0,0 +1,225 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+ ### This moz.build was AUTOMATICALLY GENERATED from a GN config, ###
+ ### DO NOT edit it by hand. ###
+
+COMPILE_FLAGS["OS_INCLUDES"] = []
+AllowCompilerWarnings()
+
+DEFINES["ABSL_ALLOCATOR_NOTHROW"] = "1"
+DEFINES["RTC_DAV1D_IN_INTERNAL_DECODER_FACTORY"] = True
+DEFINES["RTC_ENABLE_VP9"] = True
+DEFINES["WEBRTC_ENABLE_PROTOBUF"] = "0"
+DEFINES["WEBRTC_LIBRARY_IMPL"] = True
+DEFINES["WEBRTC_MOZILLA_BUILD"] = True
+DEFINES["WEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS"] = "0"
+DEFINES["WEBRTC_STRICT_FIELD_TRIALS"] = "0"
+
+FINAL_LIBRARY = "webrtc"
+
+
+LOCAL_INCLUDES += [
+ "!/ipc/ipdl/_ipdlheaders",
+ "!/third_party/libwebrtc/gen",
+ "/ipc/chromium/src",
+ "/third_party/libwebrtc/",
+ "/third_party/libwebrtc/third_party/abseil-cpp/",
+ "/tools/profiler/public"
+]
+
+UNIFIED_SOURCES += [
+ "/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_alr_state.cc"
+]
+
+if not CONFIG["MOZ_DEBUG"]:
+
+ DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "0"
+ DEFINES["NDEBUG"] = True
+ DEFINES["NVALGRIND"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1":
+
+ DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "1"
+
+if CONFIG["OS_TARGET"] == "Android":
+
+ DEFINES["ANDROID"] = True
+ DEFINES["ANDROID_NDK_VERSION_ROLL"] = "r22_1"
+ DEFINES["HAVE_SYS_UIO_H"] = True
+ DEFINES["WEBRTC_ANDROID"] = True
+ DEFINES["WEBRTC_ANDROID_OPENSLES"] = True
+ DEFINES["WEBRTC_LINUX"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_GNU_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+ OS_LIBS += [
+ "log"
+ ]
+
+if CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["WEBRTC_MAC"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_LIBCPP_HAS_NO_ALIGNED_ALLOCATION"] = True
+ DEFINES["__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES"] = "0"
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["USE_AURA"] = "1"
+ DEFINES["USE_GLIB"] = "1"
+ DEFINES["USE_NSS_CERTS"] = "1"
+ DEFINES["USE_OZONE"] = "1"
+ DEFINES["USE_UDEV"] = True
+ DEFINES["WEBRTC_LINUX"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+ DEFINES["_LARGEFILE64_SOURCE"] = True
+ DEFINES["_LARGEFILE_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "OpenBSD":
+
+ DEFINES["USE_GLIB"] = "1"
+ DEFINES["USE_OZONE"] = "1"
+ DEFINES["USE_X11"] = "1"
+ DEFINES["WEBRTC_BSD"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+ DEFINES["_LARGEFILE64_SOURCE"] = True
+ DEFINES["_LARGEFILE_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "WINNT":
+
+ DEFINES["CERT_CHAIN_PARA_HAS_EXTRA_FIELDS"] = True
+ DEFINES["NOMINMAX"] = True
+ DEFINES["NTDDI_VERSION"] = "0x0A000000"
+ DEFINES["PSAPI_VERSION"] = "2"
+ DEFINES["UNICODE"] = True
+ DEFINES["USE_AURA"] = "1"
+ DEFINES["WEBRTC_WIN"] = True
+ DEFINES["WIN32"] = True
+ DEFINES["WIN32_LEAN_AND_MEAN"] = True
+ DEFINES["WINAPI_FAMILY"] = "WINAPI_FAMILY_DESKTOP_APP"
+ DEFINES["WINVER"] = "0x0A00"
+ DEFINES["_ATL_NO_OPENGL"] = True
+ DEFINES["_CRT_RAND_S"] = True
+ DEFINES["_CRT_SECURE_NO_DEPRECATE"] = True
+ DEFINES["_ENABLE_EXTENDED_ALIGNED_STORAGE"] = True
+ DEFINES["_HAS_EXCEPTIONS"] = "0"
+ DEFINES["_HAS_NODISCARD"] = True
+ DEFINES["_SCL_SECURE_NO_DEPRECATE"] = True
+ DEFINES["_SECURE_ATL"] = True
+ DEFINES["_UNICODE"] = True
+ DEFINES["_WIN32_WINNT"] = "0x0A00"
+ DEFINES["_WINDOWS"] = True
+ DEFINES["__STD_C"] = True
+
+ OS_LIBS += [
+ "winmm"
+ ]
+
+if CONFIG["CPU_ARCH"] == "aarch64":
+
+ DEFINES["WEBRTC_ARCH_ARM64"] = True
+ DEFINES["WEBRTC_HAS_NEON"] = True
+
+if CONFIG["CPU_ARCH"] == "arm":
+
+ CXXFLAGS += [
+ "-mfpu=neon"
+ ]
+
+ DEFINES["WEBRTC_ARCH_ARM"] = True
+ DEFINES["WEBRTC_ARCH_ARM_V7"] = True
+ DEFINES["WEBRTC_HAS_NEON"] = True
+
+if CONFIG["CPU_ARCH"] == "mips32":
+
+ DEFINES["MIPS32_LE"] = True
+ DEFINES["MIPS_FPU_LE"] = True
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "mips64":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86":
+
+ DEFINES["WEBRTC_ENABLE_AVX2"] = True
+
+if CONFIG["CPU_ARCH"] == "x86_64":
+
+ DEFINES["WEBRTC_ENABLE_AVX2"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Android":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "OpenBSD":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "WINNT":
+
+ DEFINES["_HAS_ITERATOR_DEBUGGING"] = "0"
+
+if CONFIG["MOZ_X11"] == "1" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["USE_X11"] = "1"
+
+if CONFIG["CPU_ARCH"] == "arm" and CONFIG["OS_TARGET"] == "Android":
+
+ OS_LIBS += [
+ "android_support",
+ "unwind"
+ ]
+
+if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Android":
+
+ CXXFLAGS += [
+ "-msse2"
+ ]
+
+ OS_LIBS += [
+ "android_support"
+ ]
+
+if CONFIG["CPU_ARCH"] == "aarch64" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "arm" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Linux":
+
+ CXXFLAGS += [
+ "-msse2"
+ ]
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86_64" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+Library("rtc_event_pacing_gn")
diff --git a/third_party/libwebrtc/logging/rtc_event_rtp_rtcp_gn/moz.build b/third_party/libwebrtc/logging/rtc_event_rtp_rtcp_gn/moz.build
new file mode 100644
index 0000000000..bb826e4a72
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_rtp_rtcp_gn/moz.build
@@ -0,0 +1,235 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+ ### This moz.build was AUTOMATICALLY GENERATED from a GN config, ###
+ ### DO NOT edit it by hand. ###
+
+COMPILE_FLAGS["OS_INCLUDES"] = []
+AllowCompilerWarnings()
+
+DEFINES["ABSL_ALLOCATOR_NOTHROW"] = "1"
+DEFINES["RTC_DAV1D_IN_INTERNAL_DECODER_FACTORY"] = True
+DEFINES["RTC_ENABLE_VP9"] = True
+DEFINES["WEBRTC_ENABLE_PROTOBUF"] = "0"
+DEFINES["WEBRTC_LIBRARY_IMPL"] = True
+DEFINES["WEBRTC_MOZILLA_BUILD"] = True
+DEFINES["WEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS"] = "0"
+DEFINES["WEBRTC_STRICT_FIELD_TRIALS"] = "0"
+
+FINAL_LIBRARY = "webrtc"
+
+
+LOCAL_INCLUDES += [
+ "!/ipc/ipdl/_ipdlheaders",
+ "!/third_party/libwebrtc/gen",
+ "/ipc/chromium/src",
+ "/third_party/libwebrtc/",
+ "/third_party/libwebrtc/third_party/abseil-cpp/",
+ "/tools/profiler/public"
+]
+
+UNIFIED_SOURCES += [
+ "/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_rtcp_packet_incoming.cc",
+ "/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_rtcp_packet_outgoing.cc",
+ "/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_rtp_packet_incoming.cc",
+ "/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_rtp_packet_outgoing.cc"
+]
+
+if not CONFIG["MOZ_DEBUG"]:
+
+ DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "0"
+ DEFINES["NDEBUG"] = True
+ DEFINES["NVALGRIND"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1":
+
+ DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "1"
+
+if CONFIG["OS_TARGET"] == "Android":
+
+ DEFINES["ANDROID"] = True
+ DEFINES["ANDROID_NDK_VERSION_ROLL"] = "r22_1"
+ DEFINES["HAVE_SYS_UIO_H"] = True
+ DEFINES["WEBRTC_ANDROID"] = True
+ DEFINES["WEBRTC_ANDROID_OPENSLES"] = True
+ DEFINES["WEBRTC_LINUX"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_GNU_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+ OS_LIBS += [
+ "log"
+ ]
+
+if CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["WEBRTC_MAC"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_LIBCPP_HAS_NO_ALIGNED_ALLOCATION"] = True
+ DEFINES["__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES"] = "0"
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["USE_AURA"] = "1"
+ DEFINES["USE_GLIB"] = "1"
+ DEFINES["USE_NSS_CERTS"] = "1"
+ DEFINES["USE_OZONE"] = "1"
+ DEFINES["USE_UDEV"] = True
+ DEFINES["WEBRTC_LINUX"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+ DEFINES["_LARGEFILE64_SOURCE"] = True
+ DEFINES["_LARGEFILE_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+ OS_LIBS += [
+ "rt"
+ ]
+
+if CONFIG["OS_TARGET"] == "OpenBSD":
+
+ DEFINES["USE_GLIB"] = "1"
+ DEFINES["USE_OZONE"] = "1"
+ DEFINES["USE_X11"] = "1"
+ DEFINES["WEBRTC_BSD"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+ DEFINES["_LARGEFILE64_SOURCE"] = True
+ DEFINES["_LARGEFILE_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "WINNT":
+
+ DEFINES["CERT_CHAIN_PARA_HAS_EXTRA_FIELDS"] = True
+ DEFINES["NOMINMAX"] = True
+ DEFINES["NTDDI_VERSION"] = "0x0A000000"
+ DEFINES["PSAPI_VERSION"] = "2"
+ DEFINES["UNICODE"] = True
+ DEFINES["USE_AURA"] = "1"
+ DEFINES["WEBRTC_WIN"] = True
+ DEFINES["WIN32"] = True
+ DEFINES["WIN32_LEAN_AND_MEAN"] = True
+ DEFINES["WINAPI_FAMILY"] = "WINAPI_FAMILY_DESKTOP_APP"
+ DEFINES["WINVER"] = "0x0A00"
+ DEFINES["_ATL_NO_OPENGL"] = True
+ DEFINES["_CRT_RAND_S"] = True
+ DEFINES["_CRT_SECURE_NO_DEPRECATE"] = True
+ DEFINES["_ENABLE_EXTENDED_ALIGNED_STORAGE"] = True
+ DEFINES["_HAS_EXCEPTIONS"] = "0"
+ DEFINES["_HAS_NODISCARD"] = True
+ DEFINES["_SCL_SECURE_NO_DEPRECATE"] = True
+ DEFINES["_SECURE_ATL"] = True
+ DEFINES["_UNICODE"] = True
+ DEFINES["_WIN32_WINNT"] = "0x0A00"
+ DEFINES["_WINDOWS"] = True
+ DEFINES["__STD_C"] = True
+
+ OS_LIBS += [
+ "crypt32",
+ "iphlpapi",
+ "secur32",
+ "winmm"
+ ]
+
+if CONFIG["CPU_ARCH"] == "aarch64":
+
+ DEFINES["WEBRTC_ARCH_ARM64"] = True
+ DEFINES["WEBRTC_HAS_NEON"] = True
+
+if CONFIG["CPU_ARCH"] == "arm":
+
+ CXXFLAGS += [
+ "-mfpu=neon"
+ ]
+
+ DEFINES["WEBRTC_ARCH_ARM"] = True
+ DEFINES["WEBRTC_ARCH_ARM_V7"] = True
+ DEFINES["WEBRTC_HAS_NEON"] = True
+
+if CONFIG["CPU_ARCH"] == "mips32":
+
+ DEFINES["MIPS32_LE"] = True
+ DEFINES["MIPS_FPU_LE"] = True
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "mips64":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86":
+
+ DEFINES["WEBRTC_ENABLE_AVX2"] = True
+
+if CONFIG["CPU_ARCH"] == "x86_64":
+
+ DEFINES["WEBRTC_ENABLE_AVX2"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Android":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "OpenBSD":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "WINNT":
+
+ DEFINES["_HAS_ITERATOR_DEBUGGING"] = "0"
+
+if CONFIG["MOZ_X11"] == "1" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["USE_X11"] = "1"
+
+if CONFIG["CPU_ARCH"] == "arm" and CONFIG["OS_TARGET"] == "Android":
+
+ OS_LIBS += [
+ "android_support",
+ "unwind"
+ ]
+
+if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Android":
+
+ CXXFLAGS += [
+ "-msse2"
+ ]
+
+ OS_LIBS += [
+ "android_support"
+ ]
+
+if CONFIG["CPU_ARCH"] == "aarch64" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "arm" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Linux":
+
+ CXXFLAGS += [
+ "-msse2"
+ ]
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86_64" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+Library("rtc_event_rtp_rtcp_gn")
diff --git a/third_party/libwebrtc/logging/rtc_event_video_gn/moz.build b/third_party/libwebrtc/logging/rtc_event_video_gn/moz.build
new file mode 100644
index 0000000000..423abc9ec4
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_event_video_gn/moz.build
@@ -0,0 +1,226 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+ ### This moz.build was AUTOMATICALLY GENERATED from a GN config, ###
+ ### DO NOT edit it by hand. ###
+
+COMPILE_FLAGS["OS_INCLUDES"] = []
+AllowCompilerWarnings()
+
+DEFINES["ABSL_ALLOCATOR_NOTHROW"] = "1"
+DEFINES["RTC_DAV1D_IN_INTERNAL_DECODER_FACTORY"] = True
+DEFINES["RTC_ENABLE_VP9"] = True
+DEFINES["WEBRTC_ENABLE_PROTOBUF"] = "0"
+DEFINES["WEBRTC_LIBRARY_IMPL"] = True
+DEFINES["WEBRTC_MOZILLA_BUILD"] = True
+DEFINES["WEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS"] = "0"
+DEFINES["WEBRTC_STRICT_FIELD_TRIALS"] = "0"
+
+FINAL_LIBRARY = "webrtc"
+
+
+LOCAL_INCLUDES += [
+ "!/ipc/ipdl/_ipdlheaders",
+ "!/third_party/libwebrtc/gen",
+ "/ipc/chromium/src",
+ "/third_party/libwebrtc/",
+ "/third_party/libwebrtc/third_party/abseil-cpp/",
+ "/tools/profiler/public"
+]
+
+UNIFIED_SOURCES += [
+ "/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_video_receive_stream_config.cc",
+ "/third_party/libwebrtc/logging/rtc_event_log/events/rtc_event_video_send_stream_config.cc"
+]
+
+if not CONFIG["MOZ_DEBUG"]:
+
+ DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "0"
+ DEFINES["NDEBUG"] = True
+ DEFINES["NVALGRIND"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1":
+
+ DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "1"
+
+if CONFIG["OS_TARGET"] == "Android":
+
+ DEFINES["ANDROID"] = True
+ DEFINES["ANDROID_NDK_VERSION_ROLL"] = "r22_1"
+ DEFINES["HAVE_SYS_UIO_H"] = True
+ DEFINES["WEBRTC_ANDROID"] = True
+ DEFINES["WEBRTC_ANDROID_OPENSLES"] = True
+ DEFINES["WEBRTC_LINUX"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_GNU_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+ OS_LIBS += [
+ "log"
+ ]
+
+if CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["WEBRTC_MAC"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_LIBCPP_HAS_NO_ALIGNED_ALLOCATION"] = True
+ DEFINES["__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES"] = "0"
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["USE_AURA"] = "1"
+ DEFINES["USE_GLIB"] = "1"
+ DEFINES["USE_NSS_CERTS"] = "1"
+ DEFINES["USE_OZONE"] = "1"
+ DEFINES["USE_UDEV"] = True
+ DEFINES["WEBRTC_LINUX"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+ DEFINES["_LARGEFILE64_SOURCE"] = True
+ DEFINES["_LARGEFILE_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "OpenBSD":
+
+ DEFINES["USE_GLIB"] = "1"
+ DEFINES["USE_OZONE"] = "1"
+ DEFINES["USE_X11"] = "1"
+ DEFINES["WEBRTC_BSD"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+ DEFINES["_LARGEFILE64_SOURCE"] = True
+ DEFINES["_LARGEFILE_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "WINNT":
+
+ DEFINES["CERT_CHAIN_PARA_HAS_EXTRA_FIELDS"] = True
+ DEFINES["NOMINMAX"] = True
+ DEFINES["NTDDI_VERSION"] = "0x0A000000"
+ DEFINES["PSAPI_VERSION"] = "2"
+ DEFINES["UNICODE"] = True
+ DEFINES["USE_AURA"] = "1"
+ DEFINES["WEBRTC_WIN"] = True
+ DEFINES["WIN32"] = True
+ DEFINES["WIN32_LEAN_AND_MEAN"] = True
+ DEFINES["WINAPI_FAMILY"] = "WINAPI_FAMILY_DESKTOP_APP"
+ DEFINES["WINVER"] = "0x0A00"
+ DEFINES["_ATL_NO_OPENGL"] = True
+ DEFINES["_CRT_RAND_S"] = True
+ DEFINES["_CRT_SECURE_NO_DEPRECATE"] = True
+ DEFINES["_ENABLE_EXTENDED_ALIGNED_STORAGE"] = True
+ DEFINES["_HAS_EXCEPTIONS"] = "0"
+ DEFINES["_HAS_NODISCARD"] = True
+ DEFINES["_SCL_SECURE_NO_DEPRECATE"] = True
+ DEFINES["_SECURE_ATL"] = True
+ DEFINES["_UNICODE"] = True
+ DEFINES["_WIN32_WINNT"] = "0x0A00"
+ DEFINES["_WINDOWS"] = True
+ DEFINES["__STD_C"] = True
+
+ OS_LIBS += [
+ "winmm"
+ ]
+
+if CONFIG["CPU_ARCH"] == "aarch64":
+
+ DEFINES["WEBRTC_ARCH_ARM64"] = True
+ DEFINES["WEBRTC_HAS_NEON"] = True
+
+if CONFIG["CPU_ARCH"] == "arm":
+
+ CXXFLAGS += [
+ "-mfpu=neon"
+ ]
+
+ DEFINES["WEBRTC_ARCH_ARM"] = True
+ DEFINES["WEBRTC_ARCH_ARM_V7"] = True
+ DEFINES["WEBRTC_HAS_NEON"] = True
+
+if CONFIG["CPU_ARCH"] == "mips32":
+
+ DEFINES["MIPS32_LE"] = True
+ DEFINES["MIPS_FPU_LE"] = True
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "mips64":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86":
+
+ DEFINES["WEBRTC_ENABLE_AVX2"] = True
+
+if CONFIG["CPU_ARCH"] == "x86_64":
+
+ DEFINES["WEBRTC_ENABLE_AVX2"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Android":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "OpenBSD":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "WINNT":
+
+ DEFINES["_HAS_ITERATOR_DEBUGGING"] = "0"
+
+if CONFIG["MOZ_X11"] == "1" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["USE_X11"] = "1"
+
+if CONFIG["CPU_ARCH"] == "arm" and CONFIG["OS_TARGET"] == "Android":
+
+ OS_LIBS += [
+ "android_support",
+ "unwind"
+ ]
+
+if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Android":
+
+ CXXFLAGS += [
+ "-msse2"
+ ]
+
+ OS_LIBS += [
+ "android_support"
+ ]
+
+if CONFIG["CPU_ARCH"] == "aarch64" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "arm" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Linux":
+
+ CXXFLAGS += [
+ "-msse2"
+ ]
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86_64" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+Library("rtc_event_video_gn")
diff --git a/third_party/libwebrtc/logging/rtc_stream_config_gn/moz.build b/third_party/libwebrtc/logging/rtc_stream_config_gn/moz.build
new file mode 100644
index 0000000000..14ba953e29
--- /dev/null
+++ b/third_party/libwebrtc/logging/rtc_stream_config_gn/moz.build
@@ -0,0 +1,225 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+ ### This moz.build was AUTOMATICALLY GENERATED from a GN config, ###
+ ### DO NOT edit it by hand. ###
+
+COMPILE_FLAGS["OS_INCLUDES"] = []
+AllowCompilerWarnings()
+
+DEFINES["ABSL_ALLOCATOR_NOTHROW"] = "1"
+DEFINES["RTC_DAV1D_IN_INTERNAL_DECODER_FACTORY"] = True
+DEFINES["RTC_ENABLE_VP9"] = True
+DEFINES["WEBRTC_ENABLE_PROTOBUF"] = "0"
+DEFINES["WEBRTC_LIBRARY_IMPL"] = True
+DEFINES["WEBRTC_MOZILLA_BUILD"] = True
+DEFINES["WEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS"] = "0"
+DEFINES["WEBRTC_STRICT_FIELD_TRIALS"] = "0"
+
+FINAL_LIBRARY = "webrtc"
+
+
+LOCAL_INCLUDES += [
+ "!/ipc/ipdl/_ipdlheaders",
+ "!/third_party/libwebrtc/gen",
+ "/ipc/chromium/src",
+ "/third_party/libwebrtc/",
+ "/third_party/libwebrtc/third_party/abseil-cpp/",
+ "/tools/profiler/public"
+]
+
+UNIFIED_SOURCES += [
+ "/third_party/libwebrtc/logging/rtc_event_log/rtc_stream_config.cc"
+]
+
+if not CONFIG["MOZ_DEBUG"]:
+
+ DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "0"
+ DEFINES["NDEBUG"] = True
+ DEFINES["NVALGRIND"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1":
+
+ DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "1"
+
+if CONFIG["OS_TARGET"] == "Android":
+
+ DEFINES["ANDROID"] = True
+ DEFINES["ANDROID_NDK_VERSION_ROLL"] = "r22_1"
+ DEFINES["HAVE_SYS_UIO_H"] = True
+ DEFINES["WEBRTC_ANDROID"] = True
+ DEFINES["WEBRTC_ANDROID_OPENSLES"] = True
+ DEFINES["WEBRTC_LINUX"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_GNU_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+ OS_LIBS += [
+ "log"
+ ]
+
+if CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["WEBRTC_MAC"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_LIBCPP_HAS_NO_ALIGNED_ALLOCATION"] = True
+ DEFINES["__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES"] = "0"
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["USE_AURA"] = "1"
+ DEFINES["USE_GLIB"] = "1"
+ DEFINES["USE_NSS_CERTS"] = "1"
+ DEFINES["USE_OZONE"] = "1"
+ DEFINES["USE_UDEV"] = True
+ DEFINES["WEBRTC_LINUX"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+ DEFINES["_LARGEFILE64_SOURCE"] = True
+ DEFINES["_LARGEFILE_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "OpenBSD":
+
+ DEFINES["USE_GLIB"] = "1"
+ DEFINES["USE_OZONE"] = "1"
+ DEFINES["USE_X11"] = "1"
+ DEFINES["WEBRTC_BSD"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+ DEFINES["_LARGEFILE64_SOURCE"] = True
+ DEFINES["_LARGEFILE_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "WINNT":
+
+ DEFINES["CERT_CHAIN_PARA_HAS_EXTRA_FIELDS"] = True
+ DEFINES["NOMINMAX"] = True
+ DEFINES["NTDDI_VERSION"] = "0x0A000000"
+ DEFINES["PSAPI_VERSION"] = "2"
+ DEFINES["UNICODE"] = True
+ DEFINES["USE_AURA"] = "1"
+ DEFINES["WEBRTC_WIN"] = True
+ DEFINES["WIN32"] = True
+ DEFINES["WIN32_LEAN_AND_MEAN"] = True
+ DEFINES["WINAPI_FAMILY"] = "WINAPI_FAMILY_DESKTOP_APP"
+ DEFINES["WINVER"] = "0x0A00"
+ DEFINES["_ATL_NO_OPENGL"] = True
+ DEFINES["_CRT_RAND_S"] = True
+ DEFINES["_CRT_SECURE_NO_DEPRECATE"] = True
+ DEFINES["_ENABLE_EXTENDED_ALIGNED_STORAGE"] = True
+ DEFINES["_HAS_EXCEPTIONS"] = "0"
+ DEFINES["_HAS_NODISCARD"] = True
+ DEFINES["_SCL_SECURE_NO_DEPRECATE"] = True
+ DEFINES["_SECURE_ATL"] = True
+ DEFINES["_UNICODE"] = True
+ DEFINES["_WIN32_WINNT"] = "0x0A00"
+ DEFINES["_WINDOWS"] = True
+ DEFINES["__STD_C"] = True
+
+ OS_LIBS += [
+ "winmm"
+ ]
+
+if CONFIG["CPU_ARCH"] == "aarch64":
+
+ DEFINES["WEBRTC_ARCH_ARM64"] = True
+ DEFINES["WEBRTC_HAS_NEON"] = True
+
+if CONFIG["CPU_ARCH"] == "arm":
+
+ CXXFLAGS += [
+ "-mfpu=neon"
+ ]
+
+ DEFINES["WEBRTC_ARCH_ARM"] = True
+ DEFINES["WEBRTC_ARCH_ARM_V7"] = True
+ DEFINES["WEBRTC_HAS_NEON"] = True
+
+if CONFIG["CPU_ARCH"] == "mips32":
+
+ DEFINES["MIPS32_LE"] = True
+ DEFINES["MIPS_FPU_LE"] = True
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "mips64":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86":
+
+ DEFINES["WEBRTC_ENABLE_AVX2"] = True
+
+if CONFIG["CPU_ARCH"] == "x86_64":
+
+ DEFINES["WEBRTC_ENABLE_AVX2"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Android":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "OpenBSD":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "WINNT":
+
+ DEFINES["_HAS_ITERATOR_DEBUGGING"] = "0"
+
+if CONFIG["MOZ_X11"] == "1" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["USE_X11"] = "1"
+
+if CONFIG["CPU_ARCH"] == "arm" and CONFIG["OS_TARGET"] == "Android":
+
+ OS_LIBS += [
+ "android_support",
+ "unwind"
+ ]
+
+if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Android":
+
+ CXXFLAGS += [
+ "-msse2"
+ ]
+
+ OS_LIBS += [
+ "android_support"
+ ]
+
+if CONFIG["CPU_ARCH"] == "aarch64" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "arm" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Linux":
+
+ CXXFLAGS += [
+ "-msse2"
+ ]
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86_64" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+Library("rtc_stream_config_gn")