diff options
Diffstat (limited to 'logging')
108 files changed, 7081 insertions, 2383 deletions
diff --git a/logging/BUILD.gn b/logging/BUILD.gn index c1edd69680..fea5569a7d 100644 --- a/logging/BUILD.gn +++ b/logging/BUILD.gn @@ -18,6 +18,7 @@ if (is_android) { group("logging") { deps = [ ":rtc_event_audio", + ":rtc_event_begin_end", ":rtc_event_bwe", ":rtc_event_log_impl_encoder", ":rtc_event_pacing", @@ -32,6 +33,34 @@ rtc_source_set("rtc_event_log_api") { 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", @@ -42,6 +71,7 @@ rtc_library("rtc_stream_config") { "../api:rtp_headers", "../api:rtp_parameters", ] + absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] } rtc_library("rtc_event_pacing") { @@ -51,10 +81,14 @@ rtc_library("rtc_event_pacing") { ] deps = [ - "../api:scoped_refptr", + ":rtc_event_field", "../api/rtc_event_log", + "../api/units:timestamp", + ] + absl_deps = [ + "//third_party/abseil-cpp/absl/memory", + "//third_party/abseil-cpp/absl/strings", ] - absl_deps = [ "//third_party/abseil-cpp/absl/memory" ] } rtc_library("rtc_event_audio") { @@ -70,13 +104,33 @@ rtc_library("rtc_event_audio") { ] deps = [ + ":rtc_event_field", ":rtc_stream_config", - "../api:scoped_refptr", "../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" ] + 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") { @@ -97,13 +151,34 @@ rtc_library("rtc_event_bwe") { ] deps = [ - "../api:scoped_refptr", + ":rtc_event_field", + "../api:network_state_predictor_api", "../api/rtc_event_log", "../api/units:data_rate", - "../modules/remote_bitrate_estimator", + "../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", ] } @@ -119,17 +194,21 @@ rtc_library("rtc_event_generic_packet_events") { "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", @@ -141,14 +220,19 @@ rtc_library("rtc_event_rtp_rtcp") { ] deps = [ + ":rtc_event_field", "../api:array_view", - "../api:scoped_refptr", + "../api:rtp_headers", "../api/rtc_event_log", + "../api/units:timestamp", "../modules/rtp_rtcp:rtp_rtcp_format", + "../rtc_base:buffer", "../rtc_base:checks", - "../rtc_base:rtc_base_approved", ] - absl_deps = [ "//third_party/abseil-cpp/absl/memory" ] + absl_deps = [ + "//third_party/abseil-cpp/absl/memory", + "//third_party/abseil-cpp/absl/strings", + ] } rtc_library("rtc_event_video") { @@ -160,12 +244,42 @@ rtc_library("rtc_event_video") { ] deps = [ + ":rtc_event_field", ":rtc_stream_config", - "../api:scoped_refptr", "../api/rtc_event_log", + "../api/units:timestamp", "../rtc_base:checks", ] - absl_deps = [ "//third_party/abseil-cpp/absl/memory" ] + 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 @@ -176,21 +290,22 @@ rtc_library("rtc_event_log_impl_encoder") { "rtc_event_log/encoder/blob_encoding.h", "rtc_event_log/encoder/delta_encoding.cc", "rtc_event_log/encoder/delta_encoding.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_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:rtc_base_approved", + "../rtc_base:logging", + "../rtc_base:safe_conversions", ] absl_deps = [ "//third_party/abseil-cpp/absl/memory", @@ -202,7 +317,10 @@ rtc_library("rtc_event_log_impl_encoder") { 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", @@ -212,8 +330,8 @@ rtc_library("rtc_event_log_impl_encoder") { ":rtc_event_video", ":rtc_stream_config", "../api:array_view", + "../api:network_state_predictor_api", "../modules/audio_coding:audio_network_adaptor", - "../modules/remote_bitrate_estimator", "../modules/rtp_rtcp:rtp_rtcp_format", ] sources += [ @@ -221,6 +339,8 @@ rtc_library("rtc_event_log_impl_encoder") { "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", ] } } @@ -244,15 +364,24 @@ if (rtc_enable_protobuf) { ":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:rtc_base_approved", + "../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/synchronization:sequence_checker", + "../rtc_base:timeutils", + "../rtc_base/system:no_unique_address", + ] + absl_deps = [ + "//third_party/abseil-cpp/absl/strings", + "//third_party/abseil-cpp/absl/types:optional", ] - absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } } @@ -266,10 +395,10 @@ rtc_library("fake_rtc_event_log") { ] deps = [ - ":ice_log", "../api/rtc_event_log", "../rtc_base", - "../rtc_base:checks", + "../rtc_base:macromagic", + "../rtc_base/synchronization:mutex", ] } @@ -289,7 +418,6 @@ if (rtc_enable_protobuf) { rtc_library("rtc_event_log_parser") { visibility = [ "*" ] sources = [ - "rtc_event_log/logged_events.cc", "rtc_event_log/logged_events.h", "rtc_event_log/rtc_event_log_parser.cc", "rtc_event_log/rtc_event_log_parser.h", @@ -299,34 +427,45 @@ if (rtc_enable_protobuf) { 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", "../modules:module_api_public", "../modules/audio_coding:audio_network_adaptor", - "../modules/remote_bitrate_estimator", - "../modules/rtp_rtcp", "../modules/rtp_rtcp:rtp_rtcp_format", "../rtc_base:checks", - "../rtc_base:deprecation", + "../rtc_base:copy_on_write_buffer", "../rtc_base:ignore_wundef", + "../rtc_base:logging", "../rtc_base:protobuf_utils", - "../rtc_base:rtc_base_approved", "../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", ] } @@ -340,6 +479,8 @@ if (rtc_enable_protobuf) { "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_unittest.cc", "rtc_event_log/rtc_event_log_unittest_helper.cc", "rtc_event_log/rtc_event_log_unittest_helper.h", @@ -349,61 +490,73 @@ if (rtc_enable_protobuf) { ":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_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/remote_bitrate_estimator", "../modules/rtp_rtcp:rtp_rtcp_format", + "../rtc_base:buffer", "../rtc_base:checks", - "../rtc_base:rtc_base_approved", + "../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", "//testing/gtest", ] absl_deps = [ "//third_party/abseil-cpp/absl/memory", + "//third_party/abseil-cpp/absl/strings", "//third_party/abseil-cpp/absl/types:optional", ] } - 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", - "../rtc_base:rtc_base_approved", - "../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/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", + ] + } } } } @@ -423,12 +576,16 @@ rtc_library("ice_log") { ] deps = [ + ":rtc_event_field", + "../api:dtls_transport_interface", "../api:libjingle_logging_api", - "../api:libjingle_peerconnection_api", # For api/dtls_transport_interface.h "../api/rtc_event_log", - "../rtc_base:rtc_base_approved", + "../api/units:timestamp", + ] + absl_deps = [ + "//third_party/abseil-cpp/absl/memory", + "//third_party/abseil-cpp/absl/strings", ] - absl_deps = [ "//third_party/abseil-cpp/absl/memory" ] } if (rtc_include_tests) { diff --git a/logging/g3doc/rtc_event_log.md b/logging/g3doc/rtc_event_log.md new file mode 100644 index 0000000000..6b81de1066 --- /dev/null +++ b/logging/g3doc/rtc_event_log.md @@ -0,0 +1,85 @@ +# RTC event log + +<?% config.freshness.owner = 'terelius' %?> +<?% config.freshness.reviewed = '2021-06-02' %?> + +## 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/logging/rtc_event_log/DEPS b/logging/rtc_event_log/DEPS index 325114c199..fe8a9114ed 100644 --- a/logging/rtc_event_log/DEPS +++ b/logging/rtc_event_log/DEPS @@ -2,7 +2,6 @@ include_rules = [ "+call", "+modules/audio_coding/audio_network_adaptor", "+modules/congestion_controller", - "+modules/remote_bitrate_estimator/include", "+modules/rtp_rtcp", "+system_wrappers", ] diff --git a/logging/rtc_event_log/encoder/bit_writer.cc b/logging/rtc_event_log/encoder/bit_writer.cc new file mode 100644 index 0000000000..e8748d3db3 --- /dev/null +++ b/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/logging/rtc_event_log/encoder/bit_writer.h b/logging/rtc_event_log/encoder/bit_writer.h new file mode 100644 index 0000000000..421e7c4370 --- /dev/null +++ b/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/logging/rtc_event_log/encoder/blob_encoding.cc b/logging/rtc_event_log/encoder/blob_encoding.cc index 48316b052b..96699dc96a 100644 --- a/logging/rtc_event_log/encoder/blob_encoding.cc +++ b/logging/rtc_event_log/encoder/blob_encoding.cc @@ -58,49 +58,30 @@ std::vector<absl::string_view> DecodeBlobs(absl::string_view encoded_blobs, return std::vector<absl::string_view>(); } - size_t read_idx = 0; - // Read the lengths of all blobs. std::vector<uint64_t> lengths(num_of_blobs); for (size_t i = 0; i < num_of_blobs; ++i) { - if (read_idx >= encoded_blobs.length()) { - RTC_DCHECK_EQ(read_idx, encoded_blobs.length()); - RTC_LOG(LS_WARNING) << "Corrupt input; excessive number of blobs."; - return std::vector<absl::string_view>(); - } - - const size_t read_bytes = - DecodeVarInt(encoded_blobs.substr(read_idx), &lengths[i]); - if (read_bytes == 0) { + 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_idx += read_bytes; - - // Note: It might be that read_idx == encoded_blobs.length(), if this - // is the last iteration, and all of the blobs are the empty string. - RTC_DCHECK_LE(read_idx, encoded_blobs.length()); } // Read the blobs themselves. std::vector<absl::string_view> blobs(num_of_blobs); for (size_t i = 0; i < num_of_blobs; ++i) { - if (read_idx + lengths[i] < read_idx) { // Wrap-around detection. - RTC_LOG(LS_WARNING) << "Corrupt input; unreasonably large blob sequence."; - return std::vector<absl::string_view>(); - } - - if (read_idx + lengths[i] > encoded_blobs.length()) { + 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(read_idx, lengths[i]); - read_idx += lengths[i]; + blobs[i] = encoded_blobs.substr(0, lengths[i]); + encoded_blobs = encoded_blobs.substr(lengths[i]); } - if (read_idx != encoded_blobs.length()) { + if (!encoded_blobs.empty()) { RTC_LOG(LS_WARNING) << "Corrupt input; unrecognized trailer."; return std::vector<absl::string_view>(); } diff --git a/logging/rtc_event_log/encoder/blob_encoding.h b/logging/rtc_event_log/encoder/blob_encoding.h index b5b589aaf6..123fffe8e8 100644 --- a/logging/rtc_event_log/encoder/blob_encoding.h +++ b/logging/rtc_event_log/encoder/blob_encoding.h @@ -32,13 +32,13 @@ namespace webrtc { // EncodeBlobs() may not fail. // EncodeBlobs() never returns the empty string. // -// Calling DecodeBlobs() on an empty string, or with |num_of_blobs| set to 0, +// 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. +// 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 +// 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 diff --git a/logging/rtc_event_log/encoder/delta_encoding.cc b/logging/rtc_event_log/encoder/delta_encoding.cc index 022fb9c163..c80424574c 100644 --- a/logging/rtc_event_log/encoder/delta_encoding.cc +++ b/logging/rtc_event_log/encoder/delta_encoding.cc @@ -16,10 +16,12 @@ #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/constructor_magic.h" #include "rtc_base/logging.h" #include "rtc_base/numerics/safe_conversions.h" @@ -71,8 +73,8 @@ uint64_t MaxUnsignedValueOfBitWidth(uint64_t bit_width) { : ((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. +// 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; } @@ -106,58 +108,6 @@ constexpr bool kDefaultSignedDeltas = false; constexpr bool kDefaultValuesOptional = false; constexpr uint64_t kDefaultValueWidthBits = 64; -// 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); - } - - void 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 WriteBits(const std::string& input) { - RTC_DCHECK(valid_); - for (std::string::value_type c : input) { - WriteBits(c, 8 * sizeof(std::string::value_type)); - } - } - - // Returns everything that was written so far. - // Nothing more may be written after this is called. - std::string GetString() { - RTC_DCHECK(valid_); - valid_ = false; - - buffer_.resize(BitsToBytes(written_bits_)); - written_bits_ = 0; - - std::string result; - std::swap(buffer_, result); - return result; - } - - 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_; - - RTC_DISALLOW_COPY_AND_ASSIGN(BitWriter); -}; - // Parameters for fixed-size delta-encoding/decoding. // These are tailored for the sequence which will be encoded (e.g. widths). class FixedLengthEncodingParameters final { @@ -237,6 +187,9 @@ class FixedLengthDeltaEncoder final { 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. @@ -258,7 +211,7 @@ class FixedLengthDeltaEncoder final { // 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|. + // `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, @@ -287,7 +240,7 @@ class FixedLengthDeltaEncoder final { // 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_|. + // which is `base_`. const absl::optional<uint64_t> base_; // The values to be encoded. @@ -299,8 +252,6 @@ class FixedLengthDeltaEncoder final { // 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_; - - RTC_DISALLOW_COPY_AND_ASSIGN(FixedLengthDeltaEncoder); }; // TODO(eladalon): Reduce the number of passes. @@ -604,39 +555,42 @@ class FixedLengthDeltaDecoder final { // 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(const std::string& input); + 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| + // 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 + // If an error occurs (can happen if `input` is corrupt), an empty // vector will be returned. static std::vector<absl::optional<uint64_t>> DecodeDeltas( - const std::string& input, + 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 + // Reads the encoding header in `input` and returns a FixedLengthDeltaDecoder // with the corresponding configuration, that can be used to decode the - // values in |input|. + // 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( - const std::string& input, + 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(std::unique_ptr<rtc::BitBuffer> reader, + // 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); @@ -644,17 +598,7 @@ class FixedLengthDeltaDecoder final { // Perform the decoding using the parameters given to the ctor. std::vector<absl::optional<uint64_t>> Decode(); - // Decode a varint and write it to |output|. Return value indicates success - // or failure. In case of failure, no guarantees are made about the contents - // of |output| or the results of additional reads. - bool ParseVarInt(uint64_t* output); - - // Attempt to parse a delta from the input reader. - // Returns true/false for success/failure. - // Writes the delta into |delta| if successful. - bool ParseDelta(uint64_t* delta); - - // Add |delta| to |base| to produce the next value in a sequence. + // 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. @@ -666,7 +610,7 @@ class FixedLengthDeltaDecoder final { // Reader of the input stream to be decoded. Does not own that buffer. // See comment above ctor for details. - const std::unique_ptr<rtc::BitBuffer> reader_; + BitstreamReader reader_; // The parameters according to which encoding will be done (width of // fields, whether signed deltas should be used, etc.) @@ -674,28 +618,20 @@ class FixedLengthDeltaDecoder final { // 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_|. + // 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_; - - RTC_DISALLOW_COPY_AND_ASSIGN(FixedLengthDeltaDecoder); }; -bool FixedLengthDeltaDecoder::IsSuitableDecoderFor(const std::string& input) { - if (input.length() < kBitsInHeaderForEncodingType) { +bool FixedLengthDeltaDecoder::IsSuitableDecoderFor(absl::string_view input) { + BitstreamReader reader(input); + uint64_t encoding_type_bits = reader.ReadBits(kBitsInHeaderForEncodingType); + if (!reader.Ok()) { return false; } - rtc::BitBuffer reader(reinterpret_cast<const uint8_t*>(&input[0]), - kBitsInHeaderForEncodingType); - - uint32_t encoding_type_bits; - const bool result = - reader.ReadBits(&encoding_type_bits, kBitsInHeaderForEncodingType); - RTC_DCHECK(result); - const auto encoding_type = static_cast<EncodingType>(encoding_type_bits); return encoding_type == EncodingType::kFixedSizeUnsignedDeltasNoEarlyWrapNoOpt || @@ -704,7 +640,7 @@ bool FixedLengthDeltaDecoder::IsSuitableDecoderFor(const std::string& input) { } std::vector<absl::optional<uint64_t>> FixedLengthDeltaDecoder::DecodeDeltas( - const std::string& input, + absl::string_view input, absl::optional<uint64_t> base, size_t num_of_deltas) { auto decoder = FixedLengthDeltaDecoder::Create(input, base, num_of_deltas); @@ -716,21 +652,16 @@ std::vector<absl::optional<uint64_t>> FixedLengthDeltaDecoder::DecodeDeltas( } std::unique_ptr<FixedLengthDeltaDecoder> FixedLengthDeltaDecoder::Create( - const std::string& input, + absl::string_view input, absl::optional<uint64_t> base, size_t num_of_deltas) { - if (input.length() < kBitsInHeaderForEncodingType) { + BitstreamReader reader(input); + // Encoding type + uint32_t encoding_type_bits = reader.ReadBits(kBitsInHeaderForEncodingType); + if (!reader.Ok()) { return nullptr; } - auto reader = std::make_unique<rtc::BitBuffer>( - reinterpret_cast<const uint8_t*>(&input[0]), input.length()); - - // Encoding type - uint32_t encoding_type_bits; - const bool result = - reader->ReadBits(&encoding_type_bits, kBitsInHeaderForEncodingType); - RTC_DCHECK(result); const EncodingType encoding = static_cast<EncodingType>(encoding_type_bits); if (encoding != EncodingType::kFixedSizeUnsignedDeltasNoEarlyWrapNoOpt && encoding != @@ -739,15 +670,10 @@ std::unique_ptr<FixedLengthDeltaDecoder> FixedLengthDeltaDecoder::Create( return nullptr; } - uint32_t read_buffer; - - // delta_width_bits - if (!reader->ReadBits(&read_buffer, kBitsInHeaderForDeltaWidthBits)) { - return nullptr; - } - RTC_DCHECK_LE(read_buffer, 64 - 1); // See encoding for -1's rationale. + // See encoding for +1's rationale. const uint64_t delta_width_bits = - read_buffer + 1; // See encoding for +1's rationale. + reader.ReadBits(kBitsInHeaderForDeltaWidthBits) + 1; + RTC_DCHECK_LE(delta_width_bits, 64); // signed_deltas, values_optional, value_width_bits bool signed_deltas; @@ -758,25 +684,15 @@ std::unique_ptr<FixedLengthDeltaDecoder> FixedLengthDeltaDecoder::Create( values_optional = kDefaultValuesOptional; value_width_bits = kDefaultValueWidthBits; } else { - // signed_deltas - if (!reader->ReadBits(&read_buffer, kBitsInHeaderForSignedDeltas)) { - return nullptr; - } - signed_deltas = rtc::dchecked_cast<bool>(read_buffer); - - // values_optional - if (!reader->ReadBits(&read_buffer, kBitsInHeaderForValuesOptional)) { - return nullptr; - } - RTC_DCHECK_LE(read_buffer, 1); - values_optional = rtc::dchecked_cast<bool>(read_buffer); + 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); + } - // value_width_bits - if (!reader->ReadBits(&read_buffer, kBitsInHeaderForValueWidthBits)) { - return nullptr; - } - RTC_DCHECK_LE(read_buffer, 64 - 1); // See encoding for -1's rationale. - value_width_bits = read_buffer + 1; // See encoding for +1's rationale. + if (!reader.Ok()) { + return nullptr; } // Note: Because of the way the parameters are read, it is not possible @@ -790,35 +706,28 @@ std::unique_ptr<FixedLengthDeltaDecoder> FixedLengthDeltaDecoder::Create( FixedLengthEncodingParameters params(delta_width_bits, signed_deltas, values_optional, value_width_bits); - return absl::WrapUnique(new FixedLengthDeltaDecoder(std::move(reader), params, - base, num_of_deltas)); + return absl::WrapUnique( + new FixedLengthDeltaDecoder(reader, params, base, num_of_deltas)); } FixedLengthDeltaDecoder::FixedLengthDeltaDecoder( - std::unique_ptr<rtc::BitBuffer> reader, + BitstreamReader reader, const FixedLengthEncodingParameters& params, absl::optional<uint64_t> base, size_t num_of_deltas) - : reader_(std::move(reader)), + : reader_(reader), params_(params), base_(base), num_of_deltas_(num_of_deltas) { - RTC_DCHECK(reader_); + RTC_DCHECK(reader_.Ok()); } std::vector<absl::optional<uint64_t>> FixedLengthDeltaDecoder::Decode() { - RTC_DCHECK(reader_); - + 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) { - uint32_t exists; - if (!reader_->ReadBits(&exists, 1u)) { - RTC_LOG(LS_WARNING) << "Failed to read existence-indicating bit."; - return std::vector<absl::optional<uint64_t>>(); - } - RTC_DCHECK_LE(exists, 1u); - existing_values[i] = (exists == 1); + existing_values[i] = reader_.Read<bool>(); } } else { std::fill(existing_values.begin(), existing_values.end(), true); @@ -837,64 +746,20 @@ std::vector<absl::optional<uint64_t>> FixedLengthDeltaDecoder::Decode() { // 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()); - uint64_t first_value; - if (!ParseVarInt(&first_value)) { - RTC_LOG(LS_WARNING) << "Failed to read first value."; - return std::vector<absl::optional<uint64_t>>(); - } - values[i] = first_value; + values[i] = DecodeVarInt(reader_); } else { - uint64_t delta; - if (!ParseDelta(&delta)) { - return std::vector<absl::optional<uint64_t>>(); - } - values[i] = ApplyDelta(previous.value(), delta); + uint64_t delta = reader_.ReadBits(params_.delta_width_bits()); + values[i] = ApplyDelta(*previous, delta); } previous = values[i]; } - return values; -} - -bool FixedLengthDeltaDecoder::ParseVarInt(uint64_t* output) { - RTC_DCHECK(reader_); - return DecodeVarInt(reader_.get(), output) != 0; -} - -bool FixedLengthDeltaDecoder::ParseDelta(uint64_t* delta) { - RTC_DCHECK(reader_); - - // BitBuffer and BitBufferWriter read/write higher bits before lower bits. - - const size_t lower_bit_count = - std::min<uint64_t>(params_.delta_width_bits(), 32u); - const size_t higher_bit_count = (params_.delta_width_bits() <= 32u) - ? 0 - : params_.delta_width_bits() - 32u; - - uint32_t lower_bits; - uint32_t higher_bits; - - if (higher_bit_count > 0) { - if (!reader_->ReadBits(&higher_bits, higher_bit_count)) { - RTC_LOG(LS_WARNING) << "Failed to read higher half of delta."; - return false; - } - } else { - higher_bits = 0; - } - - if (!reader_->ReadBits(&lower_bits, lower_bit_count)) { - RTC_LOG(LS_WARNING) << "Failed to read lower half of delta."; - return false; + if (!reader_.Ok()) { + values = {}; } - const uint64_t lower_bits_64 = static_cast<uint64_t>(lower_bits); - const uint64_t higher_bits_64 = static_cast<uint64_t>(higher_bits); - - *delta = (higher_bits_64 << 32) | lower_bits_64; - return true; + return values; } uint64_t FixedLengthDeltaDecoder::ApplyDelta(uint64_t base, @@ -940,7 +805,7 @@ std::string EncodeDeltas(absl::optional<uint64_t> base, } std::vector<absl::optional<uint64_t>> DecodeDeltas( - const std::string& input, + 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. diff --git a/logging/rtc_event_log/encoder/delta_encoding.h b/logging/rtc_event_log/encoder/delta_encoding.h index 5e86a986f6..779cdc6b2f 100644 --- a/logging/rtc_event_log/encoder/delta_encoding.h +++ b/logging/rtc_event_log/encoder/delta_encoding.h @@ -17,14 +17,15 @@ #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. +// 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 +// `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). @@ -34,12 +35,12 @@ std::string EncodeDeltas(absl::optional<uint64_t> base, // 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 +// `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( - const std::string& input, + absl::string_view input, absl::optional<uint64_t> base, size_t num_of_deltas); diff --git a/logging/rtc_event_log/encoder/delta_encoding_unittest.cc b/logging/rtc_event_log/encoder/delta_encoding_unittest.cc index b385b8998a..d0f7fb93db 100644 --- a/logging/rtc_event_log/encoder/delta_encoding_unittest.cc +++ b/logging/rtc_event_log/encoder/delta_encoding_unittest.cc @@ -44,7 +44,7 @@ void MaybeSetSignedness(DeltaSignedness signedness) { SetFixedLengthEncoderDeltaSignednessForTesting(true); return; } - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); } uint64_t RandomWithMaxBitWidth(Random* prng, uint64_t max_width) { @@ -64,9 +64,9 @@ uint64_t RandomWithMaxBitWidth(Random* prng, uint64_t max_width) { } } -// Encodes |values| based on |base|, then decodes the result and makes sure +// 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 +// If `encoded_string` is non-null, the encoded result will also be written // into it. void TestEncodingAndDecoding( absl::optional<uint64_t> base, @@ -100,7 +100,7 @@ std::vector<absl::optional<uint64_t>> CreateSequenceByLastValue( return result; } -// If |sequence_length| is greater than the number of deltas, the sequence of +// 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, @@ -141,7 +141,7 @@ size_t EncodingLengthUpperBound(size_t delta_max_bit_width, 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 +// 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, @@ -502,7 +502,7 @@ TEST_P(DeltaEncodingCompressionQualityTest, uint64_t last_element[arraysize(bases)]; memcpy(last_element, bases, sizeof(bases)); - // Avoid empty |deltas| due to first element causing wrap-around. + // 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; diff --git a/logging/rtc_event_log/encoder/rtc_event_log_encoder_common.h b/logging/rtc_event_log/encoder/rtc_event_log_encoder_common.h index 429f8ed2ad..c167a8eb8f 100644 --- a/logging/rtc_event_log/encoder/rtc_event_log_encoder_common.h +++ b/logging/rtc_event_log/encoder/rtc_event_log_encoder_common.h @@ -55,7 +55,7 @@ uint64_t ToUnsigned(T y) { } } -// Assuming x = ToUnsigned(y), return |y|. +// 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 @@ -74,7 +74,7 @@ bool ToSigned(uint64_t x, T* y) { 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. + return false; // `x` cannot be represented using a T. } if (x <= static_cast<uint64_t>(MAX_T)) { diff --git a/logging/rtc_event_log/encoder/rtc_event_log_encoder_legacy.cc b/logging/rtc_event_log/encoder/rtc_event_log_encoder_legacy.cc index 2f1c5a4533..9bc770849c 100644 --- a/logging/rtc_event_log/encoder/rtc_event_log_encoder_legacy.cc +++ b/logging/rtc_event_log/encoder/rtc_event_log_encoder_legacy.cc @@ -15,6 +15,8 @@ #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" @@ -30,6 +32,7 @@ #include "logging/rtc_event_log/events/rtc_event_probe_cluster_created.h" #include "logging/rtc_event_log/events/rtc_event_probe_result_failure.h" #include "logging/rtc_event_log/events/rtc_event_probe_result_success.h" +#include "logging/rtc_event_log/events/rtc_event_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" @@ -38,12 +41,10 @@ #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/remote_bitrate_estimator/include/bwe_defines.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_jitter_report.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" @@ -77,9 +78,9 @@ rtclog::DelayBasedBweUpdate::DetectorState ConvertDetectorState( case BandwidthUsage::kBwOverusing: return rtclog::DelayBasedBweUpdate::BWE_OVERUSING; case BandwidthUsage::kLast: - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); } - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return rtclog::DelayBasedBweUpdate::BWE_NORMAL; } @@ -93,9 +94,9 @@ rtclog::BweProbeResult::ResultType ConvertProbeResultType( case ProbeFailureReason::kTimeout: return rtclog::BweProbeResult::TIMEOUT; case ProbeFailureReason::kLast: - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); } - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return rtclog::BweProbeResult::SUCCESS; } @@ -106,9 +107,9 @@ rtclog::VideoReceiveConfig_RtcpMode ConvertRtcpMode(RtcpMode rtcp_mode) { case RtcpMode::kReducedSize: return rtclog::VideoReceiveConfig::RTCP_REDUCEDSIZE; case RtcpMode::kOff: - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); } - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return rtclog::VideoReceiveConfig::RTCP_COMPOUND; } @@ -124,9 +125,9 @@ ConvertIceCandidatePairConfigType(IceCandidatePairConfigType type) { case IceCandidatePairConfigType::kSelected: return rtclog::IceCandidatePairConfig::SELECTED; case IceCandidatePairConfigType::kNumValues: - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); } - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return rtclog::IceCandidatePairConfig::ADDED; } @@ -144,9 +145,9 @@ rtclog::IceCandidatePairConfig::IceCandidateType ConvertIceCandidateType( case IceCandidateType::kRelay: return rtclog::IceCandidatePairConfig::RELAY; case IceCandidateType::kNumValues: - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); } - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return rtclog::IceCandidatePairConfig::UNKNOWN_CANDIDATE_TYPE; } @@ -164,9 +165,9 @@ rtclog::IceCandidatePairConfig::Protocol ConvertIceCandidatePairProtocol( case IceCandidatePairProtocol::kTls: return rtclog::IceCandidatePairConfig::TLS; case IceCandidatePairProtocol::kNumValues: - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); } - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return rtclog::IceCandidatePairConfig::UNKNOWN_PROTOCOL; } @@ -181,9 +182,9 @@ ConvertIceCandidatePairAddressFamily( case IceCandidatePairAddressFamily::kIpv6: return rtclog::IceCandidatePairConfig::IPV6; case IceCandidatePairAddressFamily::kNumValues: - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); } - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return rtclog::IceCandidatePairConfig::UNKNOWN_ADDRESS_FAMILY; } @@ -203,9 +204,9 @@ rtclog::IceCandidatePairConfig::NetworkType ConvertIceCandidateNetworkType( case IceCandidateNetworkType::kCellular: return rtclog::IceCandidatePairConfig::CELLULAR; case IceCandidateNetworkType::kNumValues: - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); } - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return rtclog::IceCandidatePairConfig::UNKNOWN_NETWORK_TYPE; } @@ -221,9 +222,9 @@ ConvertIceCandidatePairEventType(IceCandidatePairEventType type) { case IceCandidatePairEventType::kCheckResponseReceived: return rtclog::IceCandidatePairEvent::CHECK_RESPONSE_RECEIVED; case IceCandidatePairEventType::kNumValues: - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); } - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return rtclog::IceCandidatePairEvent::CHECK_SENT; } @@ -331,6 +332,11 @@ std::string RtcEventLogEncoderLegacy::Encode(const RtcEvent& 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); @@ -362,17 +368,23 @@ std::string RtcEventLogEncoderLegacy::Encode(const RtcEvent& 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::RouteChangeEvent: - case RtcEvent::Type::RemoteEstimateEvent: case RtcEvent::Type::GenericPacketReceived: case RtcEvent::Type::GenericPacketSent: case RtcEvent::Type::GenericAckReceived: + case RtcEvent::Type::FrameDecoded: // These are unsupported in the old format, but shouldn't crash. return ""; } int event_type = static_cast<int>(event.GetType()); - RTC_NOTREACHED() << "Unknown event type (" << event_type << ")"; + RTC_DCHECK_NOTREACHED() << "Unknown event type (" << event_type << ")"; return ""; } @@ -580,6 +592,23 @@ std::string RtcEventLogEncoderLegacy::EncodeProbeResultSuccess( 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); @@ -592,14 +621,14 @@ std::string RtcEventLogEncoderLegacy::EncodeRtcpPacketOutgoing( std::string RtcEventLogEncoderLegacy::EncodeRtpPacketIncoming( const RtcEventRtpPacketIncoming& event) { - return EncodeRtpPacket(event.timestamp_us(), event.header(), + 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.header(), + return EncodeRtpPacket(event.timestamp_us(), event.RawHeader(), event.packet_length(), event.probe_cluster_id(), false); } @@ -672,7 +701,7 @@ std::string RtcEventLogEncoderLegacy::EncodeVideoSendStreamConfig( encoder->set_payload_type(codec.payload_type); if (event.config().codecs.size() > 1) { - RTC_LOG(WARNING) + RTC_LOG(LS_WARNING) << "LogVideoSendStreamConfig currently only supports one " "codec. Logging codec :" << codec.payload_name; @@ -695,8 +724,7 @@ std::string RtcEventLogEncoderLegacy::EncodeRtcpPacket( rtcp::CommonHeader header; const uint8_t* block_begin = packet.data(); const uint8_t* packet_end = packet.data() + packet.size(); - RTC_DCHECK(packet.size() <= IP_PACKET_SIZE); - uint8_t buffer[IP_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)) { @@ -706,16 +734,14 @@ std::string RtcEventLogEncoderLegacy::EncodeRtcpPacket( uint32_t block_size = next_block - block_begin; switch (header.type()) { case rtcp::Bye::kPacketType: - case rtcp::ExtendedJitterReport::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 - // inter-arrival jitter, third-party loss reports, payload-specific - // feedback and extended reports. - memcpy(buffer + buffer_length, block_begin, block_size); + // 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: @@ -728,14 +754,15 @@ std::string RtcEventLogEncoderLegacy::EncodeRtcpPacket( block_begin += block_size; } - rtclog_event.mutable_rtcp_packet()->set_packet_data(buffer, buffer_length); + rtclog_event.mutable_rtcp_packet()->set_packet_data(buffer.data(), + buffer_length); return Serialize(&rtclog_event); } std::string RtcEventLogEncoderLegacy::EncodeRtpPacket( int64_t timestamp_us, - const webrtc::RtpPacket& header, + rtc::ArrayView<const uint8_t> header, size_t packet_length, int probe_cluster_id, bool is_incoming) { diff --git a/logging/rtc_event_log/encoder/rtc_event_log_encoder_legacy.h b/logging/rtc_event_log/encoder/rtc_event_log_encoder_legacy.h index 3105dc1e68..33c530789b 100644 --- a/logging/rtc_event_log/encoder/rtc_event_log_encoder_legacy.h +++ b/logging/rtc_event_log/encoder/rtc_event_log_encoder_legacy.h @@ -15,6 +15,7 @@ #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" @@ -24,6 +25,7 @@ namespace rtclog { class Event; // Auto-generated from protobuf. } // namespace rtclog +class RtcEventAlrState; class RtcEventAudioNetworkAdaptation; class RtcEventAudioPlayout; class RtcEventAudioReceiveStreamConfig; @@ -37,13 +39,13 @@ class RtcEventLoggingStopped; class RtcEventProbeClusterCreated; class RtcEventProbeResultFailure; class RtcEventProbeResultSuccess; +class RtcEventRemoteEstimate; class RtcEventRtcpPacketIncoming; class RtcEventRtcpPacketOutgoing; class RtcEventRtpPacketIncoming; class RtcEventRtpPacketOutgoing; class RtcEventVideoReceiveStreamConfig; class RtcEventVideoSendStreamConfig; -class RtcEventAlrState; class RtpPacket; class RtcEventLogEncoderLegacy final : public RtcEventLogEncoder { @@ -80,6 +82,7 @@ class RtcEventLogEncoderLegacy final : public RtcEventLogEncoder { 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); @@ -94,7 +97,7 @@ class RtcEventLogEncoderLegacy final : public RtcEventLogEncoder { const rtc::Buffer& packet, bool is_incoming); std::string EncodeRtpPacket(int64_t timestamp_us, - const RtpPacket& header, + rtc::ArrayView<const uint8_t> header, size_t packet_length, int probe_cluster_id, bool is_incoming); diff --git a/logging/rtc_event_log/encoder/rtc_event_log_encoder_new_format.cc b/logging/rtc_event_log/encoder/rtc_event_log_encoder_new_format.cc index 70c7f37356..9d791d1aca 100644 --- a/logging/rtc_event_log/encoder/rtc_event_log_encoder_new_format.cc +++ b/logging/rtc_event_log/encoder/rtc_event_log_encoder_new_format.cc @@ -12,6 +12,7 @@ #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" @@ -24,6 +25,7 @@ #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" @@ -42,13 +44,11 @@ #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/remote_bitrate_estimator/include/bwe_defines.h" #include "modules/rtp_rtcp/include/rtp_cvo.h" #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" #include "modules/rtp_rtcp/source/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_jitter_report.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" @@ -85,12 +85,32 @@ rtclog2::DelayBasedBweUpdates::DetectorState ConvertToProtoFormat( case BandwidthUsage::kBwOverusing: return rtclog2::DelayBasedBweUpdates::BWE_OVERUSING; case BandwidthUsage::kLast: - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); } - RTC_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) { @@ -101,16 +121,16 @@ rtclog2::BweProbeResultFailure::FailureReason ConvertToProtoFormat( case ProbeFailureReason::kTimeout: return rtclog2::BweProbeResultFailure::TIMEOUT; case ProbeFailureReason::kLast: - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); } - RTC_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|. +// `proto_config`. bool ConvertToProtoFormat(const std::vector<RtpExtension>& extensions, rtclog2::RtpHeaderExtensionConfig* proto_config) { size_t unknown_extensions = 0; @@ -146,9 +166,9 @@ rtclog2::DtlsTransportStateEvent::DtlsTransportState ConvertToProtoFormat( case webrtc::DtlsTransportState::kFailed: return rtclog2::DtlsTransportStateEvent::DTLS_TRANSPORT_FAILED; case webrtc::DtlsTransportState::kNumValues: - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); } - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return rtclog2::DtlsTransportStateEvent::UNKNOWN_DTLS_TRANSPORT_STATE; } @@ -164,9 +184,9 @@ ConvertToProtoFormat(IceCandidatePairConfigType type) { case IceCandidatePairConfigType::kSelected: return rtclog2::IceCandidatePairConfig::SELECTED; case IceCandidatePairConfigType::kNumValues: - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); } - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return rtclog2::IceCandidatePairConfig::UNKNOWN_CONFIG_TYPE; } @@ -184,9 +204,9 @@ rtclog2::IceCandidatePairConfig::IceCandidateType ConvertToProtoFormat( case IceCandidateType::kRelay: return rtclog2::IceCandidatePairConfig::RELAY; case IceCandidateType::kNumValues: - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); } - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return rtclog2::IceCandidatePairConfig::UNKNOWN_CANDIDATE_TYPE; } @@ -204,9 +224,9 @@ rtclog2::IceCandidatePairConfig::Protocol ConvertToProtoFormat( case IceCandidatePairProtocol::kTls: return rtclog2::IceCandidatePairConfig::TLS; case IceCandidatePairProtocol::kNumValues: - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); } - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return rtclog2::IceCandidatePairConfig::UNKNOWN_PROTOCOL; } @@ -220,9 +240,9 @@ rtclog2::IceCandidatePairConfig::AddressFamily ConvertToProtoFormat( case IceCandidatePairAddressFamily::kIpv6: return rtclog2::IceCandidatePairConfig::IPV6; case IceCandidatePairAddressFamily::kNumValues: - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); } - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return rtclog2::IceCandidatePairConfig::UNKNOWN_ADDRESS_FAMILY; } @@ -242,9 +262,9 @@ rtclog2::IceCandidatePairConfig::NetworkType ConvertToProtoFormat( case IceCandidateNetworkType::kCellular: return rtclog2::IceCandidatePairConfig::CELLULAR; case IceCandidateNetworkType::kNumValues: - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); } - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return rtclog2::IceCandidatePairConfig::UNKNOWN_NETWORK_TYPE; } @@ -260,18 +280,16 @@ rtclog2::IceCandidatePairEvent::IceCandidatePairEventType ConvertToProtoFormat( case IceCandidatePairEventType::kCheckResponseReceived: return rtclog2::IceCandidatePairEvent::CHECK_RESPONSE_RECEIVED; case IceCandidatePairEventType::kNumValues: - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); } - RTC_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 |IP_PACKET_SIZE| bytes. |packet| must -// be at most |IP_PACKET_SIZE| bytes long. -size_t RemoveNonWhitelistedRtcpBlocks(const rtc::Buffer& packet, +// 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(packet.size() <= IP_PACKET_SIZE); RTC_DCHECK(buffer != nullptr); rtcp::CommonHeader header; const uint8_t* block_begin = packet.data(); @@ -287,17 +305,15 @@ size_t RemoveNonWhitelistedRtcpBlocks(const rtc::Buffer& packet, size_t block_size = next_block - block_begin; switch (header.type()) { case rtcp::Bye::kPacketType: - case rtcp::ExtendedJitterReport::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 - // inter-arrival jitter, third-party loss reports, payload-specific - // feedback and extended reports. + // 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 whitelisted types. + // in the packet are allowlisted types. memcpy(buffer + buffer_length, block_begin, block_size); buffer_length += block_size; break; @@ -325,10 +341,10 @@ void EncodeRtcpPacket(rtc::ArrayView<const EventType*> batch, const EventType* const base_event = batch[0]; proto_batch->set_timestamp_ms(base_event->timestamp_ms()); { - uint8_t buffer[IP_PACKET_SIZE]; + std::vector<uint8_t> buffer(base_event->packet().size()); size_t buffer_length = - RemoveNonWhitelistedRtcpBlocks(base_event->packet(), buffer); - proto_batch->set_raw_packet(buffer, buffer_length); + RemoveNonAllowlistedRtcpBlocks(base_event->packet(), buffer.data()); + proto_batch->set_raw_packet(buffer.data(), buffer_length); } if (batch.size() == 1) { @@ -356,7 +372,7 @@ void EncodeRtcpPacket(rtc::ArrayView<const EventType*> batch, 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 = RemoveNonWhitelistedRtcpBlocks( + 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); @@ -375,12 +391,12 @@ void EncodeRtpPacket(const std::vector<const EventType*>& batch, // Base event const EventType* const base_event = batch[0]; proto_batch->set_timestamp_ms(base_event->timestamp_ms()); - proto_batch->set_marker(base_event->header().Marker()); + proto_batch->set_marker(base_event->Marker()); // TODO(terelius): Is payload type needed? - proto_batch->set_payload_type(base_event->header().PayloadType()); - proto_batch->set_sequence_number(base_event->header().SequenceNumber()); - proto_batch->set_rtp_timestamp(base_event->header().Timestamp()); - proto_batch->set_ssrc(base_event->header().Ssrc()); + 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()); @@ -389,8 +405,7 @@ void EncodeRtpPacket(const std::vector<const EventType*>& batch, absl::optional<uint64_t> base_transport_sequence_number; { uint16_t seqnum; - if (base_event->header().template GetExtension<TransportSequenceNumber>( - &seqnum)) { + if (base_event->template GetExtension<TransportSequenceNumber>(&seqnum)) { proto_batch->set_transport_sequence_number(seqnum); base_transport_sequence_number = seqnum; } @@ -399,8 +414,7 @@ void EncodeRtpPacket(const std::vector<const EventType*>& batch, absl::optional<uint64_t> unsigned_base_transmission_time_offset; { int32_t offset; - if (base_event->header().template GetExtension<TransmissionOffset>( - &offset)) { + if (base_event->template GetExtension<TransmissionOffset>(&offset)) { proto_batch->set_transmission_time_offset(offset); unsigned_base_transmission_time_offset = ToUnsigned(offset); } @@ -409,8 +423,7 @@ void EncodeRtpPacket(const std::vector<const EventType*>& batch, absl::optional<uint64_t> base_absolute_send_time; { uint32_t sendtime; - if (base_event->header().template GetExtension<AbsoluteSendTime>( - &sendtime)) { + if (base_event->template GetExtension<AbsoluteSendTime>(&sendtime)) { proto_batch->set_absolute_send_time(sendtime); base_absolute_send_time = sendtime; } @@ -419,8 +432,7 @@ void EncodeRtpPacket(const std::vector<const EventType*>& batch, absl::optional<uint64_t> base_video_rotation; { VideoRotation video_rotation; - if (base_event->header().template GetExtension<VideoOrientation>( - &video_rotation)) { + if (base_event->template GetExtension<VideoOrientation>(&video_rotation)) { proto_batch->set_video_rotation( ConvertVideoRotationToCVOByte(video_rotation)); base_video_rotation = ConvertVideoRotationToCVOByte(video_rotation); @@ -432,8 +444,8 @@ void EncodeRtpPacket(const std::vector<const EventType*>& batch, { bool voice_activity; uint8_t audio_level; - if (base_event->header().template GetExtension<AudioLevel>(&voice_activity, - &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); @@ -465,9 +477,9 @@ void EncodeRtpPacket(const std::vector<const EventType*>& batch, // marker (RTP base) for (size_t i = 0; i < values.size(); ++i) { const EventType* event = batch[i + 1]; - values[i] = event->header().Marker(); + values[i] = event->Marker(); } - encoded_deltas = EncodeDeltas(base_event->header().Marker(), values); + encoded_deltas = EncodeDeltas(base_event->Marker(), values); if (!encoded_deltas.empty()) { proto_batch->set_marker_deltas(encoded_deltas); } @@ -475,9 +487,9 @@ void EncodeRtpPacket(const std::vector<const EventType*>& batch, // payload_type (RTP base) for (size_t i = 0; i < values.size(); ++i) { const EventType* event = batch[i + 1]; - values[i] = event->header().PayloadType(); + values[i] = event->PayloadType(); } - encoded_deltas = EncodeDeltas(base_event->header().PayloadType(), values); + encoded_deltas = EncodeDeltas(base_event->PayloadType(), values); if (!encoded_deltas.empty()) { proto_batch->set_payload_type_deltas(encoded_deltas); } @@ -485,9 +497,9 @@ void EncodeRtpPacket(const std::vector<const EventType*>& batch, // sequence_number (RTP base) for (size_t i = 0; i < values.size(); ++i) { const EventType* event = batch[i + 1]; - values[i] = event->header().SequenceNumber(); + values[i] = event->SequenceNumber(); } - encoded_deltas = EncodeDeltas(base_event->header().SequenceNumber(), values); + encoded_deltas = EncodeDeltas(base_event->SequenceNumber(), values); if (!encoded_deltas.empty()) { proto_batch->set_sequence_number_deltas(encoded_deltas); } @@ -495,9 +507,9 @@ void EncodeRtpPacket(const std::vector<const EventType*>& batch, // rtp_timestamp (RTP base) for (size_t i = 0; i < values.size(); ++i) { const EventType* event = batch[i + 1]; - values[i] = event->header().Timestamp(); + values[i] = event->Timestamp(); } - encoded_deltas = EncodeDeltas(base_event->header().Timestamp(), values); + encoded_deltas = EncodeDeltas(base_event->Timestamp(), values); if (!encoded_deltas.empty()) { proto_batch->set_rtp_timestamp_deltas(encoded_deltas); } @@ -505,9 +517,9 @@ void EncodeRtpPacket(const std::vector<const EventType*>& batch, // ssrc (RTP base) for (size_t i = 0; i < values.size(); ++i) { const EventType* event = batch[i + 1]; - values[i] = event->header().Ssrc(); + values[i] = event->Ssrc(); } - encoded_deltas = EncodeDeltas(base_event->header().Ssrc(), values); + encoded_deltas = EncodeDeltas(base_event->Ssrc(), values); if (!encoded_deltas.empty()) { proto_batch->set_ssrc_deltas(encoded_deltas); } @@ -546,8 +558,7 @@ void EncodeRtpPacket(const std::vector<const EventType*>& batch, for (size_t i = 0; i < values.size(); ++i) { const EventType* event = batch[i + 1]; uint16_t seqnum; - if (event->header().template GetExtension<TransportSequenceNumber>( - &seqnum)) { + if (event->template GetExtension<TransportSequenceNumber>(&seqnum)) { values[i] = seqnum; } else { values[i].reset(); @@ -562,7 +573,7 @@ void EncodeRtpPacket(const std::vector<const EventType*>& batch, for (size_t i = 0; i < values.size(); ++i) { const EventType* event = batch[i + 1]; int32_t offset; - if (event->header().template GetExtension<TransmissionOffset>(&offset)) { + if (event->template GetExtension<TransmissionOffset>(&offset)) { values[i] = ToUnsigned(offset); } else { values[i].reset(); @@ -577,7 +588,7 @@ void EncodeRtpPacket(const std::vector<const EventType*>& batch, for (size_t i = 0; i < values.size(); ++i) { const EventType* event = batch[i + 1]; uint32_t sendtime; - if (event->header().template GetExtension<AbsoluteSendTime>(&sendtime)) { + if (event->template GetExtension<AbsoluteSendTime>(&sendtime)) { values[i] = sendtime; } else { values[i].reset(); @@ -592,8 +603,7 @@ void EncodeRtpPacket(const std::vector<const EventType*>& batch, for (size_t i = 0; i < values.size(); ++i) { const EventType* event = batch[i + 1]; VideoRotation video_rotation; - if (event->header().template GetExtension<VideoOrientation>( - &video_rotation)) { + if (event->template GetExtension<VideoOrientation>(&video_rotation)) { values[i] = ConvertVideoRotationToCVOByte(video_rotation); } else { values[i].reset(); @@ -609,8 +619,8 @@ void EncodeRtpPacket(const std::vector<const EventType*>& batch, const EventType* event = batch[i + 1]; bool voice_activity; uint8_t audio_level; - if (event->header().template GetExtension<AudioLevel>(&voice_activity, - &audio_level)) { + if (event->template GetExtension<AudioLevel>(&voice_activity, + &audio_level)) { RTC_DCHECK_LE(audio_level, 0x7Fu); values[i] = audio_level; } else { @@ -627,8 +637,8 @@ void EncodeRtpPacket(const std::vector<const EventType*>& batch, const EventType* event = batch[i + 1]; bool voice_activity; uint8_t audio_level; - if (event->header().template GetExtension<AudioLevel>(&voice_activity, - &audio_level)) { + if (event->template GetExtension<AudioLevel>(&voice_activity, + &audio_level)) { RTC_DCHECK_LE(audio_level, 0x7Fu); values[i] = voice_activity; } else { @@ -677,6 +687,8 @@ std::string RtcEventLogEncoderNewFormat::EncodeBatch( 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; @@ -802,14 +814,14 @@ std::string RtcEventLogEncoderNewFormat::EncodeBatch( case RtcEvent::Type::RtpPacketIncoming: { auto* rtc_event = static_cast<const RtcEventRtpPacketIncoming* const>(it->get()); - auto& v = incoming_rtp_packets[rtc_event->header().Ssrc()]; + 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->header().Ssrc()]; + auto& v = outgoing_rtp_packets[rtc_event->Ssrc()]; v.emplace_back(rtc_event); break; } @@ -859,6 +871,18 @@ std::string RtcEventLogEncoderNewFormat::EncodeBatch( 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::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; } } @@ -872,6 +896,9 @@ std::string RtcEventLogEncoderNewFormat::EncodeBatch( 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); @@ -932,7 +959,7 @@ void RtcEventLogEncoderNewFormat::EncodeAudioNetworkAdaptation( 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, + // 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()) @@ -1377,7 +1404,7 @@ void RtcEventLogEncoderNewFormat::EncodeRemoteEstimate( // link_capacity_lower_kbps for (size_t i = 0; i < values.size(); ++i) { const auto* event = batch[i + 1]; - if (base_event->link_capacity_lower_.IsFinite()) { + if (event->link_capacity_lower_.IsFinite()) { values[i] = event->link_capacity_lower_.kbps<uint32_t>(); } else { values[i].reset(); @@ -1391,7 +1418,7 @@ void RtcEventLogEncoderNewFormat::EncodeRemoteEstimate( // link_capacity_upper_kbps for (size_t i = 0; i < values.size(); ++i) { const auto* event = batch[i + 1]; - if (base_event->link_capacity_upper_.IsFinite()) { + if (event->link_capacity_upper_.IsFinite()) { values[i] = event->link_capacity_upper_.kbps<uint32_t>(); } else { values[i].reset(); @@ -1431,6 +1458,105 @@ void RtcEventLogEncoderNewFormat::EncodeRtpPacketIncoming( } } +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) { diff --git a/logging/rtc_event_log/encoder/rtc_event_log_encoder_new_format.h b/logging/rtc_event_log/encoder/rtc_event_log_encoder_new_format.h index d25184ec4a..6af34bc6cd 100644 --- a/logging/rtc_event_log/encoder/rtc_event_log_encoder_new_format.h +++ b/logging/rtc_event_log/encoder/rtc_event_log_encoder_new_format.h @@ -51,6 +51,7 @@ class RtcEventVideoSendStreamConfig; class RtcEventIceCandidatePairConfig; class RtcEventIceCandidatePair; class RtpPacket; +class RtcEventFrameDecoded; class RtcEventGenericAckReceived; class RtcEventGenericPacketReceived; class RtcEventGenericPacketSent; @@ -94,6 +95,9 @@ class RtcEventLogEncoderNewFormat final : public RtcEventLogEncoder { 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); diff --git a/logging/rtc_event_log/encoder/rtc_event_log_encoder_unittest.cc b/logging/rtc_event_log/encoder/rtc_event_log_encoder_unittest.cc index cf85775f52..c910003e29 100644 --- a/logging/rtc_event_log/encoder/rtc_event_log_encoder_unittest.cc +++ b/logging/rtc_event_log/encoder/rtc_event_log_encoder_unittest.cc @@ -16,6 +16,7 @@ #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" @@ -35,7 +36,7 @@ #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/remote_bitrate_estimator/include/bwe_defines.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" @@ -43,21 +44,30 @@ namespace webrtc { class RtcEventLogEncoderTest - : public ::testing::TestWithParam<std::tuple<int, bool, size_t, bool>> { + : public ::testing::TestWithParam< + std::tuple<int, RtcEventLog::EncodingType, size_t, bool>> { protected: RtcEventLogEncoderTest() : seed_(std::get<0>(GetParam())), prng_(seed_), - new_encoding_(std::get<1>(GetParam())), + encoding_type_(std::get<1>(GetParam())), event_count_(std::get<2>(GetParam())), force_repeated_fields_(std::get<3>(GetParam())), gen_(seed_ * 880001UL), - verifier_(new_encoding_ ? RtcEventLog::EncodingType::NewFormat - : RtcEventLog::EncodingType::Legacy) { - if (new_encoding_) - encoder_ = std::make_unique<RtcEventLogEncoderNewFormat>(); - else - encoder_ = std::make_unique<RtcEventLogEncoderLegacy>(); + 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; @@ -85,11 +95,12 @@ class RtcEventLogEncoderTest ParsedRtcEventLog parsed_log_; const uint64_t seed_; Random prng_; - const bool new_encoding_; + 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( @@ -101,8 +112,8 @@ void RtcEventLogEncoderTest::TestRtcEventAudioNetworkAdaptation( history_.push_back(event->Copy()); } - std::string encoded = encoder_->EncodeBatch(history_.begin(), history_.end()); - ASSERT_TRUE(parsed_log_.ParseString(encoded).ok()); + 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()); @@ -163,11 +174,11 @@ void RtcEventLogEncoderTest::TestRtpPackets() { // TODO(terelius): Test extensions for legacy encoding, too. RtpHeaderExtensionMap extension_map; - if (new_encoding_) { + if (encoding_type_ != RtcEventLog::EncodingType::Legacy) { extension_map = gen_.NewRtpHeaderExtensionMap(true); } - // Simulate |event_count_| RTP packets, with SSRCs assigned randomly + // 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) { @@ -181,8 +192,8 @@ void RtcEventLogEncoderTest::TestRtpPackets() { } // Encode and parse. - std::string encoded = encoder_->EncodeBatch(history_.begin(), history_.end()); - ASSERT_TRUE(parsed_log_.ParseString(encoded).ok()); + 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. @@ -208,8 +219,8 @@ TEST_P(RtcEventLogEncoderTest, RtcEventAlrState) { history_.push_back(events[i]->Copy()); } - std::string encoded = encoder_->EncodeBatch(history_.begin(), history_.end()); - ASSERT_TRUE(parsed_log_.ParseString(encoded).ok()); + 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_); @@ -219,7 +230,7 @@ TEST_P(RtcEventLogEncoderTest, RtcEventAlrState) { } TEST_P(RtcEventLogEncoderTest, RtcEventRouteChange) { - if (!new_encoding_) { + if (encoding_type_ == RtcEventLog::EncodingType::Legacy) { return; } std::vector<std::unique_ptr<RtcEventRouteChange>> events(event_count_); @@ -229,8 +240,8 @@ TEST_P(RtcEventLogEncoderTest, RtcEventRouteChange) { history_.push_back(events[i]->Copy()); } - std::string encoded = encoder_->EncodeBatch(history_.begin(), history_.end()); - ASSERT_TRUE(parsed_log_.ParseString(encoded).ok()); + 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_); @@ -240,9 +251,6 @@ TEST_P(RtcEventLogEncoderTest, RtcEventRouteChange) { } TEST_P(RtcEventLogEncoderTest, RtcEventRemoteEstimate) { - if (!new_encoding_) { - return; - } 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_) @@ -251,8 +259,8 @@ TEST_P(RtcEventLogEncoderTest, RtcEventRemoteEstimate) { history_.push_back(std::make_unique<RtcEventRemoteEstimate>(*events[i])); } - std::string encoded = encoder_->EncodeBatch(history_.begin(), history_.end()); - ASSERT_TRUE(parsed_log_.ParseString(encoded).ok()); + 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_); @@ -405,8 +413,8 @@ TEST_P(RtcEventLogEncoderTest, RtcEventAudioPlayout) { original_events_by_ssrc[ssrc].push_back(std::move(event)); } - std::string encoded = encoder_->EncodeBatch(history_.begin(), history_.end()); - ASSERT_TRUE(parsed_log_.ParseString(encoded).ok()); + 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(); @@ -441,8 +449,8 @@ TEST_P(RtcEventLogEncoderTest, RtcEventAudioReceiveStreamConfig) { gen_.NewAudioReceiveStreamConfig(ssrc, extensions); history_.push_back(event->Copy()); - std::string encoded = encoder_->EncodeBatch(history_.begin(), history_.end()); - ASSERT_TRUE(parsed_log_.ParseString(encoded).ok()); + 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); @@ -457,8 +465,8 @@ TEST_P(RtcEventLogEncoderTest, RtcEventAudioSendStreamConfig) { gen_.NewAudioSendStreamConfig(ssrc, extensions); history_.push_back(event->Copy()); - std::string encoded = encoder_->EncodeBatch(history_.begin(), history_.end()); - ASSERT_TRUE(parsed_log_.ParseString(encoded).ok()); + 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); @@ -475,8 +483,8 @@ TEST_P(RtcEventLogEncoderTest, RtcEventBweUpdateDelayBased) { history_.push_back(events[i]->Copy()); } - std::string encoded = encoder_->EncodeBatch(history_.begin(), history_.end()); - ASSERT_TRUE(parsed_log_.ParseString(encoded).ok()); + 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_); @@ -495,8 +503,8 @@ TEST_P(RtcEventLogEncoderTest, RtcEventBweUpdateLossBased) { history_.push_back(events[i]->Copy()); } - std::string encoded = encoder_->EncodeBatch(history_.begin(), history_.end()); - ASSERT_TRUE(parsed_log_.ParseString(encoded).ok()); + 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_); @@ -507,7 +515,7 @@ TEST_P(RtcEventLogEncoderTest, RtcEventBweUpdateLossBased) { } TEST_P(RtcEventLogEncoderTest, RtcEventGenericPacketReceived) { - if (!new_encoding_) { + if (encoding_type_ == RtcEventLog::EncodingType::Legacy) { return; } std::vector<std::unique_ptr<RtcEventGenericPacketReceived>> events( @@ -519,8 +527,8 @@ TEST_P(RtcEventLogEncoderTest, RtcEventGenericPacketReceived) { history_.push_back(events[i]->Copy()); } - std::string encoded = encoder_->EncodeBatch(history_.begin(), history_.end()); - ASSERT_TRUE(parsed_log_.ParseString(encoded).ok()); + 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_); @@ -532,7 +540,7 @@ TEST_P(RtcEventLogEncoderTest, RtcEventGenericPacketReceived) { } TEST_P(RtcEventLogEncoderTest, RtcEventGenericPacketSent) { - if (!new_encoding_) { + if (encoding_type_ == RtcEventLog::EncodingType::Legacy) { return; } std::vector<std::unique_ptr<RtcEventGenericPacketSent>> events(event_count_); @@ -543,8 +551,8 @@ TEST_P(RtcEventLogEncoderTest, RtcEventGenericPacketSent) { history_.push_back(events[i]->Copy()); } - std::string encoded = encoder_->EncodeBatch(history_.begin(), history_.end()); - ASSERT_TRUE(parsed_log_.ParseString(encoded).ok()); + 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_); @@ -555,7 +563,7 @@ TEST_P(RtcEventLogEncoderTest, RtcEventGenericPacketSent) { } TEST_P(RtcEventLogEncoderTest, RtcEventGenericAcksReceived) { - if (!new_encoding_) { + if (encoding_type_ == RtcEventLog::EncodingType::Legacy) { return; } std::vector<std::unique_ptr<RtcEventGenericAckReceived>> events(event_count_); @@ -566,8 +574,8 @@ TEST_P(RtcEventLogEncoderTest, RtcEventGenericAcksReceived) { history_.push_back(events[i]->Copy()); } - std::string encoded = encoder_->EncodeBatch(history_.begin(), history_.end()); - ASSERT_TRUE(parsed_log_.ParseString(encoded).ok()); + 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_); @@ -586,12 +594,11 @@ TEST_P(RtcEventLogEncoderTest, RtcEventDtlsTransportState) { history_.push_back(events[i]->Copy()); } - const std::string encoded = - encoder_->EncodeBatch(history_.begin(), history_.end()); - ASSERT_TRUE(parsed_log_.ParseString(encoded).ok()); + 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 (!new_encoding_) { + if (encoding_type_ == RtcEventLog::EncodingType::Legacy) { ASSERT_EQ(dtls_transport_states.size(), 0u); return; } @@ -612,12 +619,11 @@ TEST_P(RtcEventLogEncoderTest, RtcEventDtlsWritableState) { history_.push_back(events[i]->Copy()); } - const std::string encoded = - encoder_->EncodeBatch(history_.begin(), history_.end()); - ASSERT_TRUE(parsed_log_.ParseString(encoded).ok()); + 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 (!new_encoding_) { + if (encoding_type_ == RtcEventLog::EncodingType::Legacy) { ASSERT_EQ(dtls_writable_states.size(), 0u); return; } @@ -630,14 +636,68 @@ TEST_P(RtcEventLogEncoderTest, RtcEventDtlsWritableState) { } } +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()); - std::string encoded = encoder_->EncodeBatch(history_.begin(), history_.end()); - ASSERT_TRUE(parsed_log_.ParseString(encoded).ok()); + 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(); @@ -651,8 +711,8 @@ TEST_P(RtcEventLogEncoderTest, RtcEventIceCandidatePair) { std::unique_ptr<RtcEventIceCandidatePair> event = gen_.NewIceCandidatePair(); history_.push_back(event->Copy()); - std::string encoded = encoder_->EncodeBatch(history_.begin(), history_.end()); - ASSERT_TRUE(parsed_log_.ParseString(encoded).ok()); + 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(); @@ -662,31 +722,35 @@ TEST_P(RtcEventLogEncoderTest, RtcEventIceCandidatePair) { } TEST_P(RtcEventLogEncoderTest, RtcEventLoggingStarted) { - const int64_t timestamp_us = rtc::TimeMicros(); - const int64_t utc_time_us = rtc::TimeUTCMicros(); + const int64_t timestamp_ms = prng_.Rand(1'000'000'000); + const int64_t utc_time_ms = prng_.Rand(1'000'000'000); - std::string encoded = encoder_->EncodeLogStart(timestamp_us, utc_time_us); - ASSERT_TRUE(parsed_log_.ParseString(encoded).ok()); + // 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_us, utc_time_us, + verifier_.VerifyLoggedStartEvent(timestamp_ms * 1000, utc_time_ms * 1000, start_log_events[0]); } TEST_P(RtcEventLogEncoderTest, RtcEventLoggingStopped) { - const int64_t start_timestamp_us = rtc::TimeMicros(); - const int64_t start_utc_time_us = rtc::TimeUTCMicros(); - std::string encoded = - encoder_->EncodeLogStart(start_timestamp_us, start_utc_time_us); - - const int64_t stop_timestamp_us = rtc::TimeMicros(); - encoded += encoder_->EncodeLogEnd(stop_timestamp_us); - ASSERT_TRUE(parsed_log_.ParseString(encoded).ok()); + 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_us, stop_log_events[0]); + verifier_.VerifyLoggedStopEvent(stop_timestamp_ms * 1000, stop_log_events[0]); } // TODO(eladalon/terelius): Test with multiple events in the batch. @@ -695,8 +759,8 @@ TEST_P(RtcEventLogEncoderTest, RtcEventProbeClusterCreated) { gen_.NewProbeClusterCreated(); history_.push_back(event->Copy()); - std::string encoded = encoder_->EncodeBatch(history_.begin(), history_.end()); - ASSERT_TRUE(parsed_log_.ParseString(encoded).ok()); + 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(); @@ -711,8 +775,8 @@ TEST_P(RtcEventLogEncoderTest, RtcEventProbeResultFailure) { gen_.NewProbeResultFailure(); history_.push_back(event->Copy()); - std::string encoded = encoder_->EncodeBatch(history_.begin(), history_.end()); - ASSERT_TRUE(parsed_log_.ParseString(encoded).ok()); + 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); @@ -726,8 +790,8 @@ TEST_P(RtcEventLogEncoderTest, RtcEventProbeResultSuccess) { gen_.NewProbeResultSuccess(); history_.push_back(event->Copy()); - std::string encoded = encoder_->EncodeBatch(history_.begin(), history_.end()); - ASSERT_TRUE(parsed_log_.ParseString(encoded).ok()); + 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); @@ -750,8 +814,8 @@ TEST_P(RtcEventLogEncoderTest, RtcEventRtcpPacketIncoming) { history_.push_back(events[i]->Copy()); } - std::string encoded = encoder_->EncodeBatch(history_.begin(), history_.end()); - ASSERT_TRUE(parsed_log_.ParseString(encoded).ok()); + 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_); @@ -771,8 +835,8 @@ TEST_P(RtcEventLogEncoderTest, RtcEventRtcpPacketOutgoing) { history_.push_back(events[i]->Copy()); } - std::string encoded = encoder_->EncodeBatch(history_.begin(), history_.end()); - ASSERT_TRUE(parsed_log_.ParseString(encoded).ok()); + 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_); @@ -793,9 +857,9 @@ TEST_P(RtcEventLogEncoderTest, RtcEventRtcpReceiverReport) { for (auto direction : {kIncomingPacket, kOutgoingPacket}) { std::vector<rtcp::ReceiverReport> events(event_count_); - std::vector<int64_t> timestamps_us(event_count_); + std::vector<int64_t> timestamps_ms(event_count_); for (size_t i = 0; i < event_count_; ++i) { - timestamps_us[i] = rtc::TimeMicros(); + timestamps_ms[i] = rtc::TimeMillis(); events[i] = gen_.NewReceiverReport(); rtc::Buffer buffer = events[i].Build(); if (direction == kIncomingPacket) { @@ -808,15 +872,14 @@ TEST_P(RtcEventLogEncoderTest, RtcEventRtcpReceiverReport) { fake_clock.AdvanceTime(TimeDelta::Millis(prng_.Rand(0, 1000))); } - std::string encoded = - encoder_->EncodeBatch(history_.begin(), history_.end()); - ASSERT_TRUE(parsed_log_.ParseString(encoded).ok()); + 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_us[i], events[i], + verifier_.VerifyLoggedReceiverReport(timestamps_ms[i], events[i], receiver_reports[i]); } } @@ -832,9 +895,9 @@ TEST_P(RtcEventLogEncoderTest, RtcEventRtcpSenderReport) { for (auto direction : {kIncomingPacket, kOutgoingPacket}) { std::vector<rtcp::SenderReport> events(event_count_); - std::vector<int64_t> timestamps_us(event_count_); + std::vector<int64_t> timestamps_ms(event_count_); for (size_t i = 0; i < event_count_; ++i) { - timestamps_us[i] = rtc::TimeMicros(); + timestamps_ms[i] = rtc::TimeMillis(); events[i] = gen_.NewSenderReport(); rtc::Buffer buffer = events[i].Build(); if (direction == kIncomingPacket) { @@ -847,15 +910,14 @@ TEST_P(RtcEventLogEncoderTest, RtcEventRtcpSenderReport) { fake_clock.AdvanceTime(TimeDelta::Millis(prng_.Rand(0, 1000))); } - std::string encoded = - encoder_->EncodeBatch(history_.begin(), history_.end()); - ASSERT_TRUE(parsed_log_.ParseString(encoded).ok()); + 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_us[i], events[i], + verifier_.VerifyLoggedSenderReport(timestamps_ms[i], events[i], sender_reports[i]); } } @@ -871,9 +933,9 @@ TEST_P(RtcEventLogEncoderTest, RtcEventRtcpExtendedReports) { for (auto direction : {kIncomingPacket, kOutgoingPacket}) { std::vector<rtcp::ExtendedReports> events(event_count_); - std::vector<int64_t> timestamps_us(event_count_); + std::vector<int64_t> timestamps_ms(event_count_); for (size_t i = 0; i < event_count_; ++i) { - timestamps_us[i] = rtc::TimeMicros(); + timestamps_ms[i] = rtc::TimeMillis(); events[i] = gen_.NewExtendedReports(); rtc::Buffer buffer = events[i].Build(); if (direction == kIncomingPacket) { @@ -886,15 +948,14 @@ TEST_P(RtcEventLogEncoderTest, RtcEventRtcpExtendedReports) { fake_clock.AdvanceTime(TimeDelta::Millis(prng_.Rand(0, 1000))); } - std::string encoded = - encoder_->EncodeBatch(history_.begin(), history_.end()); - ASSERT_TRUE(parsed_log_.ParseString(encoded).ok()); + 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_us[i], events[i], + verifier_.VerifyLoggedExtendedReports(timestamps_ms[i], events[i], extended_reports[i]); } } @@ -910,9 +971,9 @@ TEST_P(RtcEventLogEncoderTest, RtcEventRtcpFir) { for (auto direction : {kIncomingPacket, kOutgoingPacket}) { std::vector<rtcp::Fir> events(event_count_); - std::vector<int64_t> timestamps_us(event_count_); + std::vector<int64_t> timestamps_ms(event_count_); for (size_t i = 0; i < event_count_; ++i) { - timestamps_us[i] = rtc::TimeMicros(); + timestamps_ms[i] = rtc::TimeMillis(); events[i] = gen_.NewFir(); rtc::Buffer buffer = events[i].Build(); if (direction == kIncomingPacket) { @@ -925,15 +986,14 @@ TEST_P(RtcEventLogEncoderTest, RtcEventRtcpFir) { fake_clock.AdvanceTime(TimeDelta::Millis(prng_.Rand(0, 1000))); } - std::string encoded = - encoder_->EncodeBatch(history_.begin(), history_.end()); - ASSERT_TRUE(parsed_log_.ParseString(encoded).ok()); + 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_us[i], events[i], firs[i]); + verifier_.VerifyLoggedFir(timestamps_ms[i], events[i], firs[i]); } } } @@ -948,9 +1008,9 @@ TEST_P(RtcEventLogEncoderTest, RtcEventRtcpPli) { for (auto direction : {kIncomingPacket, kOutgoingPacket}) { std::vector<rtcp::Pli> events(event_count_); - std::vector<int64_t> timestamps_us(event_count_); + std::vector<int64_t> timestamps_ms(event_count_); for (size_t i = 0; i < event_count_; ++i) { - timestamps_us[i] = rtc::TimeMicros(); + timestamps_ms[i] = rtc::TimeMillis(); events[i] = gen_.NewPli(); rtc::Buffer buffer = events[i].Build(); if (direction == kIncomingPacket) { @@ -963,15 +1023,51 @@ TEST_P(RtcEventLogEncoderTest, RtcEventRtcpPli) { fake_clock.AdvanceTime(TimeDelta::Millis(prng_.Rand(0, 1000))); } - std::string encoded = - encoder_->EncodeBatch(history_.begin(), history_.end()); - ASSERT_TRUE(parsed_log_.ParseString(encoded).ok()); + 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_us[i], events[i], plis[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]); } } } @@ -986,9 +1082,9 @@ TEST_P(RtcEventLogEncoderTest, RtcEventRtcpNack) { for (auto direction : {kIncomingPacket, kOutgoingPacket}) { std::vector<rtcp::Nack> events(event_count_); - std::vector<int64_t> timestamps_us(event_count_); + std::vector<int64_t> timestamps_ms(event_count_); for (size_t i = 0; i < event_count_; ++i) { - timestamps_us[i] = rtc::TimeMicros(); + timestamps_ms[i] = rtc::TimeMillis(); events[i] = gen_.NewNack(); rtc::Buffer buffer = events[i].Build(); if (direction == kIncomingPacket) { @@ -1001,15 +1097,14 @@ TEST_P(RtcEventLogEncoderTest, RtcEventRtcpNack) { fake_clock.AdvanceTime(TimeDelta::Millis(prng_.Rand(0, 1000))); } - std::string encoded = - encoder_->EncodeBatch(history_.begin(), history_.end()); - ASSERT_TRUE(parsed_log_.ParseString(encoded).ok()); + 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_us[i], events[i], nacks[i]); + verifier_.VerifyLoggedNack(timestamps_ms[i], events[i], nacks[i]); } } } @@ -1024,9 +1119,9 @@ TEST_P(RtcEventLogEncoderTest, RtcEventRtcpRemb) { for (auto direction : {kIncomingPacket, kOutgoingPacket}) { std::vector<rtcp::Remb> events(event_count_); - std::vector<int64_t> timestamps_us(event_count_); + std::vector<int64_t> timestamps_ms(event_count_); for (size_t i = 0; i < event_count_; ++i) { - timestamps_us[i] = rtc::TimeMicros(); + timestamps_ms[i] = rtc::TimeMillis(); events[i] = gen_.NewRemb(); rtc::Buffer buffer = events[i].Build(); if (direction == kIncomingPacket) { @@ -1039,15 +1134,14 @@ TEST_P(RtcEventLogEncoderTest, RtcEventRtcpRemb) { fake_clock.AdvanceTime(TimeDelta::Millis(prng_.Rand(0, 1000))); } - std::string encoded = - encoder_->EncodeBatch(history_.begin(), history_.end()); - ASSERT_TRUE(parsed_log_.ParseString(encoded).ok()); + 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_us[i], events[i], rembs[i]); + verifier_.VerifyLoggedRemb(timestamps_ms[i], events[i], rembs[i]); } } } @@ -1063,9 +1157,9 @@ TEST_P(RtcEventLogEncoderTest, RtcEventRtcpTransportFeedback) { for (auto direction : {kIncomingPacket, kOutgoingPacket}) { std::vector<rtcp::TransportFeedback> events; events.reserve(event_count_); - std::vector<int64_t> timestamps_us(event_count_); + std::vector<int64_t> timestamps_ms(event_count_); for (size_t i = 0; i < event_count_; ++i) { - timestamps_us[i] = rtc::TimeMicros(); + timestamps_ms[i] = rtc::TimeMillis(); events.emplace_back(gen_.NewTransportFeedback()); rtc::Buffer buffer = events[i].Build(); if (direction == kIncomingPacket) { @@ -1078,16 +1172,15 @@ TEST_P(RtcEventLogEncoderTest, RtcEventRtcpTransportFeedback) { fake_clock.AdvanceTime(TimeDelta::Millis(prng_.Rand(0, 1000))); } - std::string encoded = - encoder_->EncodeBatch(history_.begin(), history_.end()); - ASSERT_TRUE(parsed_log_.ParseString(encoded).ok()); + 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_us[i], events[i], + verifier_.VerifyLoggedTransportFeedback(timestamps_ms[i], events[i], transport_feedbacks[i]); } } @@ -1104,9 +1197,9 @@ TEST_P(RtcEventLogEncoderTest, RtcEventRtcpLossNotification) { for (auto direction : {kIncomingPacket, kOutgoingPacket}) { std::vector<rtcp::LossNotification> events; events.reserve(event_count_); - std::vector<int64_t> timestamps_us(event_count_); + std::vector<int64_t> timestamps_ms(event_count_); for (size_t i = 0; i < event_count_; ++i) { - timestamps_us[i] = rtc::TimeMicros(); + timestamps_ms[i] = rtc::TimeMillis(); events.emplace_back(gen_.NewLossNotification()); rtc::Buffer buffer = events[i].Build(); if (direction == kIncomingPacket) { @@ -1119,15 +1212,14 @@ TEST_P(RtcEventLogEncoderTest, RtcEventRtcpLossNotification) { fake_clock.AdvanceTime(TimeDelta::Millis(prng_.Rand(0, 1000))); } - std::string encoded = - encoder_->EncodeBatch(history_.begin(), history_.end()); - ASSERT_TRUE(parsed_log_.ParseString(encoded).ok()); + 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_us[i], events[i], + verifier_.VerifyLoggedLossNotification(timestamps_ms[i], events[i], loss_notifications[i]); } } @@ -1149,8 +1241,8 @@ TEST_P(RtcEventLogEncoderTest, RtcEventVideoReceiveStreamConfig) { gen_.NewVideoReceiveStreamConfig(ssrc, extensions); history_.push_back(event->Copy()); - std::string encoded = encoder_->EncodeBatch(history_.begin(), history_.end()); - ASSERT_TRUE(parsed_log_.ParseString(encoded).ok()); + 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); @@ -1165,8 +1257,8 @@ TEST_P(RtcEventLogEncoderTest, RtcEventVideoSendStreamConfig) { gen_.NewVideoSendStreamConfig(ssrc, extensions); history_.push_back(event->Copy()); - std::string encoded = encoder_->EncodeBatch(history_.begin(), history_.end()); - ASSERT_TRUE(parsed_log_.ParseString(encoded).ok()); + 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); @@ -1177,8 +1269,75 @@ INSTANTIATE_TEST_SUITE_P( RandomSeeds, RtcEventLogEncoderTest, ::testing::Combine(/* Random seed*: */ ::testing::Values(1, 2, 3, 4, 5), - /* Encoding: */ ::testing::Bool(), + /* 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/logging/rtc_event_log/encoder/rtc_event_log_encoder_v3.cc b/logging/rtc_event_log/encoder/rtc_event_log_encoder_v3.cc new file mode 100644 index 0000000000..131aae1de8 --- /dev/null +++ b/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/logging/rtc_event_log/encoder/rtc_event_log_encoder_v3.h b/logging/rtc_event_log/encoder/rtc_event_log_encoder_v3.h new file mode 100644 index 0000000000..cb796ec562 --- /dev/null +++ b/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/logging/rtc_event_log/encoder/var_int.cc b/logging/rtc_event_log/encoder/var_int.cc index b2c695ee78..a84a233d6b 100644 --- a/logging/rtc_event_log/encoder/var_int.cc +++ b/logging/rtc_event_log/encoder/var_int.cc @@ -10,6 +10,7 @@ #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. @@ -39,7 +40,8 @@ std::string EncodeVarInt(uint64_t input) { // There is some code duplication between the flavors of this function. // For performance's sake, it's best to just keep it. -size_t DecodeVarInt(absl::string_view input, uint64_t* output) { +std::pair<bool, absl::string_view> DecodeVarInt(absl::string_view input, + uint64_t* output) { RTC_DCHECK(output); uint64_t decoded = 0; @@ -48,32 +50,27 @@ size_t DecodeVarInt(absl::string_view input, uint64_t* output) { << static_cast<uint64_t>(7 * i)); if (!(input[i] & 0x80)) { *output = decoded; - return i + 1; + return {true, input.substr(i + 1)}; } } - return 0; + 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. -size_t DecodeVarInt(rtc::BitBuffer* input, uint64_t* output) { - RTC_DCHECK(output); - +uint64_t DecodeVarInt(BitstreamReader& input) { uint64_t decoded = 0; for (size_t i = 0; i < kMaxVarIntLengthBytes; ++i) { - uint8_t byte; - if (!input->ReadUInt8(&byte)) { - return 0; - } + uint8_t byte = input.Read<uint8_t>(); decoded += (static_cast<uint64_t>(byte & 0x7f) << static_cast<uint64_t>(7 * i)); if (!(byte & 0x80)) { - *output = decoded; - return i + 1; + return decoded; } } + input.Invalidate(); return 0; } diff --git a/logging/rtc_event_log/encoder/var_int.h b/logging/rtc_event_log/encoder/var_int.h index 178c9cec18..4624e046ba 100644 --- a/logging/rtc_event_log/encoder/var_int.h +++ b/logging/rtc_event_log/encoder/var_int.h @@ -15,9 +15,10 @@ #include <stdint.h> #include <string> +#include <utility> #include "absl/strings/string_view.h" -#include "rtc_base/bit_buffer.h" +#include "rtc_base/bitstream_reader.h" namespace webrtc { @@ -26,22 +27,23 @@ 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 +// 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(). -// If decoding is successful, a non-zero number is returned, indicating the -// number of bytes read from |input|, and the decoded varint is written -// into |output|. -// If not successful, 0 is returned, and |output| is not modified. -size_t DecodeVarInt(absl::string_view input, uint64_t* output); - -// Same as other version, but uses a rtc::BitBuffer for input. -// Some bits may be consumed even if a varint fails to be read. -size_t DecodeVarInt(rtc::BitBuffer* input, uint64_t* output); +// 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 diff --git a/logging/rtc_event_log/events/fixed_length_encoding_parameters_v3.cc b/logging/rtc_event_log/events/fixed_length_encoding_parameters_v3.cc new file mode 100644 index 0000000000..0c93e6226d --- /dev/null +++ b/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/logging/rtc_event_log/events/fixed_length_encoding_parameters_v3.h b/logging/rtc_event_log/events/fixed_length_encoding_parameters_v3.h new file mode 100644 index 0000000000..666fae1c63 --- /dev/null +++ b/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/logging/rtc_event_log/events/logged_rtp_rtcp.h b/logging/rtc_event_log/events/logged_rtp_rtcp.h new file mode 100644 index 0000000000..00689a0a16 --- /dev/null +++ b/logging/rtc_event_log/events/logged_rtp_rtcp.h @@ -0,0 +1,260 @@ +/* + * 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, /*include_lost*/ 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/logging/rtc_event_log/events/rtc_event_alr_state.cc b/logging/rtc_event_log/events/rtc_event_alr_state.cc index 8ab7f798c0..25941eb16b 100644 --- a/logging/rtc_event_log/events/rtc_event_alr_state.cc +++ b/logging/rtc_event_log/events/rtc_event_alr_state.cc @@ -13,6 +13,9 @@ #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) {} @@ -21,16 +24,15 @@ RtcEventAlrState::RtcEventAlrState(const RtcEventAlrState& other) RtcEventAlrState::~RtcEventAlrState() = default; -RtcEvent::Type RtcEventAlrState::GetType() const { - return RtcEvent::Type::AlrStateEvent; -} - -bool RtcEventAlrState::IsConfigEvent() const { - return false; -} - 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/logging/rtc_event_log/events/rtc_event_alr_state.h b/logging/rtc_event_log/events/rtc_event_alr_state.h index 0869aa4d98..9f595ecd90 100644 --- a/logging/rtc_event_log/events/rtc_event_alr_state.h +++ b/logging/rtc_event_log/events/rtc_event_alr_state.h @@ -12,28 +12,66 @@ #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; - - bool IsConfigEvent() const 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 diff --git a/logging/rtc_event_log/events/rtc_event_audio_network_adaptation.cc b/logging/rtc_event_log/events/rtc_event_audio_network_adaptation.cc index 73783167a9..5f2d55c357 100644 --- a/logging/rtc_event_log/events/rtc_event_audio_network_adaptation.cc +++ b/logging/rtc_event_log/events/rtc_event_audio_network_adaptation.cc @@ -31,14 +31,6 @@ RtcEventAudioNetworkAdaptation::RtcEventAudioNetworkAdaptation( RtcEventAudioNetworkAdaptation::~RtcEventAudioNetworkAdaptation() = default; -RtcEvent::Type RtcEventAudioNetworkAdaptation::GetType() const { - return RtcEvent::Type::AudioNetworkAdaptation; -} - -bool RtcEventAudioNetworkAdaptation::IsConfigEvent() const { - return false; -} - std::unique_ptr<RtcEventAudioNetworkAdaptation> RtcEventAudioNetworkAdaptation::Copy() const { return absl::WrapUnique(new RtcEventAudioNetworkAdaptation(*this)); diff --git a/logging/rtc_event_log/events/rtc_event_audio_network_adaptation.h b/logging/rtc_event_log/events/rtc_event_audio_network_adaptation.h index 7c50054561..d4cae3abfa 100644 --- a/logging/rtc_event_log/events/rtc_event_audio_network_adaptation.h +++ b/logging/rtc_event_log/events/rtc_event_audio_network_adaptation.h @@ -12,27 +12,61 @@ #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; - - bool IsConfigEvent() const 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); diff --git a/logging/rtc_event_log/events/rtc_event_audio_playout.cc b/logging/rtc_event_log/events/rtc_event_audio_playout.cc index 6c4aa98d3e..21a3f9266c 100644 --- a/logging/rtc_event_log/events/rtc_event_audio_playout.cc +++ b/logging/rtc_event_log/events/rtc_event_audio_playout.cc @@ -14,19 +14,16 @@ 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_) {} -RtcEvent::Type RtcEventAudioPlayout::GetType() const { - return RtcEvent::Type::AudioPlayout; -} - -bool RtcEventAudioPlayout::IsConfigEvent() const { - return false; -} - std::unique_ptr<RtcEventAudioPlayout> RtcEventAudioPlayout::Copy() const { return absl::WrapUnique<RtcEventAudioPlayout>( new RtcEventAudioPlayout(*this)); diff --git a/logging/rtc_event_log/events/rtc_event_audio_playout.h b/logging/rtc_event_log/events/rtc_event_audio_playout.h index 45836b79e3..196c3ca247 100644 --- a/logging/rtc_event_log/events/rtc_event_audio_playout.h +++ b/logging/rtc_event_log/events/rtc_event_audio_playout.h @@ -13,29 +13,74 @@ #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; - - bool IsConfigEvent() const override; + 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 diff --git a/logging/rtc_event_log/events/rtc_event_audio_receive_stream_config.cc b/logging/rtc_event_log/events/rtc_event_audio_receive_stream_config.cc index 5cdfb473bb..87caaff098 100644 --- a/logging/rtc_event_log/events/rtc_event_audio_receive_stream_config.cc +++ b/logging/rtc_event_log/events/rtc_event_audio_receive_stream_config.cc @@ -31,14 +31,6 @@ RtcEventAudioReceiveStreamConfig::RtcEventAudioReceiveStreamConfig( RtcEventAudioReceiveStreamConfig::~RtcEventAudioReceiveStreamConfig() = default; -RtcEvent::Type RtcEventAudioReceiveStreamConfig::GetType() const { - return RtcEvent::Type::AudioReceiveStreamConfig; -} - -bool RtcEventAudioReceiveStreamConfig::IsConfigEvent() const { - return true; -} - std::unique_ptr<RtcEventAudioReceiveStreamConfig> RtcEventAudioReceiveStreamConfig::Copy() const { return absl::WrapUnique<RtcEventAudioReceiveStreamConfig>( diff --git a/logging/rtc_event_log/events/rtc_event_audio_receive_stream_config.h b/logging/rtc_event_log/events/rtc_event_audio_receive_stream_config.h index 67f28602f3..9863e235af 100644 --- a/logging/rtc_event_log/events/rtc_event_audio_receive_stream_config.h +++ b/logging/rtc_event_log/events/rtc_event_audio_receive_stream_config.h @@ -12,29 +12,58 @@ #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 { -namespace rtclog { -struct StreamConfig; -} // namespace rtclog +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; - - bool IsConfigEvent() const 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); diff --git a/logging/rtc_event_log/events/rtc_event_audio_send_stream_config.cc b/logging/rtc_event_log/events/rtc_event_audio_send_stream_config.cc index f4403afddf..681ae11e63 100644 --- a/logging/rtc_event_log/events/rtc_event_audio_send_stream_config.cc +++ b/logging/rtc_event_log/events/rtc_event_audio_send_stream_config.cc @@ -31,14 +31,6 @@ RtcEventAudioSendStreamConfig::RtcEventAudioSendStreamConfig( RtcEventAudioSendStreamConfig::~RtcEventAudioSendStreamConfig() = default; -RtcEvent::Type RtcEventAudioSendStreamConfig::GetType() const { - return RtcEvent::Type::AudioSendStreamConfig; -} - -bool RtcEventAudioSendStreamConfig::IsConfigEvent() const { - return true; -} - std::unique_ptr<RtcEventAudioSendStreamConfig> RtcEventAudioSendStreamConfig::Copy() const { return absl::WrapUnique<RtcEventAudioSendStreamConfig>( diff --git a/logging/rtc_event_log/events/rtc_event_audio_send_stream_config.h b/logging/rtc_event_log/events/rtc_event_audio_send_stream_config.h index 8617b950e7..550723bcf0 100644 --- a/logging/rtc_event_log/events/rtc_event_audio_send_stream_config.h +++ b/logging/rtc_event_log/events/rtc_event_audio_send_stream_config.h @@ -12,29 +12,57 @@ #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 { -namespace rtclog { -struct StreamConfig; -} // namespace rtclog +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; - - bool IsConfigEvent() const 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); diff --git a/logging/rtc_event_log/events/rtc_event_begin_log.cc b/logging/rtc_event_log/events/rtc_event_begin_log.cc new file mode 100644 index 0000000000..49b9effa9e --- /dev/null +++ b/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/logging/rtc_event_log/events/rtc_event_begin_log.h b/logging/rtc_event_log/events/rtc_event_begin_log.h new file mode 100644 index 0000000000..f3b74c117e --- /dev/null +++ b/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/logging/rtc_event_log/events/rtc_event_bwe_update_delay_based.cc b/logging/rtc_event_log/events/rtc_event_bwe_update_delay_based.cc index dcc87421f8..0e98b2ff11 100644 --- a/logging/rtc_event_log/events/rtc_event_bwe_update_delay_based.cc +++ b/logging/rtc_event_log/events/rtc_event_bwe_update_delay_based.cc @@ -11,10 +11,16 @@ #include "logging/rtc_event_log/events/rtc_event_bwe_update_delay_based.h" #include "absl/memory/memory.h" -#include "modules/remote_bitrate_estimator/include/bwe_defines.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) @@ -28,14 +34,6 @@ RtcEventBweUpdateDelayBased::RtcEventBweUpdateDelayBased( RtcEventBweUpdateDelayBased::~RtcEventBweUpdateDelayBased() = default; -RtcEvent::Type RtcEventBweUpdateDelayBased::GetType() const { - return RtcEvent::Type::BweUpdateDelayBased; -} - -bool RtcEventBweUpdateDelayBased::IsConfigEvent() const { - return false; -} - std::unique_ptr<RtcEventBweUpdateDelayBased> RtcEventBweUpdateDelayBased::Copy() const { return absl::WrapUnique<RtcEventBweUpdateDelayBased>( diff --git a/logging/rtc_event_log/events/rtc_event_bwe_update_delay_based.h b/logging/rtc_event_log/events/rtc_event_bwe_update_delay_based.h index 8908ce2be1..796f119388 100644 --- a/logging/rtc_event_log/events/rtc_event_bwe_update_delay_based.h +++ b/logging/rtc_event_log/events/rtc_event_bwe_update_delay_based.h @@ -13,34 +13,122 @@ #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 { -enum class BandwidthUsage; +// 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; - - bool IsConfigEvent() const 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 diff --git a/logging/rtc_event_log/events/rtc_event_bwe_update_loss_based.cc b/logging/rtc_event_log/events/rtc_event_bwe_update_loss_based.cc index 8453238cf9..44524ab033 100644 --- a/logging/rtc_event_log/events/rtc_event_bwe_update_loss_based.cc +++ b/logging/rtc_event_log/events/rtc_event_bwe_update_loss_based.cc @@ -30,14 +30,6 @@ RtcEventBweUpdateLossBased::RtcEventBweUpdateLossBased( RtcEventBweUpdateLossBased::~RtcEventBweUpdateLossBased() = default; -RtcEvent::Type RtcEventBweUpdateLossBased::GetType() const { - return RtcEvent::Type::BweUpdateLossBased; -} - -bool RtcEventBweUpdateLossBased::IsConfigEvent() const { - return false; -} - std::unique_ptr<RtcEventBweUpdateLossBased> RtcEventBweUpdateLossBased::Copy() const { return absl::WrapUnique<RtcEventBweUpdateLossBased>( diff --git a/logging/rtc_event_log/events/rtc_event_bwe_update_loss_based.h b/logging/rtc_event_log/events/rtc_event_bwe_update_loss_based.h index 78829a9586..fd41b316e0 100644 --- a/logging/rtc_event_log/events/rtc_event_bwe_update_loss_based.h +++ b/logging/rtc_event_log/events/rtc_event_bwe_update_loss_based.h @@ -14,21 +14,48 @@ #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; - - bool IsConfigEvent() const override; + Type GetType() const override { return kType; } + bool IsConfigEvent() const override { return false; } std::unique_ptr<RtcEventBweUpdateLossBased> Copy() const; @@ -36,6 +63,19 @@ class RtcEventBweUpdateLossBased final : public RtcEvent { 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); diff --git a/logging/rtc_event_log/events/rtc_event_definition.h b/logging/rtc_event_log/events/rtc_event_definition.h new file mode 100644 index 0000000000..8688c5fc7b --- /dev/null +++ b/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/logging/rtc_event_log/events/rtc_event_dtls_transport_state.cc b/logging/rtc_event_log/events/rtc_event_dtls_transport_state.cc index ac8e642daa..f00342df72 100644 --- a/logging/rtc_event_log/events/rtc_event_dtls_transport_state.cc +++ b/logging/rtc_event_log/events/rtc_event_dtls_transport_state.cc @@ -24,14 +24,6 @@ RtcEventDtlsTransportState::RtcEventDtlsTransportState( RtcEventDtlsTransportState::~RtcEventDtlsTransportState() = default; -RtcEvent::Type RtcEventDtlsTransportState::GetType() const { - return RtcEvent::Type::DtlsTransportState; -} - -bool RtcEventDtlsTransportState::IsConfigEvent() const { - return false; -} - std::unique_ptr<RtcEventDtlsTransportState> RtcEventDtlsTransportState::Copy() const { return absl::WrapUnique<RtcEventDtlsTransportState>( diff --git a/logging/rtc_event_log/events/rtc_event_dtls_transport_state.h b/logging/rtc_event_log/events/rtc_event_dtls_transport_state.h index 4fbe5a7932..b9af213256 100644 --- a/logging/rtc_event_log/events/rtc_event_dtls_transport_state.h +++ b/logging/rtc_event_log/events/rtc_event_dtls_transport_state.h @@ -12,19 +12,35 @@ #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; - bool IsConfigEvent() const override; + Type GetType() const override { return kType; } + bool IsConfigEvent() const override { return false; } std::unique_ptr<RtcEventDtlsTransportState> Copy() const; @@ -32,6 +48,19 @@ class RtcEventDtlsTransportState : public RtcEvent { 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); diff --git a/logging/rtc_event_log/events/rtc_event_dtls_writable_state.cc b/logging/rtc_event_log/events/rtc_event_dtls_writable_state.cc index 16c1e7b8e8..d4cb093ce6 100644 --- a/logging/rtc_event_log/events/rtc_event_dtls_writable_state.cc +++ b/logging/rtc_event_log/events/rtc_event_dtls_writable_state.cc @@ -23,14 +23,6 @@ RtcEventDtlsWritableState::RtcEventDtlsWritableState( RtcEventDtlsWritableState::~RtcEventDtlsWritableState() = default; -RtcEvent::Type RtcEventDtlsWritableState::GetType() const { - return RtcEvent::Type::DtlsWritableState; -} - -bool RtcEventDtlsWritableState::IsConfigEvent() const { - return false; -} - std::unique_ptr<RtcEventDtlsWritableState> RtcEventDtlsWritableState::Copy() const { return absl::WrapUnique<RtcEventDtlsWritableState>( diff --git a/logging/rtc_event_log/events/rtc_event_dtls_writable_state.h b/logging/rtc_event_log/events/rtc_event_dtls_writable_state.h index 06a7f9db7e..c820f184d7 100644 --- a/logging/rtc_event_log/events/rtc_event_dtls_writable_state.h +++ b/logging/rtc_event_log/events/rtc_event_dtls_writable_state.h @@ -12,23 +12,55 @@ #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; - bool IsConfigEvent() const 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); diff --git a/logging/rtc_event_log/events/rtc_event_end_log.cc b/logging/rtc_event_log/events/rtc_event_end_log.cc new file mode 100644 index 0000000000..52abf9e842 --- /dev/null +++ b/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/logging/rtc_event_log/events/rtc_event_end_log.h b/logging/rtc_event_log/events/rtc_event_end_log.h new file mode 100644 index 0000000000..79648bdb8d --- /dev/null +++ b/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/logging/rtc_event_log/events/rtc_event_field_encoding.cc b/logging/rtc_event_log/events/rtc_event_field_encoding.cc new file mode 100644 index 0000000000..68188ce856 --- /dev/null +++ b/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/logging/rtc_event_log/events/rtc_event_field_encoding.h b/logging/rtc_event_log/events/rtc_event_field_encoding.h new file mode 100644 index 0000000000..33b77b80f5 --- /dev/null +++ b/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/logging/rtc_event_log/events/rtc_event_field_encoding_parser.cc b/logging/rtc_event_log/events/rtc_event_field_encoding_parser.cc new file mode 100644 index 0000000000..a9b0c08307 --- /dev/null +++ b/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/logging/rtc_event_log/events/rtc_event_field_encoding_parser.h b/logging/rtc_event_log/events/rtc_event_field_encoding_parser.h new file mode 100644 index 0000000000..fc87faf611 --- /dev/null +++ b/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/logging/rtc_event_log/events/rtc_event_field_encoding_unittest.cc b/logging/rtc_event_log/events/rtc_event_field_encoding_unittest.cc new file mode 100644 index 0000000000..18beda1417 --- /dev/null +++ b/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/logging/rtc_event_log/events/rtc_event_field_extraction.cc b/logging/rtc_event_log/events/rtc_event_field_extraction.cc new file mode 100644 index 0000000000..99f0b3697c --- /dev/null +++ b/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/logging/rtc_event_log/events/rtc_event_field_extraction.h b/logging/rtc_event_log/events/rtc_event_field_extraction.h new file mode 100644 index 0000000000..eb9d67f1c2 --- /dev/null +++ b/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/logging/rtc_event_log/events/rtc_event_field_extraction_unittest.cc b/logging/rtc_event_log/events/rtc_event_field_extraction_unittest.cc new file mode 100644 index 0000000000..f9fb993af0 --- /dev/null +++ b/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/logging/rtc_event_log/events/rtc_event_frame_decoded.cc b/logging/rtc_event_log/events/rtc_event_frame_decoded.cc new file mode 100644 index 0000000000..cde412e6c4 --- /dev/null +++ b/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/logging/rtc_event_log/events/rtc_event_frame_decoded.h b/logging/rtc_event_log/events/rtc_event_frame_decoded.h new file mode 100644 index 0000000000..91190faea9 --- /dev/null +++ b/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/logging/rtc_event_log/events/rtc_event_generic_ack_received.cc b/logging/rtc_event_log/events/rtc_event_generic_ack_received.cc index 0ffe62259f..ba18d50ab6 100644 --- a/logging/rtc_event_log/events/rtc_event_generic_ack_received.cc +++ b/logging/rtc_event_log/events/rtc_event_generic_ack_received.cc @@ -23,6 +23,7 @@ RtcEventGenericAckReceived::CreateLogs( 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, @@ -51,12 +52,4 @@ RtcEventGenericAckReceived::RtcEventGenericAckReceived( RtcEventGenericAckReceived::~RtcEventGenericAckReceived() = default; -RtcEvent::Type RtcEventGenericAckReceived::GetType() const { - return RtcEvent::Type::GenericAckReceived; -} - -bool RtcEventGenericAckReceived::IsConfigEvent() const { - return false; -} - } // namespace webrtc diff --git a/logging/rtc_event_log/events/rtc_event_generic_ack_received.h b/logging/rtc_event_log/events/rtc_event_generic_ack_received.h index 689c124619..57fd7cd9a6 100644 --- a/logging/rtc_event_log/events/rtc_event_generic_ack_received.h +++ b/logging/rtc_event_log/events/rtc_event_generic_ack_received.h @@ -12,13 +12,38 @@ #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; @@ -30,6 +55,8 @@ struct AckedPacket { 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( @@ -40,9 +67,8 @@ class RtcEventGenericAckReceived final : public RtcEvent { std::unique_ptr<RtcEventGenericAckReceived> Copy() const; - Type GetType() const override; - - bool IsConfigEvent() const override; + 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_; } @@ -50,18 +76,31 @@ class RtcEventGenericAckReceived final : public RtcEvent { // 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. + // 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 + // 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, diff --git a/logging/rtc_event_log/events/rtc_event_generic_packet_received.cc b/logging/rtc_event_log/events/rtc_event_generic_packet_received.cc index 92558b29dd..0bdc4dd505 100644 --- a/logging/rtc_event_log/events/rtc_event_generic_packet_received.cc +++ b/logging/rtc_event_log/events/rtc_event_generic_packet_received.cc @@ -28,12 +28,5 @@ std::unique_ptr<RtcEventGenericPacketReceived> RtcEventGenericPacketReceived::Copy() const { return absl::WrapUnique(new RtcEventGenericPacketReceived(*this)); } -RtcEvent::Type RtcEventGenericPacketReceived::GetType() const { - return RtcEvent::Type::GenericPacketReceived; -} - -bool RtcEventGenericPacketReceived::IsConfigEvent() const { - return false; -} } // namespace webrtc diff --git a/logging/rtc_event_log/events/rtc_event_generic_packet_received.h b/logging/rtc_event_log/events/rtc_event_generic_packet_received.h index 1034826a47..a6006ca4d4 100644 --- a/logging/rtc_event_log/events/rtc_event_generic_packet_received.h +++ b/logging/rtc_event_log/events/rtc_event_generic_packet_received.h @@ -12,21 +12,45 @@ #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; - - bool IsConfigEvent() const override; + 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_; } @@ -35,6 +59,19 @@ class RtcEventGenericPacketReceived final : public RtcEvent { // 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); diff --git a/logging/rtc_event_log/events/rtc_event_generic_packet_sent.cc b/logging/rtc_event_log/events/rtc_event_generic_packet_sent.cc index ef761d5e9d..e8335624b1 100644 --- a/logging/rtc_event_log/events/rtc_event_generic_packet_sent.cc +++ b/logging/rtc_event_log/events/rtc_event_generic_packet_sent.cc @@ -33,12 +33,4 @@ std::unique_ptr<RtcEventGenericPacketSent> RtcEventGenericPacketSent::Copy() return absl::WrapUnique(new RtcEventGenericPacketSent(*this)); } -RtcEvent::Type RtcEventGenericPacketSent::GetType() const { - return RtcEvent::Type::GenericPacketSent; -} - -bool RtcEventGenericPacketSent::IsConfigEvent() const { - return false; -} - } // namespace webrtc diff --git a/logging/rtc_event_log/events/rtc_event_generic_packet_sent.h b/logging/rtc_event_log/events/rtc_event_generic_packet_sent.h index d87a54cbe2..903950a398 100644 --- a/logging/rtc_event_log/events/rtc_event_generic_packet_sent.h +++ b/logging/rtc_event_log/events/rtc_event_generic_packet_sent.h @@ -12,13 +12,47 @@ #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, @@ -27,9 +61,8 @@ class RtcEventGenericPacketSent final : public RtcEvent { std::unique_ptr<RtcEventGenericPacketSent> Copy() const; - Type GetType() const override; - - bool IsConfigEvent() const override; + 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_; } @@ -50,6 +83,19 @@ class RtcEventGenericPacketSent final : public RtcEvent { 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); diff --git a/logging/rtc_event_log/events/rtc_event_ice_candidate_pair.cc b/logging/rtc_event_log/events/rtc_event_ice_candidate_pair.cc index 225362d9e6..2b4b5ba762 100644 --- a/logging/rtc_event_log/events/rtc_event_ice_candidate_pair.cc +++ b/logging/rtc_event_log/events/rtc_event_ice_candidate_pair.cc @@ -31,14 +31,6 @@ RtcEventIceCandidatePair::RtcEventIceCandidatePair( RtcEventIceCandidatePair::~RtcEventIceCandidatePair() = default; -RtcEvent::Type RtcEventIceCandidatePair::GetType() const { - return RtcEvent::Type::IceCandidatePairEvent; -} - -bool RtcEventIceCandidatePair::IsConfigEvent() const { - return false; -} - std::unique_ptr<RtcEventIceCandidatePair> RtcEventIceCandidatePair::Copy() const { return absl::WrapUnique<RtcEventIceCandidatePair>( diff --git a/logging/rtc_event_log/events/rtc_event_ice_candidate_pair.h b/logging/rtc_event_log/events/rtc_event_ice_candidate_pair.h index 88b8c8268f..bdacf15a59 100644 --- a/logging/rtc_event_log/events/rtc_event_ice_candidate_pair.h +++ b/logging/rtc_event_log/events/rtc_event_ice_candidate_pair.h @@ -14,8 +14,13 @@ #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 { @@ -27,17 +32,39 @@ enum class IceCandidatePairEventType { 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; - - bool IsConfigEvent() const override; + Type GetType() const override { return kType; } + bool IsConfigEvent() const override { return false; } std::unique_ptr<RtcEventIceCandidatePair> Copy() const; @@ -45,6 +72,19 @@ class RtcEventIceCandidatePair final : public RtcEvent { 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); diff --git a/logging/rtc_event_log/events/rtc_event_ice_candidate_pair_config.cc b/logging/rtc_event_log/events/rtc_event_ice_candidate_pair_config.cc index fbb8a73dfb..eb458c4640 100644 --- a/logging/rtc_event_log/events/rtc_event_ice_candidate_pair_config.cc +++ b/logging/rtc_event_log/events/rtc_event_ice_candidate_pair_config.cc @@ -54,16 +54,6 @@ RtcEventIceCandidatePairConfig::RtcEventIceCandidatePairConfig( RtcEventIceCandidatePairConfig::~RtcEventIceCandidatePairConfig() = default; -RtcEvent::Type RtcEventIceCandidatePairConfig::GetType() const { - return RtcEvent::Type::IceCandidatePairConfig; -} - -// The ICE candidate pair config event is not equivalent to a RtcEventLog config -// event. -bool RtcEventIceCandidatePairConfig::IsConfigEvent() const { - return false; -} - std::unique_ptr<RtcEventIceCandidatePairConfig> RtcEventIceCandidatePairConfig::Copy() const { return absl::WrapUnique<RtcEventIceCandidatePairConfig>( diff --git a/logging/rtc_event_log/events/rtc_event_ice_candidate_pair_config.h b/logging/rtc_event_log/events/rtc_event_ice_candidate_pair_config.h index 338942acb3..e72d999cff 100644 --- a/logging/rtc_event_log/events/rtc_event_ice_candidate_pair_config.h +++ b/logging/rtc_event_log/events/rtc_event_ice_candidate_pair_config.h @@ -14,8 +14,13 @@ #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 { @@ -64,6 +69,23 @@ enum class IceCandidateNetworkType { 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(); @@ -83,6 +105,8 @@ class IceCandidatePairDescription { class RtcEventIceCandidatePairConfig final : public RtcEvent { public: + static constexpr Type kType = Type::IceCandidatePairConfig; + RtcEventIceCandidatePairConfig( IceCandidatePairConfigType type, uint32_t candidate_pair_id, @@ -90,9 +114,9 @@ class RtcEventIceCandidatePairConfig final : public RtcEvent { ~RtcEventIceCandidatePairConfig() override; - Type GetType() const override; - - bool IsConfigEvent() const 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; @@ -102,6 +126,19 @@ class RtcEventIceCandidatePairConfig final : public RtcEvent { 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); diff --git a/logging/rtc_event_log/events/rtc_event_probe_cluster_created.cc b/logging/rtc_event_log/events/rtc_event_probe_cluster_created.cc index c11a6ce78e..c3d9e59b47 100644 --- a/logging/rtc_event_log/events/rtc_event_probe_cluster_created.cc +++ b/logging/rtc_event_log/events/rtc_event_probe_cluster_created.cc @@ -31,14 +31,6 @@ RtcEventProbeClusterCreated::RtcEventProbeClusterCreated( min_probes_(other.min_probes_), min_bytes_(other.min_bytes_) {} -RtcEvent::Type RtcEventProbeClusterCreated::GetType() const { - return RtcEvent::Type::ProbeClusterCreated; -} - -bool RtcEventProbeClusterCreated::IsConfigEvent() const { - return false; -} - std::unique_ptr<RtcEventProbeClusterCreated> RtcEventProbeClusterCreated::Copy() const { return absl::WrapUnique<RtcEventProbeClusterCreated>( diff --git a/logging/rtc_event_log/events/rtc_event_probe_cluster_created.h b/logging/rtc_event_log/events/rtc_event_probe_cluster_created.h index 7bfe6a252e..ae6810c39d 100644 --- a/logging/rtc_event_log/events/rtc_event_probe_cluster_created.h +++ b/logging/rtc_event_log/events/rtc_event_probe_cluster_created.h @@ -14,22 +14,52 @@ #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; - - bool IsConfigEvent() const override; + Type GetType() const override { return kType; } + bool IsConfigEvent() const override { return false; } std::unique_ptr<RtcEventProbeClusterCreated> Copy() const; @@ -38,6 +68,19 @@ class RtcEventProbeClusterCreated final : public RtcEvent { 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); diff --git a/logging/rtc_event_log/events/rtc_event_probe_result_failure.cc b/logging/rtc_event_log/events/rtc_event_probe_result_failure.cc index 295003ae8d..a79b0c173d 100644 --- a/logging/rtc_event_log/events/rtc_event_probe_result_failure.cc +++ b/logging/rtc_event_log/events/rtc_event_probe_result_failure.cc @@ -25,14 +25,6 @@ RtcEventProbeResultFailure::RtcEventProbeResultFailure( id_(other.id_), failure_reason_(other.failure_reason_) {} -RtcEvent::Type RtcEventProbeResultFailure::GetType() const { - return RtcEvent::Type::ProbeResultFailure; -} - -bool RtcEventProbeResultFailure::IsConfigEvent() const { - return false; -} - std::unique_ptr<RtcEventProbeResultFailure> RtcEventProbeResultFailure::Copy() const { return absl::WrapUnique<RtcEventProbeResultFailure>( diff --git a/logging/rtc_event_log/events/rtc_event_probe_result_failure.h b/logging/rtc_event_log/events/rtc_event_probe_result_failure.h index a493de8ec3..1aa6e75cb7 100644 --- a/logging/rtc_event_log/events/rtc_event_probe_result_failure.h +++ b/logging/rtc_event_log/events/rtc_event_probe_result_failure.h @@ -14,8 +14,13 @@ #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 { @@ -26,20 +31,50 @@ enum class ProbeFailureReason { 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; - - bool IsConfigEvent() const override; + 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); diff --git a/logging/rtc_event_log/events/rtc_event_probe_result_success.cc b/logging/rtc_event_log/events/rtc_event_probe_result_success.cc index d5f9e2f780..e7bc7c25da 100644 --- a/logging/rtc_event_log/events/rtc_event_probe_result_success.cc +++ b/logging/rtc_event_log/events/rtc_event_probe_result_success.cc @@ -24,14 +24,6 @@ RtcEventProbeResultSuccess::RtcEventProbeResultSuccess( id_(other.id_), bitrate_bps_(other.bitrate_bps_) {} -RtcEvent::Type RtcEventProbeResultSuccess::GetType() const { - return RtcEvent::Type::ProbeResultSuccess; -} - -bool RtcEventProbeResultSuccess::IsConfigEvent() const { - return false; -} - std::unique_ptr<RtcEventProbeResultSuccess> RtcEventProbeResultSuccess::Copy() const { return absl::WrapUnique<RtcEventProbeResultSuccess>( diff --git a/logging/rtc_event_log/events/rtc_event_probe_result_success.h b/logging/rtc_event_log/events/rtc_event_probe_result_success.h index e0aba982a1..49d1abec5a 100644 --- a/logging/rtc_event_log/events/rtc_event_probe_result_success.h +++ b/logging/rtc_event_log/events/rtc_event_probe_result_success.h @@ -14,25 +14,60 @@ #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; - - bool IsConfigEvent() const override; + 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); diff --git a/logging/rtc_event_log/events/rtc_event_remote_estimate.h b/logging/rtc_event_log/events/rtc_event_remote_estimate.h index b7919483cc..4a39ecc597 100644 --- a/logging/rtc_event_log/events/rtc_event_remote_estimate.h +++ b/logging/rtc_event_log/events/rtc_event_remote_estimate.h @@ -11,24 +11,58 @@ #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 RtcEvent::Type::RemoteEstimateEvent; } + + 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/logging/rtc_event_log/events/rtc_event_route_change.cc b/logging/rtc_event_log/events/rtc_event_route_change.cc index 1ea63e2dcc..71bd78b346 100644 --- a/logging/rtc_event_log/events/rtc_event_route_change.cc +++ b/logging/rtc_event_log/events/rtc_event_route_change.cc @@ -24,14 +24,6 @@ RtcEventRouteChange::RtcEventRouteChange(const RtcEventRouteChange& other) RtcEventRouteChange::~RtcEventRouteChange() = default; -RtcEvent::Type RtcEventRouteChange::GetType() const { - return RtcEvent::Type::RouteChangeEvent; -} - -bool RtcEventRouteChange::IsConfigEvent() const { - return false; -} - std::unique_ptr<RtcEventRouteChange> RtcEventRouteChange::Copy() const { return absl::WrapUnique<RtcEventRouteChange>(new RtcEventRouteChange(*this)); } diff --git a/logging/rtc_event_log/events/rtc_event_route_change.h b/logging/rtc_event_log/events/rtc_event_route_change.h index 09fb31c570..bc1461d7bb 100644 --- a/logging/rtc_event_log/events/rtc_event_route_change.h +++ b/logging/rtc_event_log/events/rtc_event_route_change.h @@ -12,25 +12,58 @@ #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; - - bool IsConfigEvent() const 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); diff --git a/logging/rtc_event_log/events/rtc_event_rtcp_packet_incoming.cc b/logging/rtc_event_log/events/rtc_event_rtcp_packet_incoming.cc index 45a418f1f6..0ea700a024 100644 --- a/logging/rtc_event_log/events/rtc_event_rtcp_packet_incoming.cc +++ b/logging/rtc_event_log/events/rtc_event_rtcp_packet_incoming.cc @@ -25,14 +25,6 @@ RtcEventRtcpPacketIncoming::RtcEventRtcpPacketIncoming( RtcEventRtcpPacketIncoming::~RtcEventRtcpPacketIncoming() = default; -RtcEvent::Type RtcEventRtcpPacketIncoming::GetType() const { - return RtcEvent::Type::RtcpPacketIncoming; -} - -bool RtcEventRtcpPacketIncoming::IsConfigEvent() const { - return false; -} - std::unique_ptr<RtcEventRtcpPacketIncoming> RtcEventRtcpPacketIncoming::Copy() const { return absl::WrapUnique<RtcEventRtcpPacketIncoming>( diff --git a/logging/rtc_event_log/events/rtc_event_rtcp_packet_incoming.h b/logging/rtc_event_log/events/rtc_event_rtcp_packet_incoming.h index 8237afea90..84fe398e08 100644 --- a/logging/rtc_event_log/events/rtc_event_rtcp_packet_incoming.h +++ b/logging/rtc_event_log/events/rtc_event_rtcp_packet_incoming.h @@ -14,26 +14,45 @@ #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; - - bool IsConfigEvent() const 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); diff --git a/logging/rtc_event_log/events/rtc_event_rtcp_packet_outgoing.cc b/logging/rtc_event_log/events/rtc_event_rtcp_packet_outgoing.cc index b583e5614a..b6a41ac034 100644 --- a/logging/rtc_event_log/events/rtc_event_rtcp_packet_outgoing.cc +++ b/logging/rtc_event_log/events/rtc_event_rtcp_packet_outgoing.cc @@ -25,14 +25,6 @@ RtcEventRtcpPacketOutgoing::RtcEventRtcpPacketOutgoing( RtcEventRtcpPacketOutgoing::~RtcEventRtcpPacketOutgoing() = default; -RtcEvent::Type RtcEventRtcpPacketOutgoing::GetType() const { - return RtcEvent::Type::RtcpPacketOutgoing; -} - -bool RtcEventRtcpPacketOutgoing::IsConfigEvent() const { - return false; -} - std::unique_ptr<RtcEventRtcpPacketOutgoing> RtcEventRtcpPacketOutgoing::Copy() const { return absl::WrapUnique<RtcEventRtcpPacketOutgoing>( diff --git a/logging/rtc_event_log/events/rtc_event_rtcp_packet_outgoing.h b/logging/rtc_event_log/events/rtc_event_rtcp_packet_outgoing.h index f451c7301e..687bd319b4 100644 --- a/logging/rtc_event_log/events/rtc_event_rtcp_packet_outgoing.h +++ b/logging/rtc_event_log/events/rtc_event_rtcp_packet_outgoing.h @@ -14,26 +14,45 @@ #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; - - bool IsConfigEvent() const 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); diff --git a/logging/rtc_event_log/events/rtc_event_rtp_packet_incoming.cc b/logging/rtc_event_log/events/rtc_event_rtp_packet_incoming.cc index 898c0aaf8e..4cf33a238f 100644 --- a/logging/rtc_event_log/events/rtc_event_rtp_packet_incoming.cc +++ b/logging/rtc_event_log/events/rtc_event_rtp_packet_incoming.cc @@ -18,33 +18,14 @@ namespace webrtc { RtcEventRtpPacketIncoming::RtcEventRtpPacketIncoming( const RtpPacketReceived& packet) - : payload_length_(packet.payload_size()), - header_length_(packet.headers_size()), - padding_length_(packet.padding_size()) { - header_.CopyHeaderFrom(packet); - RTC_DCHECK_EQ(packet.size(), - payload_length_ + header_length_ + padding_length_); -} + : packet_(packet) {} RtcEventRtpPacketIncoming::RtcEventRtpPacketIncoming( const RtcEventRtpPacketIncoming& other) - : RtcEvent(other.timestamp_us_), - payload_length_(other.payload_length_), - header_length_(other.header_length_), - padding_length_(other.padding_length_) { - header_.CopyHeaderFrom(other.header_); -} + : RtcEvent(other.timestamp_us_), packet_(other.packet_) {} RtcEventRtpPacketIncoming::~RtcEventRtpPacketIncoming() = default; -RtcEvent::Type RtcEventRtpPacketIncoming::GetType() const { - return RtcEvent::Type::RtpPacketIncoming; -} - -bool RtcEventRtpPacketIncoming::IsConfigEvent() const { - return false; -} - std::unique_ptr<RtcEventRtpPacketIncoming> RtcEventRtpPacketIncoming::Copy() const { return absl::WrapUnique<RtcEventRtpPacketIncoming>( diff --git a/logging/rtc_event_log/events/rtc_event_rtp_packet_incoming.h b/logging/rtc_event_log/events/rtc_event_rtp_packet_incoming.h index 7e30d6d7c8..926ddddff5 100644 --- a/logging/rtc_event_log/events/rtc_event_rtp_packet_incoming.h +++ b/logging/rtc_event_log/events/rtc_event_rtp_packet_incoming.h @@ -11,9 +11,19 @@ #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 { @@ -22,31 +32,56 @@ 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; - - bool IsConfigEvent() const 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 payload_length_ + header_length_ + padding_length_; + 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>(); } - const RtpPacket& header() const { return header_; } - size_t payload_length() const { return payload_length_; } - size_t header_length() const { return header_length_; } - size_t padding_length() const { return padding_length_; } + 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); - RtpPacket header_; // Only the packet's header will be stored here. - const size_t payload_length_; // Media payload, excluding header and padding. - const size_t header_length_; // RTP header. - const size_t padding_length_; // RTP padding. + const RtpPacket packet_; }; } // namespace webrtc diff --git a/logging/rtc_event_log/events/rtc_event_rtp_packet_outgoing.cc b/logging/rtc_event_log/events/rtc_event_rtp_packet_outgoing.cc index 050474edda..a6a4d99702 100644 --- a/logging/rtc_event_log/events/rtc_event_rtp_packet_outgoing.cc +++ b/logging/rtc_event_log/events/rtc_event_rtp_packet_outgoing.cc @@ -19,35 +19,16 @@ namespace webrtc { RtcEventRtpPacketOutgoing::RtcEventRtpPacketOutgoing( const RtpPacketToSend& packet, int probe_cluster_id) - : payload_length_(packet.payload_size()), - header_length_(packet.headers_size()), - padding_length_(packet.padding_size()), - probe_cluster_id_(probe_cluster_id) { - header_.CopyHeaderFrom(packet); - RTC_DCHECK_EQ(packet.size(), - payload_length_ + header_length_ + padding_length_); -} + : packet_(packet), probe_cluster_id_(probe_cluster_id) {} RtcEventRtpPacketOutgoing::RtcEventRtpPacketOutgoing( const RtcEventRtpPacketOutgoing& other) : RtcEvent(other.timestamp_us_), - payload_length_(other.payload_length_), - header_length_(other.header_length_), - padding_length_(other.padding_length_), - probe_cluster_id_(other.probe_cluster_id_) { - header_.CopyHeaderFrom(other.header_); -} + packet_(other.packet_), + probe_cluster_id_(other.probe_cluster_id_) {} RtcEventRtpPacketOutgoing::~RtcEventRtpPacketOutgoing() = default; -RtcEvent::Type RtcEventRtpPacketOutgoing::GetType() const { - return RtcEvent::Type::RtpPacketOutgoing; -} - -bool RtcEventRtpPacketOutgoing::IsConfigEvent() const { - return false; -} - std::unique_ptr<RtcEventRtpPacketOutgoing> RtcEventRtpPacketOutgoing::Copy() const { return absl::WrapUnique<RtcEventRtpPacketOutgoing>( diff --git a/logging/rtc_event_log/events/rtc_event_rtp_packet_outgoing.h b/logging/rtc_event_log/events/rtc_event_rtp_packet_outgoing.h index 9211367bf4..c7b7a09718 100644 --- a/logging/rtc_event_log/events/rtc_event_rtp_packet_outgoing.h +++ b/logging/rtc_event_log/events/rtc_event_rtp_packet_outgoing.h @@ -11,9 +11,19 @@ #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 { @@ -22,34 +32,59 @@ 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; - - bool IsConfigEvent() const 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 payload_length_ + header_length_ + padding_length_; + 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>(); } - const RtpPacket& header() const { return header_; } - size_t payload_length() const { return payload_length_; } - size_t header_length() const { return header_length_; } - size_t padding_length() const { return padding_length_; } + 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); - RtpPacket header_; // Only the packet's header will be stored here. - const size_t payload_length_; // Media payload, excluding header and padding. - const size_t header_length_; // RTP header. - const size_t padding_length_; // RTP padding. - // TODO(eladalon): Delete |probe_cluster_id_| along with legacy encoding. + const RtpPacket packet_; + // TODO(eladalon): Delete `probe_cluster_id_` along with legacy encoding. const int probe_cluster_id_; }; diff --git a/logging/rtc_event_log/events/rtc_event_video_receive_stream_config.cc b/logging/rtc_event_log/events/rtc_event_video_receive_stream_config.cc index 8942f8a642..90ab8185a3 100644 --- a/logging/rtc_event_log/events/rtc_event_video_receive_stream_config.cc +++ b/logging/rtc_event_log/events/rtc_event_video_receive_stream_config.cc @@ -30,14 +30,6 @@ RtcEventVideoReceiveStreamConfig::RtcEventVideoReceiveStreamConfig( RtcEventVideoReceiveStreamConfig::~RtcEventVideoReceiveStreamConfig() = default; -RtcEvent::Type RtcEventVideoReceiveStreamConfig::GetType() const { - return Type::VideoReceiveStreamConfig; -} - -bool RtcEventVideoReceiveStreamConfig::IsConfigEvent() const { - return true; -} - std::unique_ptr<RtcEventVideoReceiveStreamConfig> RtcEventVideoReceiveStreamConfig::Copy() const { return absl::WrapUnique<RtcEventVideoReceiveStreamConfig>( diff --git a/logging/rtc_event_log/events/rtc_event_video_receive_stream_config.h b/logging/rtc_event_log/events/rtc_event_video_receive_stream_config.h index fe5099d11b..0be56c2065 100644 --- a/logging/rtc_event_log/events/rtc_event_video_receive_stream_config.h +++ b/logging/rtc_event_log/events/rtc_event_video_receive_stream_config.h @@ -12,26 +12,58 @@ #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; - - bool IsConfigEvent() const 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); diff --git a/logging/rtc_event_log/events/rtc_event_video_send_stream_config.cc b/logging/rtc_event_log/events/rtc_event_video_send_stream_config.cc index 2c33466ab2..c28a476d01 100644 --- a/logging/rtc_event_log/events/rtc_event_video_send_stream_config.cc +++ b/logging/rtc_event_log/events/rtc_event_video_send_stream_config.cc @@ -27,14 +27,6 @@ RtcEventVideoSendStreamConfig::RtcEventVideoSendStreamConfig( RtcEventVideoSendStreamConfig::~RtcEventVideoSendStreamConfig() = default; -RtcEvent::Type RtcEventVideoSendStreamConfig::GetType() const { - return RtcEvent::Type::VideoSendStreamConfig; -} - -bool RtcEventVideoSendStreamConfig::IsConfigEvent() const { - return true; -} - std::unique_ptr<RtcEventVideoSendStreamConfig> RtcEventVideoSendStreamConfig::Copy() const { return absl::WrapUnique<RtcEventVideoSendStreamConfig>( diff --git a/logging/rtc_event_log/events/rtc_event_video_send_stream_config.h b/logging/rtc_event_log/events/rtc_event_video_send_stream_config.h index 11dd148b95..f1717b19ea 100644 --- a/logging/rtc_event_log/events/rtc_event_video_send_stream_config.h +++ b/logging/rtc_event_log/events/rtc_event_video_send_stream_config.h @@ -12,26 +12,58 @@ #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; - - bool IsConfigEvent() const 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); diff --git a/logging/rtc_event_log/fake_rtc_event_log.cc b/logging/rtc_event_log/fake_rtc_event_log.cc index 55f4b582c7..5a44b00694 100644 --- a/logging/rtc_event_log/fake_rtc_event_log.cc +++ b/logging/rtc_event_log/fake_rtc_event_log.cc @@ -10,32 +10,29 @@ #include "logging/rtc_event_log/fake_rtc_event_log.h" -#include "logging/rtc_event_log/events/rtc_event_ice_candidate_pair.h" -#include "rtc_base/bind.h" -#include "rtc_base/checks.h" -#include "rtc_base/logging.h" +#include <map> +#include <memory> -namespace webrtc { +#include "api/rtc_event_log/rtc_event_log.h" +#include "rtc_base/synchronization/mutex.h" -FakeRtcEventLog::FakeRtcEventLog(rtc::Thread* thread) : thread_(thread) { - RTC_DCHECK(thread_); -} -FakeRtcEventLog::~FakeRtcEventLog() = default; +namespace webrtc { bool FakeRtcEventLog::StartLogging(std::unique_ptr<RtcEventLogOutput> output, int64_t output_period_ms) { return true; } -void FakeRtcEventLog::StopLogging() { - invoker_.Flush(thread_); -} +void FakeRtcEventLog::StopLogging() {} void FakeRtcEventLog::Log(std::unique_ptr<RtcEvent> event) { - RtcEvent::Type rtc_event_type = event->GetType(); - invoker_.AsyncInvoke<void>( - RTC_FROM_HERE, thread_, - rtc::Bind(&FakeRtcEventLog::IncrementEventCount, this, rtc_event_type)); + 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/logging/rtc_event_log/fake_rtc_event_log.h b/logging/rtc_event_log/fake_rtc_event_log.h index fb0e6ff4dc..effa7507f1 100644 --- a/logging/rtc_event_log/fake_rtc_event_log.h +++ b/logging/rtc_event_log/fake_rtc_event_log.h @@ -16,26 +16,25 @@ #include "api/rtc_event_log/rtc_event.h" #include "api/rtc_event_log/rtc_event_log.h" -#include "rtc_base/async_invoker.h" -#include "rtc_base/thread.h" +#include "rtc_base/synchronization/mutex.h" +#include "rtc_base/thread_annotations.h" namespace webrtc { class FakeRtcEventLog : public RtcEventLog { public: - explicit FakeRtcEventLog(rtc::Thread* thread); - ~FakeRtcEventLog() override; + 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) { return count_[event_type]; } + int GetEventCount(RtcEvent::Type event_type); private: - void IncrementEventCount(RtcEvent::Type event_type) { ++count_[event_type]; } - std::map<RtcEvent::Type, int> count_; - rtc::Thread* thread_; - rtc::AsyncInvoker invoker_; + Mutex mu_; + std::map<RtcEvent::Type, int> count_ RTC_GUARDED_BY(mu_); }; } // namespace webrtc diff --git a/logging/rtc_event_log/fake_rtc_event_log_factory.cc b/logging/rtc_event_log/fake_rtc_event_log_factory.cc index f84f74fdb6..47db40c9f4 100644 --- a/logging/rtc_event_log/fake_rtc_event_log_factory.cc +++ b/logging/rtc_event_log/fake_rtc_event_log_factory.cc @@ -10,16 +10,24 @@ #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) { - std::unique_ptr<RtcEventLog> fake_event_log(new FakeRtcEventLog(thread())); - last_log_created_ = fake_event_log.get(); - return fake_event_log; + return Create(encoding_type); } } // namespace webrtc diff --git a/logging/rtc_event_log/fake_rtc_event_log_factory.h b/logging/rtc_event_log/fake_rtc_event_log_factory.h index 873e50efdc..c7ff33dee4 100644 --- a/logging/rtc_event_log/fake_rtc_event_log_factory.h +++ b/logging/rtc_event_log/fake_rtc_event_log_factory.h @@ -15,24 +15,24 @@ #include "api/rtc_event_log/rtc_event_log_factory_interface.h" #include "logging/rtc_event_log/fake_rtc_event_log.h" -#include "rtc_base/thread.h" namespace webrtc { class FakeRtcEventLogFactory : public RtcEventLogFactoryInterface { public: - explicit FakeRtcEventLogFactory(rtc::Thread* thread) : thread_(thread) {} - ~FakeRtcEventLogFactory() override {} + 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::RtcEventLog* last_log_created() { return last_log_created_; } - rtc::Thread* thread() { return thread_; } + webrtc::FakeRtcEventLog* last_log_created() { return last_log_created_; } private: - webrtc::RtcEventLog* last_log_created_; - rtc::Thread* thread_; + webrtc::FakeRtcEventLog* last_log_created_; }; } // namespace webrtc diff --git a/logging/rtc_event_log/logged_events.cc b/logging/rtc_event_log/logged_events.cc deleted file mode 100644 index 3cba8bab21..0000000000 --- a/logging/rtc_event_log/logged_events.cc +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 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/logged_events.h" - -namespace webrtc { - -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() {} - -LoggedRtcpPacket::LoggedRtcpPacket(int64_t timestamp_us, - const uint8_t* packet, - size_t total_length) - : timestamp_us(timestamp_us), raw_data(packet, packet + total_length) {} -LoggedRtcpPacket::LoggedRtcpPacket(int64_t timestamp_us, - const std::string& packet) - : timestamp_us(timestamp_us), raw_data(packet.size()) { - memcpy(raw_data.data(), packet.data(), packet.size()); -} -LoggedRtcpPacket::LoggedRtcpPacket(const LoggedRtcpPacket& rhs) = default; -LoggedRtcpPacket::~LoggedRtcpPacket() = default; - -} // namespace webrtc diff --git a/logging/rtc_event_log/logged_events.h b/logging/rtc_event_log/logged_events.h index e13bba0c43..d6b3cc607e 100644 --- a/logging/rtc_event_log/logged_events.h +++ b/logging/rtc_event_log/logged_events.h @@ -7,653 +7,12 @@ * 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_ -#include <string> -#include <vector> - -#include "absl/types/optional.h" -#include "api/rtp_headers.h" -#include "api/units/data_rate.h" -#include "api/units/time_delta.h" -#include "api/units/timestamp.h" -#include "logging/rtc_event_log/events/rtc_event_dtls_transport_state.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_result_failure.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/remote_bitrate_estimator/include/bwe_defines.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 { - -// The different event types are deliberately POD. Analysis of large logs is -// already resource intensive. The code simplifications that would be possible -// possible by having a base class (containing e.g. the log time) are not -// considered to outweigh the added memory and runtime overhead incurred by -// adding a vptr. -struct LoggedAlrStateEvent { - LoggedAlrStateEvent() = default; - LoggedAlrStateEvent(int64_t timestamp_us, bool in_alr) - : timestamp_us(timestamp_us), in_alr(in_alr) {} - - int64_t log_time_us() const { return timestamp_us; } - int64_t log_time_ms() const { return timestamp_us / 1000; } - - int64_t timestamp_us; - bool in_alr; -}; - -struct LoggedAudioPlayoutEvent { - LoggedAudioPlayoutEvent() = default; - LoggedAudioPlayoutEvent(int64_t timestamp_us, uint32_t ssrc) - : timestamp_us(timestamp_us), ssrc(ssrc) {} - - int64_t log_time_us() const { return timestamp_us; } - int64_t log_time_ms() const { return timestamp_us / 1000; } - - int64_t timestamp_us; - uint32_t ssrc; -}; - -struct LoggedAudioNetworkAdaptationEvent { - LoggedAudioNetworkAdaptationEvent() = default; - LoggedAudioNetworkAdaptationEvent(int64_t timestamp_us, - const AudioEncoderRuntimeConfig& config) - : timestamp_us(timestamp_us), config(config) {} - - int64_t log_time_us() const { return timestamp_us; } - int64_t log_time_ms() const { return timestamp_us / 1000; } - - int64_t timestamp_us; - AudioEncoderRuntimeConfig config; -}; - -struct LoggedBweDelayBasedUpdate { - LoggedBweDelayBasedUpdate() = default; - LoggedBweDelayBasedUpdate(int64_t timestamp_us, - int32_t bitrate_bps, - BandwidthUsage detector_state) - : timestamp_us(timestamp_us), - 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_us / 1000; } - - int64_t timestamp_us; - int32_t bitrate_bps; - BandwidthUsage detector_state; -}; - -struct LoggedBweLossBasedUpdate { - LoggedBweLossBasedUpdate() = default; - LoggedBweLossBasedUpdate(int64_t timestamp_us, - int32_t bitrate_bps, - uint8_t fraction_lost, - int32_t expected_packets) - : timestamp_us(timestamp_us), - 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_us / 1000; } - - int64_t timestamp_us; - int32_t bitrate_bps; - uint8_t fraction_lost; - int32_t expected_packets; -}; - -struct LoggedDtlsTransportState { - int64_t log_time_us() const { return timestamp_us; } - int64_t log_time_ms() const { return timestamp_us / 1000; } - - int64_t timestamp_us; - DtlsTransportState dtls_transport_state; -}; - -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_us / 1000; } - - int64_t timestamp_us; - bool writable; -}; - -struct LoggedBweProbeClusterCreatedEvent { - LoggedBweProbeClusterCreatedEvent() = default; - LoggedBweProbeClusterCreatedEvent(int64_t timestamp_us, - int32_t id, - int32_t bitrate_bps, - uint32_t min_packets, - uint32_t min_bytes) - : timestamp_us(timestamp_us), - 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_us / 1000; } - - int64_t timestamp_us; - int32_t id; - int32_t bitrate_bps; - uint32_t min_packets; - uint32_t min_bytes; -}; - -struct LoggedBweProbeSuccessEvent { - LoggedBweProbeSuccessEvent() = default; - LoggedBweProbeSuccessEvent(int64_t timestamp_us, - int32_t id, - int32_t bitrate_bps) - : timestamp_us(timestamp_us), id(id), bitrate_bps(bitrate_bps) {} - - int64_t log_time_us() const { return timestamp_us; } - int64_t log_time_ms() const { return timestamp_us / 1000; } - - int64_t timestamp_us; - int32_t id; - int32_t bitrate_bps; -}; - -struct LoggedBweProbeFailureEvent { - LoggedBweProbeFailureEvent() = default; - LoggedBweProbeFailureEvent(int64_t timestamp_us, - int32_t id, - ProbeFailureReason failure_reason) - : timestamp_us(timestamp_us), id(id), failure_reason(failure_reason) {} - - int64_t log_time_us() const { return timestamp_us; } - int64_t log_time_ms() const { return timestamp_us / 1000; } - - int64_t timestamp_us; - int32_t id; - ProbeFailureReason failure_reason; -}; - -struct LoggedIceCandidatePairConfig { - int64_t log_time_us() const { return timestamp_us; } - int64_t log_time_ms() const { return timestamp_us / 1000; } - - int64_t timestamp_us; - 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; -}; - -struct LoggedIceCandidatePairEvent { - LoggedIceCandidatePairEvent() = default; - LoggedIceCandidatePairEvent(int64_t timestamp_us, - IceCandidatePairEventType type, - uint32_t candidate_pair_id, - uint32_t transaction_id) - : timestamp_us(timestamp_us), - 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_us / 1000; } - - int64_t timestamp_us; - IceCandidatePairEventType type; - uint32_t candidate_pair_id; - uint32_t transaction_id; -}; - -struct LoggedRouteChangeEvent { - LoggedRouteChangeEvent() = default; - LoggedRouteChangeEvent(int64_t timestamp_ms, - bool connected, - uint32_t overhead) - : timestamp_ms(timestamp_ms), connected(connected), overhead(overhead) {} - - int64_t log_time_us() const { return timestamp_ms * 1000; } - int64_t log_time_ms() const { return timestamp_ms; } - - int64_t timestamp_ms; - bool connected; - uint32_t overhead; -}; - -struct LoggedRemoteEstimateEvent { - LoggedRemoteEstimateEvent() = default; - - int64_t log_time_us() const { return timestamp_ms * 1000; } - int64_t log_time_ms() const { return timestamp_ms; } - - int64_t timestamp_ms; - absl::optional<DataRate> link_capacity_lower; - absl::optional<DataRate> link_capacity_upper; -}; - -struct LoggedRtpPacket { - LoggedRtpPacket(int64_t timestamp_us, - RTPHeader header, - size_t header_length, - size_t total_length) - : timestamp_us(timestamp_us), - 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_us / 1000; } - - int64_t timestamp_us; - // 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(int64_t timestamp_us, - RTPHeader header, - size_t header_length, - size_t total_length) - : rtp(timestamp_us, header, header_length, total_length) {} - int64_t log_time_us() const { return rtp.timestamp_us; } - int64_t log_time_ms() const { return rtp.timestamp_us / 1000; } - - LoggedRtpPacket rtp; -}; - -struct LoggedRtpPacketOutgoing { - LoggedRtpPacketOutgoing(int64_t timestamp_us, - RTPHeader header, - size_t header_length, - size_t total_length) - : rtp(timestamp_us, header, header_length, total_length) {} - int64_t log_time_us() const { return rtp.timestamp_us; } - int64_t log_time_ms() const { return rtp.timestamp_us / 1000; } - - LoggedRtpPacket rtp; -}; - -struct LoggedRtcpPacket { - LoggedRtcpPacket(int64_t timestamp_us, - const uint8_t* packet, - size_t total_length); - LoggedRtcpPacket(int64_t timestamp_us, const std::string& packet); - LoggedRtcpPacket(const LoggedRtcpPacket&); - ~LoggedRtcpPacket(); - - int64_t log_time_us() const { return timestamp_us; } - int64_t log_time_ms() const { return timestamp_us / 1000; } - - int64_t timestamp_us; - std::vector<uint8_t> raw_data; -}; - -struct LoggedRtcpPacketIncoming { - LoggedRtcpPacketIncoming(int64_t timestamp_us, - const uint8_t* packet, - size_t total_length) - : rtcp(timestamp_us, packet, total_length) {} - LoggedRtcpPacketIncoming(uint64_t timestamp_us, const std::string& packet) - : rtcp(timestamp_us, packet) {} - - int64_t log_time_us() const { return rtcp.timestamp_us; } - int64_t log_time_ms() const { return rtcp.timestamp_us / 1000; } - - LoggedRtcpPacket rtcp; -}; - -struct LoggedRtcpPacketOutgoing { - LoggedRtcpPacketOutgoing(int64_t timestamp_us, - const uint8_t* packet, - size_t total_length) - : rtcp(timestamp_us, packet, total_length) {} - LoggedRtcpPacketOutgoing(uint64_t timestamp_us, const std::string& packet) - : rtcp(timestamp_us, packet) {} - - int64_t log_time_us() const { return rtcp.timestamp_us; } - int64_t log_time_ms() const { return rtcp.timestamp_us / 1000; } - - LoggedRtcpPacket rtcp; -}; - -struct LoggedRtcpPacketReceiverReport { - LoggedRtcpPacketReceiverReport() = default; - LoggedRtcpPacketReceiverReport(int64_t timestamp_us, - const rtcp::ReceiverReport& rr) - : timestamp_us(timestamp_us), rr(rr) {} - - int64_t log_time_us() const { return timestamp_us; } - int64_t log_time_ms() const { return timestamp_us / 1000; } - - int64_t timestamp_us; - rtcp::ReceiverReport rr; -}; - -struct LoggedRtcpPacketSenderReport { - LoggedRtcpPacketSenderReport() = default; - LoggedRtcpPacketSenderReport(int64_t timestamp_us, - const rtcp::SenderReport& sr) - : timestamp_us(timestamp_us), sr(sr) {} - - int64_t log_time_us() const { return timestamp_us; } - int64_t log_time_ms() const { return timestamp_us / 1000; } - - int64_t timestamp_us; - rtcp::SenderReport sr; -}; - -struct LoggedRtcpPacketExtendedReports { - LoggedRtcpPacketExtendedReports() = default; - - int64_t log_time_us() const { return timestamp_us; } - int64_t log_time_ms() const { return timestamp_us / 1000; } - - int64_t timestamp_us; - rtcp::ExtendedReports xr; -}; - -struct LoggedRtcpPacketRemb { - LoggedRtcpPacketRemb() = default; - LoggedRtcpPacketRemb(int64_t timestamp_us, const rtcp::Remb& remb) - : timestamp_us(timestamp_us), remb(remb) {} - - int64_t log_time_us() const { return timestamp_us; } - int64_t log_time_ms() const { return timestamp_us / 1000; } - - int64_t timestamp_us; - rtcp::Remb remb; -}; - -struct LoggedRtcpPacketNack { - LoggedRtcpPacketNack() = default; - LoggedRtcpPacketNack(int64_t timestamp_us, const rtcp::Nack& nack) - : timestamp_us(timestamp_us), nack(nack) {} - - int64_t log_time_us() const { return timestamp_us; } - int64_t log_time_ms() const { return timestamp_us / 1000; } - - int64_t timestamp_us; - rtcp::Nack nack; -}; - -struct LoggedRtcpPacketFir { - LoggedRtcpPacketFir() = default; - - int64_t log_time_us() const { return timestamp_us; } - int64_t log_time_ms() const { return timestamp_us / 1000; } - - int64_t timestamp_us; - rtcp::Fir fir; -}; - -struct LoggedRtcpPacketPli { - LoggedRtcpPacketPli() = default; - - int64_t log_time_us() const { return timestamp_us; } - int64_t log_time_ms() const { return timestamp_us / 1000; } - - int64_t timestamp_us; - rtcp::Pli pli; -}; - -struct LoggedRtcpPacketTransportFeedback { - LoggedRtcpPacketTransportFeedback() - : transport_feedback(/*include_timestamps=*/true, /*include_lost*/ true) { - } - LoggedRtcpPacketTransportFeedback( - int64_t timestamp_us, - const rtcp::TransportFeedback& transport_feedback) - : timestamp_us(timestamp_us), transport_feedback(transport_feedback) {} - - int64_t log_time_us() const { return timestamp_us; } - int64_t log_time_ms() const { return timestamp_us / 1000; } - - int64_t timestamp_us; - rtcp::TransportFeedback transport_feedback; -}; - -struct LoggedRtcpPacketLossNotification { - LoggedRtcpPacketLossNotification() = default; - LoggedRtcpPacketLossNotification( - int64_t timestamp_us, - const rtcp::LossNotification& loss_notification) - : timestamp_us(timestamp_us), loss_notification(loss_notification) {} - - int64_t log_time_us() const { return timestamp_us; } - int64_t log_time_ms() const { return timestamp_us / 1000; } - - int64_t timestamp_us; - rtcp::LossNotification loss_notification; -}; - -struct LoggedStartEvent { - explicit LoggedStartEvent(int64_t timestamp_us) - : LoggedStartEvent(timestamp_us, timestamp_us / 1000) {} - - LoggedStartEvent(int64_t timestamp_us, int64_t utc_start_time_ms) - : timestamp_us(timestamp_us), utc_start_time_ms(utc_start_time_ms) {} - - int64_t log_time_us() const { return timestamp_us; } - int64_t log_time_ms() const { return timestamp_us / 1000; } - - int64_t timestamp_us; - int64_t utc_start_time_ms; -}; - -struct LoggedStopEvent { - explicit LoggedStopEvent(int64_t timestamp_us) : timestamp_us(timestamp_us) {} - - int64_t log_time_us() const { return timestamp_us; } - int64_t log_time_ms() const { return timestamp_us / 1000; } - - int64_t timestamp_us; -}; - -struct LoggedAudioRecvConfig { - LoggedAudioRecvConfig() = default; - LoggedAudioRecvConfig(int64_t timestamp_us, const rtclog::StreamConfig config) - : timestamp_us(timestamp_us), config(config) {} - - int64_t log_time_us() const { return timestamp_us; } - int64_t log_time_ms() const { return timestamp_us / 1000; } - - int64_t timestamp_us; - rtclog::StreamConfig config; -}; - -struct LoggedAudioSendConfig { - LoggedAudioSendConfig() = default; - LoggedAudioSendConfig(int64_t timestamp_us, const rtclog::StreamConfig config) - : timestamp_us(timestamp_us), config(config) {} - - int64_t log_time_us() const { return timestamp_us; } - int64_t log_time_ms() const { return timestamp_us / 1000; } - - int64_t timestamp_us; - rtclog::StreamConfig config; -}; - -struct LoggedVideoRecvConfig { - LoggedVideoRecvConfig() = default; - LoggedVideoRecvConfig(int64_t timestamp_us, const rtclog::StreamConfig config) - : timestamp_us(timestamp_us), config(config) {} - - int64_t log_time_us() const { return timestamp_us; } - int64_t log_time_ms() const { return timestamp_us / 1000; } - - int64_t timestamp_us; - rtclog::StreamConfig config; -}; - -struct LoggedVideoSendConfig { - LoggedVideoSendConfig() = default; - LoggedVideoSendConfig(int64_t timestamp_us, const rtclog::StreamConfig config) - : timestamp_us(timestamp_us), config(config) {} - - int64_t log_time_us() const { return timestamp_us; } - int64_t log_time_ms() const { return timestamp_us / 1000; } - - int64_t timestamp_us; - rtclog::StreamConfig config; -}; - -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 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(); -}; - -enum class LoggedIceEventType { - kAdded, - kUpdated, - kDestroyed, - kSelected, - kCheckSent, - kCheckReceived, - kCheckResponseSent, - kCheckResponseReceived, -}; - -struct LoggedIceEvent { - uint32_t candidate_pair_id; - Timestamp log_time; - LoggedIceEventType event_type; -}; - -struct LoggedGenericPacketSent { - LoggedGenericPacketSent() = default; - LoggedGenericPacketSent(int64_t timestamp_us, - int64_t packet_number, - size_t overhead_length, - size_t payload_length, - size_t padding_length) - : timestamp_us(timestamp_us), - packet_number(packet_number), - overhead_length(overhead_length), - payload_length(payload_length), - padding_length(padding_length) {} - - int64_t log_time_us() const { return timestamp_us; } - int64_t log_time_ms() const { return timestamp_us / 1000; } - - size_t packet_length() const { - return payload_length + padding_length + overhead_length; - } - int64_t timestamp_us; - int64_t packet_number; - size_t overhead_length; - size_t payload_length; - size_t padding_length; -}; - -struct LoggedGenericPacketReceived { - LoggedGenericPacketReceived() = default; - LoggedGenericPacketReceived(int64_t timestamp_us, - int64_t packet_number, - int packet_length) - : timestamp_us(timestamp_us), - packet_number(packet_number), - packet_length(packet_length) {} - - int64_t log_time_us() const { return timestamp_us; } - int64_t log_time_ms() const { return timestamp_us / 1000; } - - int64_t timestamp_us; - int64_t packet_number; - int packet_length; -}; - -struct LoggedGenericAckReceived { - LoggedGenericAckReceived() = default; - LoggedGenericAckReceived(int64_t timestamp_us, - int64_t packet_number, - int64_t acked_packet_number, - absl::optional<int64_t> receive_acked_packet_time_ms) - : timestamp_us(timestamp_us), - packet_number(packet_number), - acked_packet_number(acked_packet_number), - receive_acked_packet_time_ms(receive_acked_packet_time_ms) {} - - int64_t log_time_us() const { return timestamp_us; } - int64_t log_time_ms() const { return timestamp_us / 1000; } - - int64_t timestamp_us; - int64_t packet_number; - int64_t acked_packet_number; - absl::optional<int64_t> receive_acked_packet_time_ms; -}; +// TODO(terelius): Delete this forwarding header when downstream +// projects have been updated. +#include "logging/rtc_event_log/events/logged_rtp_rtcp.h" -} // namespace webrtc #endif // LOGGING_RTC_EVENT_LOG_LOGGED_EVENTS_H_ diff --git a/logging/rtc_event_log/rtc_event_log.proto b/logging/rtc_event_log/rtc_event_log.proto index 94e288e024..12baa493bd 100644 --- a/logging/rtc_event_log/rtc_event_log.proto +++ b/logging/rtc_event_log/rtc_event_log.proto @@ -43,6 +43,7 @@ message Event { ALR_STATE_EVENT = 19; ICE_CANDIDATE_PAIR_CONFIG = 20; ICE_CANDIDATE_PAIR_EVENT = 21; + REMOTE_ESTIMATE = 22; } // required - Indicates the type of this event @@ -93,6 +94,9 @@ message Event { // required if type == ICE_CANDIDATE_PAIR_EVENT IceCandidatePairEvent ice_candidate_pair_event = 21; + + // required if type == REMOTE_ESTIMATE + RemoteEstimate remote_estimate = 22; } } @@ -327,6 +331,14 @@ message BweProbeResult { 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; diff --git a/logging/rtc_event_log/rtc_event_log2.proto b/logging/rtc_event_log/rtc_event_log2.proto index 0cdb2a43c7..a541533dcc 100644 --- a/logging/rtc_event_log/rtc_event_log2.proto +++ b/logging/rtc_event_log/rtc_event_log2.proto @@ -20,7 +20,8 @@ message EventStream { repeated IncomingRtcpPackets incoming_rtcp_packets = 4; repeated OutgoingRtcpPackets outgoing_rtcp_packets = 5; repeated AudioPlayoutEvents audio_playout_events = 6; - // The field tags 7-15 are reserved for the most common events. + 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; @@ -143,7 +144,7 @@ message IncomingRtpPackets { 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. + // `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? @@ -164,7 +165,7 @@ message IncomingRtpPackets { 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. + // `audio_level` and `voice_activity` are always used in conjunction. optional bytes audio_level_deltas = 119; optional bytes voice_activity_deltas = 120; } @@ -211,7 +212,7 @@ message OutgoingRtpPackets { 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. + // `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? @@ -232,7 +233,7 @@ message OutgoingRtpPackets { 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. + // `audio_level` and `voice_activity` are always used in conjunction. optional bytes audio_level_deltas = 119; optional bytes voice_activity_deltas = 120; } @@ -284,6 +285,50 @@ message AudioPlayoutEvents { optional bytes local_ssrc_deltas = 102; } +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; diff --git a/logging/rtc_event_log/rtc_event_log2rtp_dump.cc b/logging/rtc_event_log/rtc_event_log2rtp_dump.cc index c9d4a6ca88..a0514259aa 100644 --- a/logging/rtc_event_log/rtc_event_log2rtp_dump.cc +++ b/logging/rtc_event_log/rtc_event_log2rtp_dump.cc @@ -21,6 +21,7 @@ #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" @@ -70,12 +71,12 @@ 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, +// 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(std::string str) { +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; @@ -84,7 +85,7 @@ absl::optional<uint32_t> ParseSsrc(std::string str) { read_mode = std::hex; str = str.substr(2); } - std::stringstream ss(str); + std::stringstream ss(std::string{str}); ss >> read_mode >> ssrc; if (str.empty() || (!ss.fail() && ss.eof())) return ssrc; @@ -240,7 +241,7 @@ int main(int argc, char* argv[]) { continue; event_processor.AddEvents(stream.incoming_packets, handle_rtp); } - // Note that |packet_ssrc| is the sender SSRC. An RTCP message may contain + // 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. diff --git a/logging/rtc_event_log/rtc_event_log_impl.cc b/logging/rtc_event_log/rtc_event_log_impl.cc index 4a272f08cf..a48bbdeb8e 100644 --- a/logging/rtc_event_log/rtc_event_log_impl.cc +++ b/logging/rtc_event_log/rtc_event_log_impl.cc @@ -16,13 +16,13 @@ #include <utility> #include <vector> +#include "absl/strings/string_view.h" #include "absl/types/optional.h" -#include "api/task_queue/queued_task.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/constructor_magic.h" #include "rtc_base/event.h" #include "rtc_base/logging.h" #include "rtc_base/numerics/safe_conversions.h" @@ -40,15 +40,15 @@ std::unique_ptr<RtcEventLogEncoder> CreateEncoder( RtcEventLog::EncodingType type) { switch (type) { case RtcEventLog::EncodingType::Legacy: - RTC_LOG(LS_INFO) << "Creating legacy encoder for RTC event log."; + RTC_DLOG(LS_INFO) << "Creating legacy encoder for RTC event log."; return std::make_unique<RtcEventLogEncoderLegacy>(); case RtcEventLog::EncodingType::NewFormat: - RTC_LOG(LS_INFO) << "Creating new format encoder for RTC event log."; + 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_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return std::unique_ptr<RtcEventLogEncoder>(nullptr); } } @@ -90,15 +90,14 @@ bool RtcEventLogImpl::StartLogging(std::unique_ptr<RtcEventLogOutput> output, return false; } - const int64_t timestamp_us = rtc::TimeMicros(); - const int64_t utc_time_us = rtc::TimeUTCMicros(); - RTC_LOG(LS_INFO) << "Starting WebRTC event log. (Timestamp, UTC) = " - "(" + 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_|. + // 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()); @@ -114,15 +113,15 @@ bool RtcEventLogImpl::StartLogging(std::unique_ptr<RtcEventLogOutput> output, } void RtcEventLogImpl::StopLogging() { - RTC_LOG(LS_INFO) << "Stopping WebRTC event log."; + 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_|. + // threads with the `task_queue_`. rtc::Event output_stopped; StopLogging([&output_stopped]() { output_stopped.Set(); }); output_stopped.Wait(rtc::Event::kForever); - RTC_LOG(LS_INFO) << "WebRTC event log successfully stopped."; + RTC_DLOG(LS_INFO) << "WebRTC event log successfully stopped."; } void RtcEventLogImpl::StopLogging(std::function<void()> callback) { @@ -142,7 +141,7 @@ void RtcEventLogImpl::StopLogging(std::function<void()> callback) { void RtcEventLogImpl::Log(std::unique_ptr<RtcEvent> event) { RTC_CHECK(event); - // Binding to |this| is safe because |this| outlives the |task_queue_|. + // 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)); @@ -162,7 +161,7 @@ void RtcEventLogImpl::ScheduleOutput() { 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 + // We are already on the `task_queue_` so there is no reason to post a task // if we want to output immediately. LogEventsFromMemoryToOutput(); return; @@ -170,7 +169,7 @@ void RtcEventLogImpl::ScheduleOutput() { if (!output_scheduled_) { output_scheduled_ = true; - // Binding to |this| is safe because |this| outlives the |task_queue_|. + // 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_) { @@ -183,7 +182,8 @@ void RtcEventLogImpl::ScheduleOutput() { 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(output_task, delay); + task_queue_->PostDelayedTask(std::move(output_task), + TimeDelta::Millis(delay)); } } @@ -205,7 +205,7 @@ void RtcEventLogImpl::LogEventsFromMemoryToOutput() { 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 + // 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; @@ -232,8 +232,8 @@ void RtcEventLogImpl::LogEventsFromMemoryToOutput() { } void RtcEventLogImpl::WriteConfigsAndHistoryToOutput( - const std::string& encoded_configs, - const std::string& encoded_history) { + 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. @@ -242,7 +242,11 @@ void RtcEventLogImpl::WriteConfigsAndHistoryToOutput( } else if (encoded_history.empty()) { WriteToOutput(encoded_configs); // Very unusual case. } else { - WriteToOutput(encoded_configs + encoded_history); + 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); } } @@ -253,13 +257,13 @@ void RtcEventLogImpl::StopOutput() { void RtcEventLogImpl::StopLoggingInternal() { if (event_output_) { RTC_DCHECK(event_output_->IsActive()); - const int64_t timestamp_us = rtc::TimeMicros(); + const int64_t timestamp_us = rtc::TimeMillis() * 1000; event_output_->Write(event_encoder_->EncodeLogEnd(timestamp_us)); } StopOutput(); } -void RtcEventLogImpl::WriteToOutput(const std::string& output_string) { +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."; diff --git a/logging/rtc_event_log/rtc_event_log_impl.h b/logging/rtc_event_log/rtc_event_log_impl.h index 9c7aae669d..6c6417254e 100644 --- a/logging/rtc_event_log/rtc_event_log_impl.h +++ b/logging/rtc_event_log/rtc_event_log_impl.h @@ -17,13 +17,15 @@ #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/synchronization/sequence_checker.h" +#include "rtc_base/system/no_unique_address.h" #include "rtc_base/task_queue.h" #include "rtc_base/thread_annotations.h" @@ -53,10 +55,10 @@ class RtcEventLogImpl final : public RtcEventLog { void StopOutput() RTC_RUN_ON(task_queue_); - void WriteConfigsAndHistoryToOutput(const std::string& encoded_configs, - const std::string& encoded_history) + void WriteConfigsAndHistoryToOutput(absl::string_view encoded_configs, + absl::string_view encoded_history) RTC_RUN_ON(task_queue_); - void WriteToOutput(const std::string& output_string) RTC_RUN_ON(task_queue_); + void WriteToOutput(absl::string_view output_string) RTC_RUN_ON(task_queue_); void StopLoggingInternal() RTC_RUN_ON(task_queue_); @@ -78,11 +80,11 @@ class RtcEventLogImpl final : public RtcEventLog { int64_t last_output_ms_ RTC_GUARDED_BY(*task_queue_); bool output_scheduled_ RTC_GUARDED_BY(*task_queue_); - SequenceChecker logging_state_checker_; + 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_| + // 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_; diff --git a/logging/rtc_event_log/rtc_event_log_parser.cc b/logging/rtc_event_log/rtc_event_log_parser.cc index c88207607c..7e471ddd0f 100644 --- a/logging/rtc_event_log/rtc_event_log_parser.cc +++ b/logging/rtc_event_log/rtc_event_log_parser.cc @@ -14,35 +14,37 @@ #include <string.h> #include <algorithm> -#include <fstream> -#include <istream> // no-presubmit-check TODO(webrtc:8982) #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/include/module_common_types.h" #include "modules/include/module_common_types_public.h" -#include "modules/remote_bitrate_estimator/include/bwe_defines.h" #include "modules/rtp_rtcp/include/rtp_cvo.h" #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" #include "modules/rtp_rtcp/source/byte_io.h" #include "modules/rtp_rtcp/source/rtp_header_extensions.h" -#include "modules/rtp_rtcp/source/rtp_utility.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_util.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 @@ -54,6 +56,12 @@ 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))) \ @@ -99,6 +107,8 @@ 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; @@ -173,7 +183,7 @@ RtcpMode GetRuntimeRtcpMode(rtclog::VideoReceiveConfig::RtcpMode rtcp_mode) { case rtclog::VideoReceiveConfig::RTCP_REDUCEDSIZE: return RtcpMode::kReducedSize; } - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return RtcpMode::kOff; } @@ -187,7 +197,7 @@ BandwidthUsage GetRuntimeDetectorState( case rtclog::DelayBasedBweUpdate::BWE_OVERUSING: return BandwidthUsage::kBwOverusing; } - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return BandwidthUsage::kBwNormal; } @@ -203,7 +213,7 @@ IceCandidatePairConfigType GetRuntimeIceCandidatePairConfigType( case rtclog::IceCandidatePairConfig::SELECTED: return IceCandidatePairConfigType::kSelected; } - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return IceCandidatePairConfigType::kAdded; } @@ -221,7 +231,7 @@ IceCandidateType GetRuntimeIceCandidateType( case rtclog::IceCandidatePairConfig::UNKNOWN_CANDIDATE_TYPE: return IceCandidateType::kUnknown; } - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return IceCandidateType::kUnknown; } @@ -239,7 +249,7 @@ IceCandidatePairProtocol GetRuntimeIceCandidatePairProtocol( case rtclog::IceCandidatePairConfig::UNKNOWN_PROTOCOL: return IceCandidatePairProtocol::kUnknown; } - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return IceCandidatePairProtocol::kUnknown; } @@ -253,7 +263,7 @@ IceCandidatePairAddressFamily GetRuntimeIceCandidatePairAddressFamily( case rtclog::IceCandidatePairConfig::UNKNOWN_ADDRESS_FAMILY: return IceCandidatePairAddressFamily::kUnknown; } - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return IceCandidatePairAddressFamily::kUnknown; } @@ -273,7 +283,7 @@ IceCandidateNetworkType GetRuntimeIceCandidateNetworkType( case rtclog::IceCandidatePairConfig::UNKNOWN_NETWORK_TYPE: return IceCandidateNetworkType::kUnknown; } - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return IceCandidateNetworkType::kUnknown; } @@ -289,35 +299,29 @@ IceCandidatePairEventType GetRuntimeIceCandidatePairEventType( case rtclog::IceCandidatePairEvent::CHECK_RESPONSE_RECEIVED: return IceCandidatePairEventType::kCheckResponseReceived; } - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return IceCandidatePairEventType::kCheckSent; } -// Reads a VarInt from |stream| and returns it. Also writes the read bytes to -// |buffer| starting |bytes_written| bytes into the buffer. |bytes_written| is -// incremented for each written byte. -ParsedRtcEventLog::ParseStatusOr<uint64_t> ParseVarInt( - std::istream& stream, // no-presubmit-check TODO(webrtc:8982) - char* buffer, - size_t* bytes_written) { - uint64_t varint = 0; - for (size_t bytes_read = 0; bytes_read < 10; ++bytes_read) { - // The most significant bit of each byte is 0 if it is the last byte in - // the varint and 1 otherwise. Thus, we take the 7 least significant bits - // of each byte and shift them 7 bits for each byte read previously to get - // the (unsigned) integer. - int byte = stream.get(); - RTC_PARSE_CHECK_OR_RETURN(!stream.eof()); - RTC_DCHECK_GE(byte, 0); - RTC_DCHECK_LE(byte, 255); - varint |= static_cast<uint64_t>(byte & 0x7F) << (7 * bytes_read); - buffer[*bytes_written] = byte; - *bytes_written += 1; - if ((byte & 0x80) == 0) { - return varint; - } - } - RTC_PARSE_CHECK_OR_RETURN(false); +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( @@ -395,7 +399,7 @@ ParsedRtcEventLog::ParseStatus StoreRtpPackets( RTC_PARSE_CHECK_OR_RETURN(!proto.has_voice_activity()); } (*rtp_packets_map)[header.ssrc].emplace_back( - proto.timestamp_ms() * 1000, header, proto.header_size(), + Timestamp::Millis(proto.timestamp_ms()), header, proto.header_size(), proto.payload_size() + header.headerLength + header.paddingLength); } @@ -528,7 +532,7 @@ ParsedRtcEventLog::ParseStatus StoreRtpPackets( number_of_deltas); } - // Delta decoding + // 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()); @@ -597,7 +601,7 @@ ParsedRtcEventLog::ParseStatus StoreRtpPackets( !voice_activity_values[i].has_value()); } (*rtp_packets_map)[header.ssrc].emplace_back( - 1000 * timestamp_ms, header, header.headerLength, + Timestamp::Millis(timestamp_ms), header, header.headerLength, payload_size_values[i].value() + header.headerLength + header.paddingLength); } @@ -620,7 +624,8 @@ ParsedRtcEventLog::ParseStatus StoreRtcpPackets( !IdenticalRtcpContents(rtcp_packets->back().rtcp.raw_data, proto.raw_packet())) { // Base event - rtcp_packets->emplace_back(proto.timestamp_ms() * 1000, proto.raw_packet()); + rtcp_packets->emplace_back(Timestamp::Millis(proto.timestamp_ms()), + proto.raw_packet()); } const size_t number_of_deltas = @@ -641,7 +646,7 @@ ParsedRtcEventLog::ParseStatus StoreRtcpPackets( DecodeBlobs(proto.raw_packet_blobs(), number_of_deltas); RTC_PARSE_CHECK_OR_RETURN_EQ(raw_packet_values.size(), number_of_deltas); - // Delta decoding + // 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; @@ -657,10 +662,8 @@ ParsedRtcEventLog::ParseStatus StoreRtcpPackets( raw_packet_values[i])) { continue; } - const size_t data_size = raw_packet_values[i].size(); - const uint8_t* data = - reinterpret_cast<const uint8_t*>(raw_packet_values[i].data()); - rtcp_packets->emplace_back(1000 * timestamp_ms, data, data_size); + std::string data(raw_packet_values[i]); + rtcp_packets->emplace_back(Timestamp::Millis(timestamp_ms), data); } return ParsedRtcEventLog::ParseStatus::Success(); } @@ -676,8 +679,10 @@ ParsedRtcEventLog::ParseStatus StoreRtcpBlocks( 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()) { @@ -685,47 +690,47 @@ ParsedRtcEventLog::ParseStatus StoreRtcpBlocks( if (header.type() == rtcp::TransportFeedback::kPacketType && header.fmt() == rtcp::TransportFeedback::kFeedbackMessageType) { LoggedRtcpPacketTransportFeedback parsed_block; - parsed_block.timestamp_us = timestamp_us; - if (parsed_block.transport_feedback.Parse(header)) - transport_feedback_list->push_back(std::move(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_us = timestamp_us; - if (parsed_block.sr.Parse(header)) { - sr_list->push_back(std::move(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_us = timestamp_us; - if (parsed_block.rr.Parse(header)) { - rr_list->push_back(std::move(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_us = timestamp_us; - if (parsed_block.xr.Parse(header)) { - xr_list->push_back(std::move(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_us = timestamp_us; - if (parsed_block.fir.Parse(header)) { - fir_list->push_back(std::move(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_us = timestamp_us; - if (parsed_block.pli.Parse(header)) { - pli_list->push_back(std::move(parsed_block)); - } - } else if (header.type() == rtcp::Remb::kPacketType && + 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_us = timestamp_us; + parsed_block.timestamp = timestamp; if (parsed_block.remb.Parse(header)) { remb_list->push_back(std::move(parsed_block)); type_found = true; @@ -733,19 +738,19 @@ ParsedRtcEventLog::ParseStatus StoreRtcpBlocks( } if (!type_found) { LoggedRtcpPacketLossNotification parsed_block; - parsed_block.timestamp_us = timestamp_us; + 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_us = timestamp_us; - if (parsed_block.nack.Parse(header)) { - nack_list->push_back(std::move(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(); @@ -766,7 +771,7 @@ BandwidthUsage GetRuntimeDetectorState( case rtclog2::DelayBasedBweUpdates::BWE_UNKNOWN_STATE: break; } - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return BandwidthUsage::kBwNormal; } @@ -782,7 +787,7 @@ ProbeFailureReason GetRuntimeProbeFailureReason( case rtclog2::BweProbeResultFailure::UNKNOWN: break; } - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return ProbeFailureReason::kTimeout; } @@ -800,10 +805,10 @@ DtlsTransportState GetRuntimeDtlsTransportState( case rtclog2::DtlsTransportStateEvent::DTLS_TRANSPORT_FAILED: return DtlsTransportState::kFailed; case rtclog2::DtlsTransportStateEvent::UNKNOWN_DTLS_TRANSPORT_STATE: - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return DtlsTransportState::kNumValues; } - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return DtlsTransportState::kNumValues; } @@ -821,7 +826,7 @@ IceCandidatePairConfigType GetRuntimeIceCandidatePairConfigType( case rtclog2::IceCandidatePairConfig::UNKNOWN_CONFIG_TYPE: break; } - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return IceCandidatePairConfigType::kAdded; } @@ -839,7 +844,7 @@ IceCandidateType GetRuntimeIceCandidateType( case rtclog2::IceCandidatePairConfig::UNKNOWN_CANDIDATE_TYPE: return IceCandidateType::kUnknown; } - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return IceCandidateType::kUnknown; } @@ -857,7 +862,7 @@ IceCandidatePairProtocol GetRuntimeIceCandidatePairProtocol( case rtclog2::IceCandidatePairConfig::UNKNOWN_PROTOCOL: return IceCandidatePairProtocol::kUnknown; } - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return IceCandidatePairProtocol::kUnknown; } @@ -871,7 +876,7 @@ IceCandidatePairAddressFamily GetRuntimeIceCandidatePairAddressFamily( case rtclog2::IceCandidatePairConfig::UNKNOWN_ADDRESS_FAMILY: return IceCandidatePairAddressFamily::kUnknown; } - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return IceCandidatePairAddressFamily::kUnknown; } @@ -891,7 +896,7 @@ IceCandidateNetworkType GetRuntimeIceCandidateNetworkType( case rtclog2::IceCandidatePairConfig::UNKNOWN_NETWORK_TYPE: return IceCandidateNetworkType::kUnknown; } - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return IceCandidateNetworkType::kUnknown; } @@ -909,7 +914,7 @@ IceCandidatePairEventType GetRuntimeIceCandidatePairEventType( case rtclog2::IceCandidatePairEvent::UNKNOWN_CHECK_TYPE: break; } - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return IceCandidatePairEventType::kCheckSent; } @@ -943,6 +948,35 @@ std::vector<RtpExtension> GetRuntimeRtpHeaderExtensionConfig( } // 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; @@ -959,23 +993,21 @@ ParsedRtcEventLog::LoggedRtpStreamOutgoing::~LoggedRtpStreamOutgoing() = ParsedRtcEventLog::LoggedRtpStreamView::LoggedRtpStreamView( uint32_t ssrc, - const LoggedRtpPacketIncoming* ptr, - size_t num_elements) - : ssrc(ssrc), - packet_view(PacketView<const LoggedRtpPacket>::Create( - ptr, - num_elements, - offsetof(LoggedRtpPacketIncoming, rtp))) {} + 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 LoggedRtpPacketOutgoing* ptr, - size_t num_elements) - : ssrc(ssrc), - packet_view(PacketView<const LoggedRtpPacket>::Create( - ptr, - num_elements, - offsetof(LoggedRtpPacketOutgoing, rtp))) {} + 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; @@ -1063,6 +1095,7 @@ void ParsedRtcEventLog::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(); @@ -1071,11 +1104,10 @@ void ParsedRtcEventLog::Clear() { video_recv_configs_.clear(); video_send_configs_.clear(); - memset(last_incoming_rtcp_packet_, 0, IP_PACKET_SIZE); - last_incoming_rtcp_packet_length_ = 0; + last_incoming_rtcp_packet_.clear(); - first_timestamp_ = std::numeric_limits<int64_t>::max(); - last_timestamp_ = std::numeric_limits<int64_t>::min(); + first_timestamp_ = Timestamp::PlusInfinity(); + last_timestamp_ = Timestamp::MinusInfinity(); first_log_segment_ = LogSegment(0, std::numeric_limits<int64_t>::max()); incoming_rtp_extensions_maps_.clear(); @@ -1083,28 +1115,40 @@ void ParsedRtcEventLog::Clear() { } ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::ParseFile( - const std::string& filename) { - std::ifstream file( // no-presubmit-check TODO(webrtc:8982) - filename, std::ios_base::in | std::ios_base::binary); - if (!file.good() || !file.is_open()) { - RTC_LOG(LS_WARNING) << "Could not open file for reading."; - RTC_PARSE_CHECK_OR_RETURN(file.good() && file.is_open()); + 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(file); + return ParseStream(buffer); } ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::ParseString( - const std::string& s) { - std::istringstream stream( // no-presubmit-check TODO(webrtc:8982) - s, std::ios_base::in | std::ios_base::binary); - return ParseStream(stream); + absl::string_view s) { + return ParseStream(s); } ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::ParseStream( - std::istream& stream) { // no-presubmit-check TODO(webrtc:8982) + absl::string_view s) { Clear(); - ParseStatus status = ParseStreamInternal(stream); + ParseStatus status = ParseStreamInternal(s); // Cache the configured SSRCs. for (const auto& video_recv_config : video_recv_configs()) { @@ -1147,38 +1191,36 @@ ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::ParseStream( // 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.data(), - stream.incoming_packets.size())); + 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.data(), - stream.outgoing_packets.size())); + 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 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 status = StoreRtcpBlocks( + 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_transport_feedback_, + &incoming_pli_, &incoming_bye_, &incoming_transport_feedback_, &incoming_loss_notification_); - RTC_RETURN_IF_ERROR(status); + RTC_RETURN_IF_ERROR(store_rtcp_status); } for (const auto& outgoing : outgoing_rtcp_packets_) { - const int64_t timestamp_us = outgoing.rtcp.timestamp_us; + 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 status = StoreRtcpBlocks( + 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_transport_feedback_, + &outgoing_pli_, &outgoing_bye_, &outgoing_transport_feedback_, &outgoing_loss_notification_); - RTC_RETURN_IF_ERROR(status); + RTC_RETURN_IF_ERROR(store_rtcp_status); } // Store first and last timestamp events that might happen before the call is @@ -1186,8 +1228,8 @@ ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::ParseStream( // 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_ = std::numeric_limits<int64_t>::max(); - last_timestamp_ = std::numeric_limits<int64_t>::min(); + first_timestamp_ = Timestamp::PlusInfinity(); + last_timestamp_ = Timestamp::MinusInfinity(); StoreFirstAndLastTimestamp(alr_state_events()); StoreFirstAndLastTimestamp(route_change_events()); for (const auto& audio_stream : audio_playout_events()) { @@ -1200,6 +1242,9 @@ ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::ParseStream( 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()); @@ -1223,7 +1268,8 @@ ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::ParseStream( // 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(); + 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()) { @@ -1237,51 +1283,62 @@ ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::ParseStream( } stop_us = std::min(stop_us, next_start_us); if (stop_us == std::numeric_limits<int64_t>::max() && - last_timestamp() != std::numeric_limits<int64_t>::min()) { - stop_us = last_timestamp(); + !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_ == std::numeric_limits<int64_t>::max() && - last_timestamp_ == std::numeric_limits<int64_t>::min()) { - first_timestamp_ = last_timestamp_ = 0; + if (first_timestamp_ > last_timestamp_) { + first_timestamp_ = last_timestamp_ = Timestamp::Zero(); } return status; } ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::ParseStreamInternal( - std::istream& stream) { // no-presubmit-check TODO(webrtc:8982) + absl::string_view s) { constexpr uint64_t kMaxEventSize = 10000000; // Sanity check. - std::vector<char> buffer(0xFFFF); - - RTC_DCHECK(stream.good()); - while (1) { - // Check whether we have reached end of file. - stream.peek(); - if (stream.eof()) { - break; - } - - // Read the next message tag. Protobuf defines the message tag as - // (field_number << 3) | wire_type. In the legacy encoding, the field number - // is supposed to be 1 and the wire type for a length-delimited field is 2. - // In the new encoding we still expect the wire type to be 2, but the field - // number will be greater than 1. - constexpr uint64_t kExpectedV1Tag = (1 << 3) | 2; - size_t bytes_written = 0; - ParsedRtcEventLog::ParseStatusOr<uint64_t> tag = - ParseVarInt(stream, buffer.data(), &bytes_written); - if (!tag.ok()) { + // 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) - << "Missing field tag from beginning of protobuf event."; + << "Failed to read field tag from beginning of protobuf event."; RTC_PARSE_WARN_AND_RETURN_SUCCESS_IF(allow_incomplete_logs_, kIncompleteLogError); - return tag.status(); + return ParseStatus::Error("Failed to read field tag varint", __FILE__, + __LINE__); } + constexpr uint64_t kWireTypeMask = 0x07; - const uint64_t wire_type = tag.value() & kWireTypeMask; + 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 " @@ -1292,36 +1349,37 @@ ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::ParseStreamInternal( } // Read the length field. - ParsedRtcEventLog::ParseStatusOr<uint64_t> message_length = - ParseVarInt(stream, buffer.data(), &bytes_written); - if (!message_length.ok()) { + 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 message_length.status(); - } else if (message_length.value() > kMaxEventSize) { - RTC_LOG(LS_WARNING) << "Protobuf message length is too large."; - RTC_PARSE_WARN_AND_RETURN_SUCCESS_IF(allow_incomplete_logs_, - kIncompleteLogError); - RTC_PARSE_CHECK_OR_RETURN_LE(message_length.value(), kMaxEventSize); + return ParseStatus::Error("Failed to read message length varint", + __FILE__, __LINE__); } - // Read the next protobuf event to a temporary char buffer. - if (buffer.size() < bytes_written + message_length.value()) - buffer.resize(bytes_written + message_length.value()); - stream.read(buffer.data() + bytes_written, message_length.value()); - if (stream.gcount() != static_cast<int>(message_length.value())) { - RTC_LOG(LS_WARNING) << "Failed to read protobuf message."; + 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); - RTC_PARSE_CHECK_OR_RETURN(false); + return ParseStatus::Error( + "Incomplete message: the length of the next message is larger than " + "the remaining bytes in the proto", + __FILE__, __LINE__); } - size_t buffer_size = bytes_written + message_length.value(); - if (tag.value() == kExpectedV1Tag) { + 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(buffer.data(), buffer_size)) { + 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_, @@ -1335,7 +1393,7 @@ ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::ParseStreamInternal( } else { // Parse the protobuf event from the buffer. rtclog2::EventStream event_stream; - if (!event_stream.ParseFromArray(buffer.data(), buffer_size)) { + 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); @@ -1348,18 +1406,166 @@ ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::ParseStreamInternal( 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_us()); - last_timestamp_ = std::max(last_timestamp_, v.back().log_time_us()); + 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()); - RTC_PARSE_CHECK_OR_RETURN(event.has_type()); switch (event.type()) { case rtclog::Event::VIDEO_RECEIVER_CONFIG_EVENT: { auto config = GetVideoReceiveConfig(event); @@ -1368,7 +1574,8 @@ ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreParsedLegacyEvent( RTC_PARSE_CHECK_OR_RETURN(event.has_timestamp_us()); int64_t timestamp_us = event.timestamp_us(); - video_recv_configs_.emplace_back(timestamp_us, config.value()); + 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] = @@ -1382,7 +1589,8 @@ ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreParsedLegacyEvent( RTC_PARSE_CHECK_OR_RETURN(event.has_timestamp_us()); int64_t timestamp_us = event.timestamp_us(); - video_send_configs_.emplace_back(timestamp_us, config.value()); + 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] = @@ -1396,7 +1604,8 @@ ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreParsedLegacyEvent( RTC_PARSE_CHECK_OR_RETURN(event.has_timestamp_us()); int64_t timestamp_us = event.timestamp_us(); - audio_recv_configs_.emplace_back(timestamp_us, config.value()); + 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; @@ -1407,84 +1616,91 @@ ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreParsedLegacyEvent( 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_us, config.value()); + 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: { - PacketDirection direction; - uint8_t header[IP_PACKET_SIZE]; - size_t header_length; - size_t total_length; - ParseStatus status = GetRtpHeader(event, &direction, header, - &header_length, &total_length, nullptr); - RTC_RETURN_IF_ERROR(status); + 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); + } - uint32_t ssrc = ByteReader<uint32_t>::ReadBigEndian(header + 8); - const RtpHeaderExtensionMap* extension_map = - GetRtpHeaderExtensionMap(direction, ssrc); - RtpUtility::RtpHeaderParser rtp_parser(header, header_length); RTPHeader parsed_header; - rtp_parser.Parse(&parsed_header, extension_map, /*header_only*/ true); + 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 ((header[0] & 0x20) != 0) - parsed_header.paddingLength = total_length - header_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 (direction == kIncomingPacket) { + if (rtp_packet.incoming()) { incoming_rtp_packets_map_[parsed_header.ssrc].push_back( - LoggedRtpPacketIncoming(timestamp_us, parsed_header, header_length, + LoggedRtpPacketIncoming(Timestamp::Micros(timestamp_us), + parsed_header, rtp_header.size(), total_length)); } else { outgoing_rtp_packets_map_[parsed_header.ssrc].push_back( - LoggedRtpPacketOutgoing(timestamp_us, parsed_header, header_length, + LoggedRtpPacketOutgoing(Timestamp::Micros(timestamp_us), + parsed_header, rtp_header.size(), total_length)); } break; } case rtclog::Event::RTCP_EVENT: { PacketDirection direction; - uint8_t packet[IP_PACKET_SIZE]; - size_t total_length; - auto status = GetRtcpPacket(event, &direction, packet, &total_length); + 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(); - RTC_PARSE_CHECK_OR_RETURN_LE(total_length, IP_PACKET_SIZE); 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 (total_length == last_incoming_rtcp_packet_length_ && - memcmp(last_incoming_rtcp_packet_, packet, total_length) == 0) + if (packet == last_incoming_rtcp_packet_) break; incoming_rtcp_packets_.push_back( - LoggedRtcpPacketIncoming(timestamp_us, packet, total_length)); - last_incoming_rtcp_packet_length_ = total_length; - memcpy(last_incoming_rtcp_packet_, packet, total_length); + LoggedRtcpPacketIncoming(Timestamp::Micros(timestamp_us), packet)); + last_incoming_rtcp_packet_ = packet; } else { outgoing_rtcp_packets_.push_back( - LoggedRtcpPacketOutgoing(timestamp_us, packet, total_length)); + 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_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_us)); + stop_log_events_.push_back( + LoggedStopEvent(Timestamp::Micros(timestamp_us))); break; } case rtclog::Event::AUDIO_PLAYOUT_EVENT: { @@ -1554,88 +1770,44 @@ ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreParsedLegacyEvent( ice_candidate_pair_events_.push_back(status_or_value.value()); break; } - case rtclog::Event::UNKNOWN_EVENT: { + 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; } - } - return ParseStatus::Success(); -} - -// The header must have space for at least IP_PACKET_SIZE bytes. -ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::GetRtpHeader( - const rtclog::Event& event, - PacketDirection* incoming, - uint8_t* header, - size_t* header_length, - size_t* total_length, - int* probe_cluster_id) const { - RTC_PARSE_CHECK_OR_RETURN(event.has_type()); - RTC_PARSE_CHECK_OR_RETURN_EQ(event.type(), rtclog::Event::RTP_EVENT); - RTC_PARSE_CHECK_OR_RETURN(event.has_rtp_packet()); - const rtclog::RtpPacket& rtp_packet = event.rtp_packet(); - // Get direction of packet. - RTC_PARSE_CHECK_OR_RETURN(rtp_packet.has_incoming()); - if (incoming != nullptr) { - *incoming = rtp_packet.incoming() ? kIncomingPacket : kOutgoingPacket; - } - // Get packet length. - RTC_PARSE_CHECK_OR_RETURN(rtp_packet.has_packet_length()); - if (total_length != nullptr) { - *total_length = rtp_packet.packet_length(); - } - // Get header length. - RTC_PARSE_CHECK_OR_RETURN(rtp_packet.has_header()); - if (header_length != nullptr) { - *header_length = rtp_packet.header().size(); - } - if (probe_cluster_id != nullptr) { - if (rtp_packet.has_probe_cluster_id()) { - *probe_cluster_id = rtp_packet.probe_cluster_id(); - RTC_PARSE_CHECK_OR_RETURN_NE(*probe_cluster_id, - PacedPacketInfo::kNotAProbe); - } else { - *probe_cluster_id = PacedPacketInfo::kNotAProbe; + case rtclog::Event::UNKNOWN_EVENT: { + break; } } - // Get header contents. - if (header != nullptr) { - const size_t kMinRtpHeaderSize = 12; - RTC_PARSE_CHECK_OR_RETURN_GE(rtp_packet.header().size(), kMinRtpHeaderSize); - RTC_PARSE_CHECK_OR_RETURN_LE(rtp_packet.header().size(), - static_cast<size_t>(IP_PACKET_SIZE)); - memcpy(header, rtp_packet.header().data(), rtp_packet.header().size()); - } return ParseStatus::Success(); } const RtpHeaderExtensionMap* ParsedRtcEventLog::GetRtpHeaderExtensionMap( - PacketDirection direction, + bool incoming, uint32_t ssrc) { - auto& extensions_maps = direction == PacketDirection::kIncomingPacket - ? incoming_rtp_extensions_maps_ - : outgoing_rtp_extensions_maps_; + 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_LOG(LS_WARNING) << "Using default header extension map for SSRC " - << ssrc; + 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_LOG(LS_WARNING) << "Not parsing header extensions for SSRC " << ssrc - << ". No header extension map found."; + RTC_DLOG(LS_WARNING) << "Not parsing header extensions for SSRC " << ssrc + << ". No header extension map found."; return nullptr; } -// The packet must have space for at least IP_PACKET_SIZE bytes. ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::GetRtcpPacket( const rtclog::Event& event, PacketDirection* incoming, - uint8_t* packet, - size_t* length) const { + 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()); @@ -1645,16 +1817,11 @@ ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::GetRtcpPacket( if (incoming != nullptr) { *incoming = rtcp_packet.incoming() ? kIncomingPacket : kOutgoingPacket; } - // Get packet length. - RTC_PARSE_CHECK_OR_RETURN(rtcp_packet.has_packet_data()); - if (length != nullptr) { - *length = rtcp_packet.packet_data().size(); - } // Get packet contents. + RTC_PARSE_CHECK_OR_RETURN(rtcp_packet.has_packet_data()); if (packet != nullptr) { - RTC_PARSE_CHECK_OR_RETURN_LE(rtcp_packet.packet_data().size(), - static_cast<unsigned>(IP_PACKET_SIZE)); - memcpy(packet, rtcp_packet.packet_data().data(), + packet->resize(rtcp_packet.packet_data().size()); + memcpy(packet->data(), rtcp_packet.packet_data().data(), rtcp_packet.packet_data().size()); } return ParseStatus::Success(); @@ -1810,7 +1977,7 @@ ParsedRtcEventLog::GetAudioPlayout(const rtclog::Event& event) const { const rtclog::AudioPlayoutEvent& playout_event = event.audio_playout_event(); LoggedAudioPlayoutEvent res; RTC_PARSE_CHECK_OR_RETURN(event.has_timestamp_us()); - res.timestamp_us = event.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; @@ -1826,7 +1993,7 @@ ParsedRtcEventLog::GetLossBasedBweUpdate(const rtclog::Event& event) const { LoggedBweLossBasedUpdate bwe_update; RTC_CHECK(event.has_timestamp_us()); - bwe_update.timestamp_us = event.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()); @@ -1847,7 +2014,7 @@ ParsedRtcEventLog::GetDelayBasedBweUpdate(const rtclog::Event& event) const { LoggedBweDelayBasedUpdate res; RTC_PARSE_CHECK_OR_RETURN(event.has_timestamp_us()); - res.timestamp_us = event.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()); @@ -1866,7 +2033,7 @@ ParsedRtcEventLog::GetAudioNetworkAdaptation(const rtclog::Event& event) const { LoggedAudioNetworkAdaptationEvent res; RTC_PARSE_CHECK_OR_RETURN(event.has_timestamp_us()); - res.timestamp_us = event.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()) @@ -1892,7 +2059,7 @@ ParsedRtcEventLog::GetBweProbeClusterCreated(const rtclog::Event& event) const { const rtclog::BweProbeCluster& pcc_event = event.probe_cluster(); LoggedBweProbeClusterCreatedEvent res; RTC_PARSE_CHECK_OR_RETURN(event.has_timestamp_us()); - res.timestamp_us = event.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()); @@ -1917,7 +2084,7 @@ ParsedRtcEventLog::GetBweProbeFailure(const rtclog::Event& event) const { LoggedBweProbeFailureEvent res; RTC_PARSE_CHECK_OR_RETURN(event.has_timestamp_us()); - res.timestamp_us = event.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()); @@ -1930,7 +2097,7 @@ ParsedRtcEventLog::GetBweProbeFailure(const rtclog::Event& event) const { } else if (pr_event.result() == rtclog::BweProbeResult::TIMEOUT) { res.failure_reason = ProbeFailureReason::kTimeout; } else { - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); } RTC_PARSE_CHECK_OR_RETURN(!pr_event.has_bitrate_bps()); @@ -1950,7 +2117,7 @@ ParsedRtcEventLog::GetBweProbeSuccess(const rtclog::Event& event) const { LoggedBweProbeSuccessEvent res; RTC_PARSE_CHECK_OR_RETURN(event.has_timestamp_us()); - res.timestamp_us = event.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()); @@ -1967,7 +2134,7 @@ ParsedRtcEventLog::GetAlrState(const rtclog::Event& event) const { const rtclog::AlrState& alr_event = event.alr_state(); LoggedAlrStateEvent res; RTC_PARSE_CHECK_OR_RETURN(event.has_timestamp_us()); - res.timestamp_us = event.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(); @@ -1983,8 +2150,8 @@ ParsedRtcEventLog::GetIceCandidatePairConfig( LoggedIceCandidatePairConfig res; const rtclog::IceCandidatePairConfig& config = rtc_event.ice_candidate_pair_config(); - RTC_CHECK(rtc_event.has_timestamp_us()); - res.timestamp_us = rtc_event.timestamp_us(); + 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()); @@ -2022,8 +2189,8 @@ ParsedRtcEventLog::GetIceCandidatePairEvent( LoggedIceCandidatePairEvent res; const rtclog::IceCandidatePairEvent& event = rtc_event.ice_candidate_pair_event(); - RTC_CHECK(rtc_event.has_timestamp_us()); - res.timestamp_us = rtc_event.timestamp_us(); + 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()); @@ -2033,6 +2200,23 @@ ParsedRtcEventLog::GetIceCandidatePairEvent( 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( @@ -2120,12 +2304,12 @@ std::vector<LoggedPacketInfo> ParsedRtcEventLog::GetPacketInfos( seq_num_unwrapper = SequenceNumberUnwrapper(); indices.clear(); } - RTC_DCHECK(new_log_time >= last_log_time); + RTC_DCHECK_GE(new_log_time, last_log_time); last_log_time = new_log_time; }; auto rtp_handler = [&](const LoggedRtpPacket& rtp) { - advance_time(Timestamp::Millis(rtp.log_time_ms())); + advance_time(rtp.log_time()); MediaStreamInfo* stream = &streams[rtp.header.ssrc]; Timestamp capture_time = Timestamp::MinusInfinity(); if (!stream->rtx) { @@ -2133,9 +2317,9 @@ std::vector<LoggedPacketInfo> ParsedRtcEventLog::GetPacketInfos( // 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 + // Add an offset to avoid `capture_ticks` to become negative in the case // of reordering. - constexpr int64_t kStartingCaptureTimeTicks = 90 * 48 * 1000; + constexpr int64_t kStartingCaptureTimeTicks = 90 * 48 * 10000; int64_t capture_ticks = kStartingCaptureTimeTicks + stream->unwrap_capture_ticks.Unwrap(rtp.header.timestamp); @@ -2164,23 +2348,22 @@ std::vector<LoggedPacketInfo> ParsedRtcEventLog::GetPacketInfos( }; Timestamp feedback_base_time = Timestamp::MinusInfinity(); - absl::optional<int64_t> last_feedback_base_time_us; + Timestamp last_feedback_base_time = Timestamp::MinusInfinity(); auto feedback_handler = [&](const LoggedRtcpPacketTransportFeedback& logged_rtcp) { - auto log_feedback_time = Timestamp::Millis(logged_rtcp.log_time_ms()); + 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_us) { + if (!last_feedback_base_time.IsFinite()) { feedback_base_time = log_feedback_time; } else { - feedback_base_time += TimeDelta::Micros( - feedback.GetBaseDeltaUs(*last_feedback_base_time_us)); + feedback_base_time += feedback.GetBaseDelta(last_feedback_base_time); } - last_feedback_base_time_us = feedback.GetBaseTimeUs(); + last_feedback_base_time = feedback.BaseTime(); std::vector<LoggedPacketInfo*> packet_feedbacks; packet_feedbacks.reserve(feedback.GetAllPackets().size()); @@ -2202,10 +2385,9 @@ std::vector<LoggedPacketInfo> ParsedRtcEventLog::GetPacketInfos( continue; } if (packet.received()) { - receive_timestamp += TimeDelta::Micros(packet.delta_us()); + receive_timestamp += packet.delta(); if (sent->reported_recv_time.IsInfinite()) { - sent->reported_recv_time = - Timestamp::Millis(receive_timestamp.ms()); + sent->reported_recv_time = receive_timestamp; sent->log_feedback_time = log_feedback_time; } } else { @@ -2228,8 +2410,11 @@ std::vector<LoggedPacketInfo> ParsedRtcEventLog::GetPacketInfos( last->last_in_feedback = true; for (LoggedPacketInfo* fb : packet_feedbacks) { if (direction == PacketDirection::kOutgoingPacket) { - fb->feedback_hold_duration = - last->reported_recv_time - fb->reported_recv_time; + 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; @@ -2337,7 +2522,8 @@ ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreParsedNewFormatEvent( stream.video_send_stream_configs_size() + stream.generic_packets_sent_size() + stream.generic_packets_received_size() + - stream.generic_acks_received_size(), + stream.generic_acks_received_size() + + stream.frame_decoded_events_size(), 1u); if (stream.incoming_rtp_packets_size() == 1) { @@ -2395,8 +2581,10 @@ ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreParsedNewFormatEvent( 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 { - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return ParseStatus::Success(); } } @@ -2406,7 +2594,7 @@ ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreAlrStateEvent( RTC_PARSE_CHECK_OR_RETURN(proto.has_timestamp_ms()); RTC_PARSE_CHECK_OR_RETURN(proto.has_in_alr()); LoggedAlrStateEvent alr_event; - alr_event.timestamp_us = proto.timestamp_ms() * 1000; + alr_event.timestamp = Timestamp::Millis(proto.timestamp_ms()); alr_event.in_alr = proto.in_alr(); alr_state_events_.push_back(alr_event); @@ -2420,7 +2608,7 @@ ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreRouteChangeEvent( RTC_PARSE_CHECK_OR_RETURN(proto.has_connected()); RTC_PARSE_CHECK_OR_RETURN(proto.has_overhead()); LoggedRouteChangeEvent route_event; - route_event.timestamp_ms = proto.timestamp_ms(); + route_event.timestamp = Timestamp::Millis(proto.timestamp_ms()); route_event.connected = proto.connected(); route_event.overhead = proto.overhead(); @@ -2434,7 +2622,7 @@ ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreRemoteEstimateEvent( RTC_PARSE_CHECK_OR_RETURN(proto.has_timestamp_ms()); // Base event LoggedRemoteEstimateEvent base_event; - base_event.timestamp_ms = proto.timestamp_ms(); + base_event.timestamp = Timestamp::Millis(proto.timestamp_ms()); absl::optional<uint64_t> base_link_capacity_lower_kbps; if (proto.has_link_capacity_lower_kbps()) { @@ -2478,11 +2666,11 @@ ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreRemoteEstimateEvent( RTC_PARSE_CHECK_OR_RETURN_EQ(link_capacity_upper_kbps_values.size(), number_of_deltas); - // Delta decoding + // 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_ms = *timestamp_ms_values[i]; + 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]); @@ -2500,9 +2688,8 @@ ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreAudioPlayoutEvent( RTC_PARSE_CHECK_OR_RETURN(proto.has_local_ssrc()); // Base event - auto map_it = audio_playout_events_[proto.local_ssrc()]; audio_playout_events_[proto.local_ssrc()].emplace_back( - 1000 * proto.timestamp_ms(), proto.local_ssrc()); + Timestamp::Millis(proto.timestamp_ms()), proto.local_ssrc()); const size_t number_of_deltas = proto.has_number_of_deltas() ? proto.number_of_deltas() : 0u; @@ -2521,7 +2708,7 @@ ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreAudioPlayoutEvent( proto.local_ssrc_deltas(), proto.local_ssrc(), number_of_deltas); RTC_PARSE_CHECK_OR_RETURN_EQ(local_ssrc_values.size(), number_of_deltas); - // Delta decoding + // 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()); @@ -2534,8 +2721,8 @@ ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreAudioPlayoutEvent( const uint32_t local_ssrc = static_cast<uint32_t>(local_ssrc_values[i].value()); - audio_playout_events_[local_ssrc].emplace_back(1000 * timestamp_ms, - local_ssrc); + audio_playout_events_[local_ssrc].emplace_back( + Timestamp::Millis(timestamp_ms), local_ssrc); } return ParseStatus::Success(); } @@ -2568,8 +2755,8 @@ ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreStartEvent( 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(proto.timestamp_ms() * 1000, - proto.utc_time_ms()); + LoggedStartEvent start_event(Timestamp::Millis(proto.timestamp_ms()), + Timestamp::Millis(proto.utc_time_ms())); start_log_events_.push_back(start_event); return ParseStatus::Success(); @@ -2578,7 +2765,7 @@ ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreStartEvent( ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreStopEvent( const rtclog2::EndLogEvent& proto) { RTC_PARSE_CHECK_OR_RETURN(proto.has_timestamp_ms()); - LoggedStopEvent stop_event(proto.timestamp_ms() * 1000); + LoggedStopEvent stop_event(Timestamp::Millis(proto.timestamp_ms())); stop_log_events_.push_back(stop_event); return ParseStatus::Success(); @@ -2592,7 +2779,7 @@ ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreBweLossBasedUpdate( RTC_PARSE_CHECK_OR_RETURN(proto.has_total_packets()); // Base event - bwe_loss_updates_.emplace_back(1000 * proto.timestamp_ms(), + bwe_loss_updates_.emplace_back(Timestamp::Millis(proto.timestamp_ms()), proto.bitrate_bps(), proto.fraction_loss(), proto.total_packets()); @@ -2623,7 +2810,7 @@ ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreBweLossBasedUpdate( proto.total_packets_deltas(), proto.total_packets(), number_of_deltas); RTC_PARSE_CHECK_OR_RETURN_EQ(total_packets_values.size(), number_of_deltas); - // Delta decoding + // 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; @@ -2648,7 +2835,7 @@ ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreBweLossBasedUpdate( const uint32_t total_packets = static_cast<uint32_t>(total_packets_values[i].value()); - bwe_loss_updates_.emplace_back(1000 * timestamp_ms, bitrate_bps, + bwe_loss_updates_.emplace_back(Timestamp::Millis(timestamp_ms), bitrate_bps, fraction_loss, total_packets); } return ParseStatus::Success(); @@ -2663,7 +2850,7 @@ ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreBweDelayBasedUpdate( // Base event const BandwidthUsage base_detector_state = GetRuntimeDetectorState(proto.detector_state()); - bwe_delay_updates_.emplace_back(1000 * proto.timestamp_ms(), + bwe_delay_updates_.emplace_back(Timestamp::Millis(proto.timestamp_ms()), proto.bitrate_bps(), base_detector_state); const size_t number_of_deltas = @@ -2689,7 +2876,7 @@ ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreBweDelayBasedUpdate( static_cast<uint64_t>(proto.detector_state()), number_of_deltas); RTC_PARSE_CHECK_OR_RETURN_EQ(detector_state_values.size(), number_of_deltas); - // Delta decoding + // 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; @@ -2707,7 +2894,8 @@ ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreBweDelayBasedUpdate( static_cast<rtclog2::DelayBasedBweUpdates::DetectorState>( detector_state_values[i].value()); - bwe_delay_updates_.emplace_back(1000 * timestamp_ms, bitrate_bps, + bwe_delay_updates_.emplace_back(Timestamp::Millis(timestamp_ms), + bitrate_bps, GetRuntimeDetectorState(detector_state)); } return ParseStatus::Success(); @@ -2717,7 +2905,7 @@ ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreBweProbeClusterCreated( const rtclog2::BweProbeCluster& proto) { LoggedBweProbeClusterCreatedEvent probe_cluster; RTC_PARSE_CHECK_OR_RETURN(proto.has_timestamp_ms()); - probe_cluster.timestamp_us = proto.timestamp_ms() * 1000; + 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()); @@ -2737,7 +2925,7 @@ ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreBweProbeSuccessEvent( const rtclog2::BweProbeResultSuccess& proto) { LoggedBweProbeSuccessEvent probe_result; RTC_PARSE_CHECK_OR_RETURN(proto.has_timestamp_ms()); - probe_result.timestamp_us = proto.timestamp_ms() * 1000; + 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()); @@ -2753,7 +2941,7 @@ ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreBweProbeFailureEvent( const rtclog2::BweProbeResultFailure& proto) { LoggedBweProbeFailureEvent probe_result; RTC_PARSE_CHECK_OR_RETURN(proto.has_timestamp_ms()); - probe_result.timestamp_us = proto.timestamp_ms() * 1000; + 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()); @@ -2765,6 +2953,113 @@ ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreBweProbeFailureEvent( 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(), ×tamp_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()); @@ -2777,7 +3072,7 @@ ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreGenericAckReceivedEvent( base_receive_acked_packet_time_ms = proto.receive_acked_packet_time_ms(); } generic_acks_received_.push_back( - {proto.timestamp_ms() * 1000, proto.packet_number(), + {Timestamp::Millis(proto.timestamp_ms()), proto.packet_number(), proto.acked_packet_number(), base_receive_acked_packet_time_ms}); const size_t number_of_deltas = @@ -2836,8 +3131,8 @@ ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreGenericAckReceivedEvent( ToSigned(receive_acked_packet_time_ms_values[i].value(), &value)); receive_acked_packet_time_ms = value; } - generic_acks_received_.push_back({timestamp_ms * 1000, packet_number, - acked_packet_number, + generic_acks_received_.push_back({Timestamp::Millis(timestamp_ms), + packet_number, acked_packet_number, receive_acked_packet_time_ms}); } return ParseStatus::Success(); @@ -2854,7 +3149,7 @@ ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreGenericPacketSentEvent( RTC_PARSE_CHECK_OR_RETURN(proto.has_padding_length()); generic_packets_sent_.push_back( - {proto.timestamp_ms() * 1000, proto.packet_number(), + {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())}); @@ -2882,14 +3177,12 @@ ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreGenericPacketSentEvent( 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(), - ToUnsigned(proto.payload_length()), 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(), - ToUnsigned(proto.padding_length()), 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++) { @@ -2903,7 +3196,7 @@ ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreGenericPacketSentEvent( 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_ms * 1000, packet_number, + {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())}); @@ -2920,7 +3213,7 @@ ParsedRtcEventLog::StoreGenericPacketReceivedEvent( RTC_PARSE_CHECK_OR_RETURN(proto.has_packet_number()); RTC_PARSE_CHECK_OR_RETURN(proto.has_packet_length()); - generic_packets_received_.push_back({proto.timestamp_ms() * 1000, + generic_packets_received_.push_back({Timestamp::Millis(proto.timestamp_ms()), proto.packet_number(), proto.packet_length()}); @@ -2953,11 +3246,12 @@ ParsedRtcEventLog::StoreGenericPacketReceivedEvent( int64_t packet_number; RTC_PARSE_CHECK_OR_RETURN( ToSigned(packet_number_values[i].value(), &packet_number)); - int32_t packet_length; - RTC_PARSE_CHECK_OR_RETURN( - ToSigned(packet_length_values[i].value(), &packet_length)); + 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_ms * 1000, packet_number, packet_length}); + {Timestamp::Millis(timestamp_ms), packet_number, packet_length}); } return ParseStatus::Success(); } @@ -2989,11 +3283,11 @@ ParsedRtcEventLog::StoreAudioNetworkAdaptationEvent( runtime_config.enable_dtx = proto.enable_dtx(); } if (proto.has_num_channels()) { - // Note: Encoding N as N-1 only done for |num_channels_deltas|. + // 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(1000 * proto.timestamp_ms(), - runtime_config); + audio_network_adaptation_events_.emplace_back( + Timestamp::Millis(proto.timestamp_ms()), runtime_config); } const size_t number_of_deltas = @@ -3074,7 +3368,7 @@ ParsedRtcEventLog::StoreAudioNetworkAdaptationEvent( } RTC_PARSE_CHECK_OR_RETURN_EQ(num_channels_values.size(), number_of_deltas); - // Delta decoding + // 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; @@ -3095,12 +3389,12 @@ ParsedRtcEventLog::StoreAudioNetworkAdaptationEvent( runtime_config.frame_length_ms = signed_frame_length_ms; } if (uplink_packet_loss_fraction_values[i].has_value()) { - float uplink_packet_loss_fraction; + 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_fraction)); - runtime_config.uplink_packet_loss_fraction = uplink_packet_loss_fraction; + &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 = @@ -3114,8 +3408,8 @@ ParsedRtcEventLog::StoreAudioNetworkAdaptationEvent( runtime_config.num_channels = rtc::checked_cast<size_t>(num_channels_values[i].value()); } - audio_network_adaptation_events_.emplace_back(1000 * timestamp_ms, - runtime_config); + audio_network_adaptation_events_.emplace_back( + Timestamp::Millis(timestamp_ms), runtime_config); } return ParseStatus::Success(); } @@ -3124,7 +3418,7 @@ ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreDtlsTransportState( const rtclog2::DtlsTransportStateEvent& proto) { LoggedDtlsTransportState dtls_state; RTC_PARSE_CHECK_OR_RETURN(proto.has_timestamp_ms()); - dtls_state.timestamp_us = proto.timestamp_ms() * 1000; + dtls_state.timestamp = Timestamp::Millis(proto.timestamp_ms()); RTC_PARSE_CHECK_OR_RETURN(proto.has_dtls_transport_state()); dtls_state.dtls_transport_state = @@ -3138,7 +3432,7 @@ 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_us = proto.timestamp_ms() * 1000; + dtls_writable_state.timestamp = Timestamp::Millis(proto.timestamp_ms()); RTC_PARSE_CHECK_OR_RETURN(proto.has_writable()); dtls_writable_state.writable = proto.writable(); @@ -3150,7 +3444,7 @@ ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreIceCandidatePairConfig( const rtclog2::IceCandidatePairConfig& proto) { LoggedIceCandidatePairConfig ice_config; RTC_PARSE_CHECK_OR_RETURN(proto.has_timestamp_ms()); - ice_config.timestamp_us = proto.timestamp_ms() * 1000; + ice_config.timestamp = Timestamp::Millis(proto.timestamp_ms()); RTC_PARSE_CHECK_OR_RETURN(proto.has_config_type()); ice_config.type = GetRuntimeIceCandidatePairConfigType(proto.config_type()); @@ -3188,7 +3482,7 @@ ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreIceCandidateEvent( const rtclog2::IceCandidatePairEvent& proto) { LoggedIceCandidatePairEvent ice_event; RTC_PARSE_CHECK_OR_RETURN(proto.has_timestamp_ms()); - ice_event.timestamp_us = proto.timestamp_ms() * 1000; + 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()); @@ -3208,7 +3502,7 @@ ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreVideoRecvConfig( const rtclog2::VideoRecvStreamConfig& proto) { LoggedVideoRecvConfig stream; RTC_PARSE_CHECK_OR_RETURN(proto.has_timestamp_ms()); - stream.timestamp_us = proto.timestamp_ms() * 1000; + 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()); @@ -3228,7 +3522,7 @@ ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreVideoSendConfig( const rtclog2::VideoSendStreamConfig& proto) { LoggedVideoSendConfig stream; RTC_PARSE_CHECK_OR_RETURN(proto.has_timestamp_ms()); - stream.timestamp_us = proto.timestamp_ms() * 1000; + 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()) { @@ -3246,7 +3540,7 @@ ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreAudioRecvConfig( const rtclog2::AudioRecvStreamConfig& proto) { LoggedAudioRecvConfig stream; RTC_PARSE_CHECK_OR_RETURN(proto.has_timestamp_ms()); - stream.timestamp_us = proto.timestamp_ms() * 1000; + 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()); @@ -3263,7 +3557,7 @@ ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreAudioSendConfig( const rtclog2::AudioSendStreamConfig& proto) { LoggedAudioSendConfig stream; RTC_PARSE_CHECK_OR_RETURN(proto.has_timestamp_ms()); - stream.timestamp_us = proto.timestamp_ms() * 1000; + 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()) { diff --git a/logging/rtc_event_log/rtc_event_log_parser.h b/logging/rtc_event_log/rtc_event_log_parser.h index 8d3351e815..ae2d4fe586 100644 --- a/logging/rtc_event_log/rtc_event_log_parser.h +++ b/logging/rtc_event_log/rtc_event_log_parser.h @@ -14,15 +14,43 @@ #include <limits> #include <map> #include <set> -#include <sstream> // no-presubmit-check TODO(webrtc:8982) #include <string> -#include <utility> // pair #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/logged_events.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_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" @@ -42,144 +70,182 @@ namespace webrtc { enum PacketDirection { kIncomingPacket = 0, kOutgoingPacket }; -template <typename T> -class PacketView; +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(); +}; -template <typename T> -class PacketIterator { - friend class PacketView<T>; +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; +}; - public: - // Standard iterator traits. - using difference_type = std::ptrdiff_t; - using value_type = T; - using pointer = T*; - using reference = T&; - using iterator_category = std::bidirectional_iterator_tag; +enum class LoggedIceEventType { + kAdded, + kUpdated, + kDestroyed, + kSelected, + kCheckSent, + kCheckReceived, + kCheckResponseSent, + kCheckResponseReceived, +}; - // The default-contructed iterator is meaningless, but is required by the - // ForwardIterator concept. - PacketIterator() : ptr_(nullptr), element_size_(0) {} - PacketIterator(const PacketIterator& other) - : ptr_(other.ptr_), element_size_(other.element_size_) {} - PacketIterator(const PacketIterator&& other) - : ptr_(other.ptr_), element_size_(other.element_size_) {} - ~PacketIterator() = default; +struct LoggedIceEvent { + uint32_t candidate_pair_id; + Timestamp log_time; + LoggedIceEventType event_type; +}; - PacketIterator& operator=(const PacketIterator& other) { - ptr_ = other.ptr_; - element_size_ = other.element_size_; - return *this; - } - PacketIterator& operator=(const PacketIterator&& other) { - ptr_ = other.ptr_; - element_size_ = other.element_size_; - return *this; - } +// 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 PacketIterator<T>& other) const { - RTC_DCHECK_EQ(element_size_, other.element_size_); - return ptr_ == other.ptr_; - } - bool operator!=(const PacketIterator<T>& other) const { - RTC_DCHECK_EQ(element_size_, other.element_size_); - return ptr_ != other.ptr_; - } + bool operator==(const DereferencingIterator& other) const { + return ptr_ == other.ptr_; + } + bool operator!=(const DereferencingIterator& other) const { + return ptr_ != other.ptr_; + } - PacketIterator& operator++() { - ptr_ += element_size_; - return *this; - } - PacketIterator& operator--() { - ptr_ -= element_size_; - return *this; - } - PacketIterator operator++(int) { - PacketIterator iter_copy(ptr_, element_size_); - ptr_ += element_size_; - return iter_copy; - } - PacketIterator operator--(int) { - PacketIterator iter_copy(ptr_, element_size_); - ptr_ -= element_size_; - return iter_copy; - } + 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; + } - T& operator*() { return *reinterpret_cast<T*>(ptr_); } - const T& operator*() const { return *reinterpret_cast<const T*>(ptr_); } + template <bool _IsConst = IsConst> + std::enable_if_t<!_IsConst, reference> operator*() { + return **ptr_; + } - T* operator->() { return reinterpret_cast<T*>(ptr_); } - const T* operator->() const { return reinterpret_cast<const T*>(ptr_); } + template <bool _IsConst = IsConst> + std::enable_if_t<_IsConst, reference> operator*() const { + return **ptr_; + } - private: - PacketIterator(typename std::conditional<std::is_const<T>::value, - const void*, - void*>::type p, - size_t s) - : ptr_(reinterpret_cast<decltype(ptr_)>(p)), element_size_(s) {} - - typename std::conditional<std::is_const<T>::value, const char*, char*>::type - ptr_; - size_t element_size_; -}; + template <bool _IsConst = IsConst> + std::enable_if_t<!_IsConst, pointer> operator->() { + return *ptr_; + } -// Suppose that we have a struct S where we are only interested in a specific -// member M. Given an array of S, PacketView can be used to treat the array -// as an array of M, without exposing the type S to surrounding code and without -// accessing the member through a virtual function. In this case, we want to -// have a common view for incoming and outgoing RtpPackets, hence the PacketView -// name. -// Note that constructing a PacketView bypasses the typesystem, so the caller -// has to take extra care when constructing these objects. The implementation -// also requires that the containing struct is standard-layout (e.g. POD). -// -// Usage example: -// struct A {...}; -// struct B { A a; ...}; -// struct C { A a; ...}; -// size_t len = 10; -// B* array1 = new B[len]; -// C* array2 = new C[len]; -// -// PacketView<A> view1 = PacketView<A>::Create<B>(array1, len, offsetof(B, a)); -// PacketView<A> view2 = PacketView<A>::Create<C>(array2, len, offsetof(C, a)); -// -// The following code works with either view1 or view2. -// void f(PacketView<A> view) -// for (A& a : view) { -// DoSomething(a); -// } -template <typename T> -class PacketView { - public: - template <typename U> - static PacketView Create(U* ptr, size_t num_elements, size_t offset) { - static_assert(std::is_standard_layout<U>::value, - "PacketView can only be created for standard layout types."); - static_assert(std::is_standard_layout<T>::value, - "PacketView can only be created for standard layout types."); - return PacketView(ptr, num_elements, offset, sizeof(U)); - } + 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 = PacketIterator<T>; - using const_iterator = PacketIterator<const T>; + 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(data_, element_size_); } - iterator end() { - auto end_ptr = data_ + num_elements_ * element_size_; - return iterator(end_ptr, element_size_); - } + iterator begin() { return iterator(elems_.data()); } + iterator end() { return iterator(elems_.data() + elems_.size()); } - const_iterator begin() const { return const_iterator(data_, element_size_); } + const_iterator begin() const { return const_iterator(elems_.data()); } const_iterator end() const { - auto end_ptr = data_ + num_elements_ * element_size_; - return const_iterator(end_ptr, element_size_); + return const_iterator(elems_.data() + elems_.size()); } reverse_iterator rbegin() { return reverse_iterator(end()); } @@ -192,35 +258,27 @@ class PacketView { return const_reverse_iterator(begin()); } - size_t size() const { return num_elements_; } + size_t size() const { return elems_.size(); } - bool empty() const { return num_elements_ == 0; } + bool empty() const { return elems_.empty(); } T& operator[](size_t i) { - auto elem_ptr = data_ + i * element_size_; - return *reinterpret_cast<T*>(elem_ptr); + RTC_DCHECK_LT(i, elems_.size()); + return *elems_[i]; } const T& operator[](size_t i) const { - auto elem_ptr = data_ + i * element_size_; - return *reinterpret_cast<const T*>(elem_ptr); + RTC_DCHECK_LT(i, elems_.size()); + return *elems_[i]; + } + + void push_back(T* elem) { + RTC_DCHECK(elem != nullptr); + elems_.push_back(elem); } private: - PacketView(typename std::conditional<std::is_const<T>::value, - const void*, - void*>::type data, - size_t num_elements, - size_t offset, - size_t element_size) - : data_(reinterpret_cast<decltype(data_)>(data) + offset), - num_elements_(num_elements), - element_size_(element_size) {} - - typename std::conditional<std::is_const<T>::value, const char*, char*>::type - data_; - size_t num_elements_; - size_t element_size_; + std::vector<T*> elems_; }; // Conversion functions for version 2 of the wire format. @@ -262,48 +320,11 @@ class ParsedRtcEventLog { kDontParse, kAttemptWebrtcDefaultConfig }; - class ParseStatus { - public: - static ParseStatus Success() { return ParseStatus(); } - static ParseStatus Error(std::string error, std::string file, int line) { - return ParseStatus(error, file, line); - } - - bool ok() const { return error_.empty() && file_.empty() && line_ == 0; } - std::string message() const { - return error_ + " failed at " + file_ + " line " + std::to_string(line_); - } - RTC_DEPRECATED operator bool() const { return ok(); } - - private: - ParseStatus() : error_(), file_(), line_(0) {} - ParseStatus(std::string error, std::string file, int line) - : error_(error), file_(file), line_(line) {} - std::string error_; - std::string file_; - int line_; - }; + using ParseStatus = RtcEventLogParseStatus; template <typename T> - class ParseStatusOr { - public: - ParseStatusOr(const ParseStatus& error) // NOLINT - : status_(error), value_() {} - ParseStatusOr(const T& value) // NOLINT - : status_(ParseStatus::Success()), value_(value) {} - bool ok() const { return status_.ok(); } - const T& value() const& { - RTC_DCHECK(status_.ok()); - return value_; - } - std::string message() const { return status_.message(); } - const ParseStatus& status() const { return status_; } - - private: - ParseStatus status_; - T value_; - }; + using ParseStatusOr = RtcEventLogParseStatusOr<T>; struct LoggedRtpStreamIncoming { LoggedRtpStreamIncoming(); @@ -323,14 +344,12 @@ class ParsedRtcEventLog { struct LoggedRtpStreamView { LoggedRtpStreamView(uint32_t ssrc, - const LoggedRtpPacketIncoming* ptr, - size_t num_elements); + const std::vector<LoggedRtpPacketIncoming>& packets); LoggedRtpStreamView(uint32_t ssrc, - const LoggedRtpPacketOutgoing* ptr, - size_t num_elements); + const std::vector<LoggedRtpPacketOutgoing>& packets); LoggedRtpStreamView(const LoggedRtpStreamView&); uint32_t ssrc; - PacketView<const LoggedRtpPacket> packet_view; + DereferencingVector<const LoggedRtpPacket> packet_view; }; class LogSegment { @@ -361,14 +380,13 @@ class ParsedRtcEventLog { void Clear(); // Reads an RtcEventLog file and returns success if parsing was successful. - ParseStatus ParseFile(const std::string& file_name); + ParseStatus ParseFile(absl::string_view file_name); // Reads an RtcEventLog from a string and returns success if successful. - ParseStatus ParseString(const std::string& s); + ParseStatus ParseString(absl::string_view s); - // Reads an RtcEventLog from an istream and returns success if successful. - ParseStatus ParseStream( - std::istream& stream); // no-presubmit-check TODO(webrtc:8982) + // 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; @@ -581,6 +599,15 @@ class ParsedRtcEventLog { } } + 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) { @@ -611,8 +638,14 @@ class ParsedRtcEventLog { return generic_acks_received_; } - int64_t first_timestamp() const { return first_timestamp_; } - int64_t last_timestamp() const { return last_timestamp_; } + // 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_; } @@ -629,8 +662,8 @@ class ParsedRtcEventLog { std::vector<InferredRouteChangeEvent> GetRouteChanges() const; private: - ABSL_MUST_USE_RESULT ParseStatus ParseStreamInternal( - std::istream& stream); // no-presubmit-check TODO(webrtc:8982) + 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); @@ -638,34 +671,20 @@ class ParsedRtcEventLog { template <typename T> void StoreFirstAndLastTimestamp(const std::vector<T>& v); - // Reads the header, direction, header length and packet length from the RTP - // 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 header must have space for at least IP_PACKET_SIZE bytes. - ParseStatus GetRtpHeader(const rtclog::Event& event, - PacketDirection* incoming, - uint8_t* header, - size_t* header_length, - size_t* total_length, - int* probe_cluster_id) const; - // 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( - PacketDirection direction, - uint32_t ssrc); + const RtpHeaderExtensionMap* GetRtpHeaderExtensionMap(bool incoming, + uint32_t ssrc); - // Reads packet, direction and packet length from the RTCP event at |index|, + // 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, - uint8_t* packet, - size_t* length) const; + std::vector<uint8_t>* packet) const; ParseStatusOr<rtclog::StreamConfig> GetVideoReceiveConfig( const rtclog::Event& event) const; @@ -706,6 +725,9 @@ class ParsedRtcEventLog { 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( @@ -726,6 +748,8 @@ class ParsedRtcEventLog { 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( @@ -820,6 +844,8 @@ class ParsedRtcEventLog { 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_; @@ -848,6 +874,8 @@ class ParsedRtcEventLog { 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_; @@ -863,11 +891,10 @@ class ParsedRtcEventLog { std::vector<LoggedRouteChangeEvent> route_change_events_; std::vector<LoggedRemoteEstimateEvent> remote_estimate_events_; - uint8_t last_incoming_rtcp_packet_[IP_PACKET_SIZE]; - uint8_t last_incoming_rtcp_packet_length_; + std::vector<uint8_t> last_incoming_rtcp_packet_; - int64_t first_timestamp_; - int64_t last_timestamp_; + Timestamp first_timestamp_ = Timestamp::PlusInfinity(); + Timestamp last_timestamp_ = Timestamp::MinusInfinity(); LogSegment first_log_segment_ = LogSegment(0, std::numeric_limits<int64_t>::max()); diff --git a/logging/rtc_event_log/rtc_event_log_unittest.cc b/logging/rtc_event_log/rtc_event_log_unittest.cc index e785d6160a..314bfd90e9 100644 --- a/logging/rtc_event_log/rtc_event_log_unittest.cc +++ b/logging/rtc_event_log/rtc_event_log_unittest.cc @@ -8,6 +8,8 @@ * 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> @@ -17,9 +19,7 @@ #include <utility> #include <vector> -#include "api/rtc_event_log/rtc_event_log.h" #include "api/rtc_event_log/rtc_event_log_factory.h" -#include "api/rtc_event_log_output_file.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" @@ -50,6 +50,7 @@ #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 { @@ -69,6 +70,7 @@ struct EventCounts { 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; @@ -85,9 +87,9 @@ struct EventCounts { 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 + probe_creations + probe_successes + - probe_failures + ice_configs + ice_events + incoming_rtp_packets + - outgoing_rtp_packets + incoming_rtcp_packets + + 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; } @@ -112,11 +114,12 @@ class RtcEventLogSession output_period_ms_(std::get<1>(GetParam())), encoding_type_(std::get<2>(GetParam())), gen_(seed_ * 880001UL), - verifier_(encoding_type_) { + 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. - // TODO(terelius): Use a general utility function to generate a temp file. auto test_info = ::testing::UnitTest::GetInstance()->current_test_info(); std::string test_name = std::string(test_info->test_case_name()) + "_" + test_info->name(); @@ -124,7 +127,7 @@ class RtcEventLogSession temp_filename_ = test::OutputPath() + test_name; } - // Create and buffer the config events and |num_events_before_log_start| + // 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); @@ -165,6 +168,8 @@ class RtcEventLogSession 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>> @@ -200,6 +205,8 @@ class RtcEventLogSession test::EventVerifier verifier_; rtc::ScopedFakeClock clock_; std::string temp_filename_; + MemoryLogStorage log_storage_; + std::unique_ptr<LogWriterFactoryInterface> log_output_factory_; }; bool SsrcUsed( @@ -269,9 +276,9 @@ void RtcEventLogSession::WriteVideoRecvConfigs(size_t video_recv_streams, } while (SsrcUsed(ssrc, incoming_extensions_)); RtpHeaderExtensionMap extensions = gen_.NewRtpHeaderExtensionMap(); incoming_extensions_.emplace_back(ssrc, extensions); - auto event = gen_.NewVideoReceiveStreamConfig(ssrc, extensions); - event_log->Log(event->Copy()); - video_recv_config_list_.push_back(std::move(event)); + auto new_event = gen_.NewVideoReceiveStreamConfig(ssrc, extensions); + event_log->Log(new_event->Copy()); + video_recv_config_list_.push_back(std::move(new_event)); } } @@ -311,7 +318,7 @@ void RtcEventLogSession::WriteLog(EventCounts count, auto task_queue_factory = CreateDefaultTaskQueueFactory(); RtcEventLogFactory rtc_event_log_factory(task_queue_factory.get()); - // The log file will be flushed to disk when the event_log goes out of scope. + // 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_); @@ -330,9 +337,8 @@ void RtcEventLogSession::WriteLog(EventCounts count, for (; remaining_events > 0; remaining_events--) { if (remaining_events == remaining_events_at_start) { clock_.AdvanceTime(TimeDelta::Millis(prng_.Rand(20))); - event_log->StartLogging( - std::make_unique<RtcEventLogOutputFile>(temp_filename_, 10000000), - output_period_ms_); + event_log->StartLogging(log_output_factory_->Create(temp_filename_), + output_period_ms_); start_time_us_ = rtc::TimeMicros(); utc_start_time_us_ = rtc::TimeUTCMicros(); } @@ -444,6 +450,18 @@ void RtcEventLogSession::WriteLog(EventCounts count, } 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()); @@ -531,7 +549,7 @@ void RtcEventLogSession::WriteLog(EventCounts count, } selection -= count.generic_acks_received; - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); } event_log->StopLogging(); @@ -540,12 +558,14 @@ void RtcEventLogSession::WriteLog(EventCounts count, ASSERT_EQ(count.total_nonconfig_events(), static_cast<size_t>(0)); } -// Read the file and verify that what we read back from the event log is the +// 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 file from disk. + // Read the generated log from memory. ParsedRtcEventLog parsed_log; - ASSERT_TRUE(parsed_log.ParseFile(temp_filename_).ok()); + 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(); @@ -577,7 +597,7 @@ void RtcEventLogSession::ReadAndVerifyLog() { 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 < parsed_audio_playout_map.size(); i++) { + for (size_t i = 0; i < audio_playout_stream.size(); i++) { verifier_.VerifyLoggedAudioPlayoutEvent(*audio_playout_stream[i], parsed_audio_playout_stream[i]); } @@ -629,6 +649,35 @@ void RtcEventLogSession::ReadAndVerifyLog() { *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()); @@ -736,16 +785,13 @@ void RtcEventLogSession::ReadAndVerifyLog() { parsed_generic_acks_received[i]); } - EXPECT_EQ(first_timestamp_ms_, parsed_log.first_timestamp() / 1000); - EXPECT_EQ(last_timestamp_ms_, parsed_log.last_timestamp() / 1000); + 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); - - // Clean up temporary file - can be pretty slow. - remove(temp_filename_.c_str()); } } // namespace @@ -761,8 +807,6 @@ TEST_P(RtcEventLogSession, StartLoggingFromBeginning) { count.ana_configs = 3; count.bwe_loss_events = 20; count.bwe_delay_events = 20; - count.dtls_transport_states = 4; - count.dtls_writable_states = 2; count.probe_creations = 4; count.probe_successes = 2; count.probe_failures = 2; @@ -773,10 +817,13 @@ TEST_P(RtcEventLogSession, StartLoggingFromBeginning) { count.incoming_rtcp_packets = 20; count.outgoing_rtcp_packets = 20; if (IsNewFormat()) { - count.route_changes = 4; + 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); @@ -794,8 +841,6 @@ TEST_P(RtcEventLogSession, StartLoggingInTheMiddle) { count.ana_configs = 10; count.bwe_loss_events = 50; count.bwe_delay_events = 50; - count.dtls_transport_states = 4; - count.dtls_writable_states = 5; count.probe_creations = 10; count.probe_successes = 5; count.probe_failures = 5; @@ -806,10 +851,13 @@ TEST_P(RtcEventLogSession, StartLoggingInTheMiddle) { count.incoming_rtcp_packets = 50; count.outgoing_rtcp_packets = 50; if (IsNewFormat()) { - count.route_changes = 10; + 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); @@ -829,9 +877,14 @@ class RtcEventLogCircularBufferTest : public ::testing::TestWithParam<RtcEventLog::EncodingType> { public: RtcEventLogCircularBufferTest() - : encoding_type_(GetParam()), verifier_(encoding_type_) {} + : 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) { @@ -851,36 +904,45 @@ TEST_P(RtcEventLogCircularBufferTest, KeepsMostRecentEvents) { std::make_unique<rtc::ScopedFakeClock>(); fake_clock->SetTime(Timestamp::Seconds(kStartTimeSeconds)); - auto task_queue_factory = CreateDefaultTaskQueueFactory(); - RtcEventLogFactory rtc_event_log_factory(task_queue_factory.get()); - // When log_dumper goes out of scope, it causes the log file to be flushed - // to disk. - std::unique_ptr<RtcEventLog> log_dumper = - 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_dumper->Log(std::make_unique<RtcEventProbeResultSuccess>( - i, kStartBitrate + i * 1000)); + // 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(); } - int64_t start_time_us = rtc::TimeMicros(); - int64_t utc_start_time_us = rtc::TimeUTCMicros(); - log_dumper->StartLogging( - std::make_unique<RtcEventLogOutputFile>(temp_filename, 10000000), - RtcEventLog::kImmediateOutput); - fake_clock->AdvanceTime(TimeDelta::Millis(10)); - int64_t stop_time_us = rtc::TimeMicros(); - log_dumper->StopLogging(); - // Read the generated file from disk. + // Read the generated log from memory. ParsedRtcEventLog parsed_log; - ASSERT_TRUE(parsed_log.ParseFile(temp_filename).ok()); + 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); @@ -898,7 +960,7 @@ TEST_P(RtcEventLogCircularBufferTest, KeepsMostRecentEvents) { EXPECT_LT(probe_success_events.size(), kNumEvents); ASSERT_GT(probe_success_events.size(), 1u); - int64_t first_timestamp_us = probe_success_events[0].timestamp_us; + 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 @@ -907,7 +969,7 @@ TEST_P(RtcEventLogCircularBufferTest, KeepsMostRecentEvents) { // 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::Micros(first_timestamp_us)); + 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( @@ -925,4 +987,64 @@ INSTANTIATE_TEST_SUITE_P( // 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/logging/rtc_event_log/rtc_event_log_unittest_helper.cc b/logging/rtc_event_log/rtc_event_log_unittest_helper.cc index 2a41f6d25b..2607028f60 100644 --- a/logging/rtc_event_log/rtc_event_log_unittest_helper.cc +++ b/logging/rtc_event_log/rtc_event_log_unittest_helper.cc @@ -21,12 +21,15 @@ #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/remote_bitrate_estimator/include/bwe_defines.h" #include "modules/rtp_rtcp/include/rtp_cvo.h" #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" #include "modules/rtp_rtcp/source/rtcp_packet/dlrr.h" @@ -37,6 +40,7 @@ #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" @@ -78,7 +82,7 @@ void ShuffleInPlace(Random* prng, rtc::ArrayView<T> array) { } absl::optional<int> GetExtensionId(const std::vector<RtpExtension>& extensions, - const std::string& uri) { + absl::string_view uri) { for (const auto& extension : extensions) { if (extension.uri == uri) return extension.id; @@ -147,6 +151,29 @@ EventGenerator::NewDtlsWritableState() { 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; @@ -314,17 +341,30 @@ rtcp::Pli EventGenerator::NewPli() { 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>(); - int64_t base_time_us = prng_.Rand<uint32_t>(); - transport_feedback.SetBase(base_seq_no, base_time_us); - transport_feedback.AddReceivedPacket(base_seq_no, base_time_us); - int64_t time_us = base_time_us; + 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_us += prng_.Rand(0, 100000); + time += TimeDelta::Micros(prng_.Rand(0, 100'000)); if (prng_.Rand<bool>()) { - transport_feedback.AddReceivedPacket(base_seq_no + i, time_us); + transport_feedback.AddReceivedPacket(base_seq_no + i, time); } } return transport_feedback; @@ -372,6 +412,7 @@ EventGenerator::NewRtcpPacketIncoming() { kPli, kNack, kRemb, + kBye, kTransportFeedback, kNumValues }; @@ -413,13 +454,18 @@ EventGenerator::NewRtcpPacketIncoming() { 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_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); rtc::Buffer buffer; return std::make_unique<RtcEventRtcpPacketIncoming>(buffer); } @@ -435,6 +481,7 @@ EventGenerator::NewRtcpPacketOutgoing() { kPli, kNack, kRemb, + kBye, kTransportFeedback, kNumValues }; @@ -476,13 +523,18 @@ EventGenerator::NewRtcpPacketOutgoing() { 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_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); rtc::Buffer buffer; return std::make_unique<RtcEventRtcpPacketOutgoing>(buffer); } @@ -835,6 +887,18 @@ void EventVerifier::VerifyLoggedDtlsWritableState( 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 { @@ -870,7 +934,8 @@ void EventVerifier::VerifyLoggedIceCandidatePairEvent( } } -void VerifyLoggedRtpHeader(const RtpPacket& original_header, +template <typename Event> +void VerifyLoggedRtpHeader(const Event& original_header, const RTPHeader& logged_header) { // Standard RTP header. EXPECT_EQ(original_header.Marker(), logged_header.markerBit); @@ -879,53 +944,57 @@ void VerifyLoggedRtpHeader(const RtpPacket& original_header, EXPECT_EQ(original_header.Timestamp(), logged_header.timestamp); EXPECT_EQ(original_header.Ssrc(), logged_header.ssrc); - EXPECT_EQ(original_header.headers_size(), logged_header.headerLength); + EXPECT_EQ(original_header.header_length(), logged_header.headerLength); // TransmissionOffset header extension. - ASSERT_EQ(original_header.HasExtension<TransmissionOffset>(), + ASSERT_EQ(original_header.template HasExtension<TransmissionOffset>(), logged_header.extension.hasTransmissionTimeOffset); if (logged_header.extension.hasTransmissionTimeOffset) { int32_t offset; - ASSERT_TRUE(original_header.GetExtension<TransmissionOffset>(&offset)); + ASSERT_TRUE( + original_header.template GetExtension<TransmissionOffset>(&offset)); EXPECT_EQ(offset, logged_header.extension.transmissionTimeOffset); } // AbsoluteSendTime header extension. - ASSERT_EQ(original_header.HasExtension<AbsoluteSendTime>(), + ASSERT_EQ(original_header.template HasExtension<AbsoluteSendTime>(), logged_header.extension.hasAbsoluteSendTime); if (logged_header.extension.hasAbsoluteSendTime) { uint32_t sendtime; - ASSERT_TRUE(original_header.GetExtension<AbsoluteSendTime>(&sendtime)); + ASSERT_TRUE( + original_header.template GetExtension<AbsoluteSendTime>(&sendtime)); EXPECT_EQ(sendtime, logged_header.extension.absoluteSendTime); } // TransportSequenceNumber header extension. - ASSERT_EQ(original_header.HasExtension<TransportSequenceNumber>(), + ASSERT_EQ(original_header.template HasExtension<TransportSequenceNumber>(), logged_header.extension.hasTransportSequenceNumber); if (logged_header.extension.hasTransportSequenceNumber) { uint16_t seqnum; - ASSERT_TRUE(original_header.GetExtension<TransportSequenceNumber>(&seqnum)); + ASSERT_TRUE(original_header.template GetExtension<TransportSequenceNumber>( + &seqnum)); EXPECT_EQ(seqnum, logged_header.extension.transportSequenceNumber); } // AudioLevel header extension. - ASSERT_EQ(original_header.HasExtension<AudioLevel>(), + 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.GetExtension<AudioLevel>(&voice_activity, - &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.HasExtension<VideoOrientation>(), + ASSERT_EQ(original_header.template HasExtension<VideoOrientation>(), logged_header.extension.hasVideoRotation); if (logged_header.extension.hasVideoRotation) { uint8_t rotation; - ASSERT_TRUE(original_header.GetExtension<VideoOrientation>(&rotation)); + ASSERT_TRUE( + original_header.template GetExtension<VideoOrientation>(&rotation)); EXPECT_EQ(ConvertCVOByteToVideoRotation(rotation), logged_header.extension.videoRotation); } @@ -954,8 +1023,7 @@ void EventVerifier::VerifyLoggedRtpPacketIncoming( const LoggedRtpPacketIncoming& logged_event) const { EXPECT_EQ(original_event.timestamp_ms(), logged_event.log_time_ms()); - EXPECT_EQ(original_event.header().headers_size(), - logged_event.rtp.header_length); + EXPECT_EQ(original_event.header_length(), logged_event.rtp.header_length); EXPECT_EQ(original_event.packet_length(), logged_event.rtp.total_length); @@ -964,7 +1032,7 @@ void EventVerifier::VerifyLoggedRtpPacketIncoming( EXPECT_EQ(original_event.padding_length(), logged_event.rtp.header.paddingLength); - VerifyLoggedRtpHeader(original_event.header(), logged_event.rtp.header); + VerifyLoggedRtpHeader(original_event, logged_event.rtp.header); } void EventVerifier::VerifyLoggedRtpPacketOutgoing( @@ -972,8 +1040,7 @@ void EventVerifier::VerifyLoggedRtpPacketOutgoing( const LoggedRtpPacketOutgoing& logged_event) const { EXPECT_EQ(original_event.timestamp_ms(), logged_event.log_time_ms()); - EXPECT_EQ(original_event.header().headers_size(), - logged_event.rtp.header_length); + EXPECT_EQ(original_event.header_length(), logged_event.rtp.header_length); EXPECT_EQ(original_event.packet_length(), logged_event.rtp.total_length); @@ -985,7 +1052,7 @@ void EventVerifier::VerifyLoggedRtpPacketOutgoing( // 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.header(), logged_event.rtp.header); + VerifyLoggedRtpHeader(original_event, logged_event.rtp.header); } void EventVerifier::VerifyLoggedGenericPacketSent( @@ -1060,10 +1127,10 @@ void EventVerifier::VerifyReportBlock( } void EventVerifier::VerifyLoggedSenderReport( - int64_t log_time_us, + int64_t log_time_ms, const rtcp::SenderReport& original_sr, const LoggedRtcpPacketSenderReport& logged_sr) { - EXPECT_EQ(log_time_us, logged_sr.log_time_us()); + 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()); @@ -1080,10 +1147,10 @@ void EventVerifier::VerifyLoggedSenderReport( } void EventVerifier::VerifyLoggedReceiverReport( - int64_t log_time_us, + int64_t log_time_ms, const rtcp::ReceiverReport& original_rr, const LoggedRtcpPacketReceiverReport& logged_rr) { - EXPECT_EQ(log_time_us, logged_rr.log_time_us()); + 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()); @@ -1094,9 +1161,10 @@ void EventVerifier::VerifyLoggedReceiverReport( } void EventVerifier::VerifyLoggedExtendedReports( - int64_t log_time_us, + 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()); @@ -1134,11 +1202,11 @@ void EventVerifier::VerifyLoggedExtendedReports( } } -void EventVerifier::VerifyLoggedFir(int64_t log_time_us, +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()); @@ -1148,25 +1216,35 @@ void EventVerifier::VerifyLoggedFir(int64_t log_time_us, } } -void EventVerifier::VerifyLoggedPli(int64_t log_time_us, +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::VerifyLoggedNack(int64_t log_time_us, +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_us, logged_nack.log_time_us()); + 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_us, + int64_t log_time_ms, const rtcp::TransportFeedback& original_transport_feedback, const LoggedRtcpPacketTransportFeedback& logged_transport_feedback) { - EXPECT_EQ(log_time_us, logged_transport_feedback.log_time_us()); + 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()); @@ -1177,25 +1255,25 @@ void EventVerifier::VerifyLoggedTransportFeedback( logged_transport_feedback.transport_feedback.GetReceivedPackets()[i] .sequence_number()); EXPECT_EQ( - original_transport_feedback.GetReceivedPackets()[i].delta_us(), + original_transport_feedback.GetReceivedPackets()[i].delta(), logged_transport_feedback.transport_feedback.GetReceivedPackets()[i] - .delta_us()); + .delta()); } } -void EventVerifier::VerifyLoggedRemb(int64_t log_time_us, +void EventVerifier::VerifyLoggedRemb(int64_t log_time_ms, const rtcp::Remb& original_remb, const LoggedRtcpPacketRemb& logged_remb) { - EXPECT_EQ(log_time_us, logged_remb.log_time_us()); + 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_us, + int64_t log_time_ms, const rtcp::LossNotification& original_loss_notification, const LoggedRtcpPacketLossNotification& logged_loss_notification) { - EXPECT_EQ(log_time_us, logged_loss_notification.log_time_us()); + 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(), @@ -1210,7 +1288,7 @@ void EventVerifier::VerifyLoggedStartEvent( 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); + EXPECT_EQ(utc_start_time_us / 1000, logged_event.utc_start_time.ms()); } } diff --git a/logging/rtc_event_log/rtc_event_log_unittest_helper.h b/logging/rtc_event_log/rtc_event_log_unittest_helper.h index 6f0a9c9afe..94a46c195c 100644 --- a/logging/rtc_event_log/rtc_event_log_unittest_helper.h +++ b/logging/rtc_event_log/rtc_event_log_unittest_helper.h @@ -25,6 +25,7 @@ #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" @@ -44,6 +45,7 @@ #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" @@ -71,6 +73,7 @@ class EventGenerator { 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(); @@ -91,10 +94,11 @@ class EventGenerator { 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 + // `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, @@ -103,21 +107,21 @@ class EventGenerator { RtpPacket* rtp_packet, bool all_configured_exts); - // |all_configured_exts| determines whether the RTP packet exhibits all + // `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 + // `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, + // `configure_all` determines whether all supported extensions are configured, // or a random subset. RtpHeaderExtensionMap NewRtpHeaderExtensionMap(bool configure_all = false); @@ -189,6 +193,9 @@ class EventVerifier { 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; @@ -253,35 +260,38 @@ class EventVerifier { const RtcEventRtcpPacketOutgoing& original_event, const LoggedRtcpPacketOutgoing& logged_event) const; - void VerifyLoggedSenderReport(int64_t log_time_us, + void VerifyLoggedSenderReport(int64_t log_time_ms, const rtcp::SenderReport& original_sr, const LoggedRtcpPacketSenderReport& logged_sr); void VerifyLoggedReceiverReport( - int64_t log_time_us, + int64_t log_time_ms, const rtcp::ReceiverReport& original_rr, const LoggedRtcpPacketReceiverReport& logged_rr); void VerifyLoggedExtendedReports( - int64_t log_time_us, + int64_t log_time_ms, const rtcp::ExtendedReports& original_xr, const LoggedRtcpPacketExtendedReports& logged_xr); - void VerifyLoggedFir(int64_t log_time_us, + void VerifyLoggedFir(int64_t log_time_ms, const rtcp::Fir& original_fir, const LoggedRtcpPacketFir& logged_fir); - void VerifyLoggedPli(int64_t log_time_us, + void VerifyLoggedPli(int64_t log_time_ms, const rtcp::Pli& original_pli, const LoggedRtcpPacketPli& logged_pli); - void VerifyLoggedNack(int64_t log_time_us, + 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_us, + int64_t log_time_ms, const rtcp::TransportFeedback& original_transport_feedback, const LoggedRtcpPacketTransportFeedback& logged_transport_feedback); - void VerifyLoggedRemb(int64_t log_time_us, + void VerifyLoggedRemb(int64_t log_time_ms, const rtcp::Remb& original_remb, const LoggedRtcpPacketRemb& logged_remb); void VerifyLoggedLossNotification( - int64_t log_time_us, + int64_t log_time_ms, const rtcp::LossNotification& original_loss_notification, const LoggedRtcpPacketLossNotification& logged_loss_notification); diff --git a/logging/rtc_event_log/rtc_event_processor.cc b/logging/rtc_event_log/rtc_event_processor.cc index 804e283851..e6a9983b6f 100644 --- a/logging/rtc_event_log/rtc_event_processor.cc +++ b/logging/rtc_event_log/rtc_event_processor.cc @@ -15,7 +15,7 @@ RtcEventProcessor::RtcEventProcessor() = default; RtcEventProcessor::~RtcEventProcessor() = default; void RtcEventProcessor::ProcessEventsInOrder() { - // |event_lists_| is a min-heap of lists ordered by the timestamp of the + // `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. diff --git a/logging/rtc_event_log/rtc_event_processor.h b/logging/rtc_event_log/rtc_event_processor.h index abb73701db..9bf4c9c5db 100644 --- a/logging/rtc_event_log/rtc_event_processor.h +++ b/logging/rtc_event_log/rtc_event_processor.h @@ -98,7 +98,7 @@ class 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 + // 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> @@ -122,7 +122,7 @@ class RtcEventProcessor { 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. + // Comparison function to make `event_lists_` into a min heap. static bool Cmp(const ListPtrType& a, const ListPtrType& b); }; diff --git a/logging/rtc_event_log/rtc_event_processor_unittest.cc b/logging/rtc_event_log/rtc_event_processor_unittest.cc index 4ec5abee5e..b0cec25f1f 100644 --- a/logging/rtc_event_log/rtc_event_processor_unittest.cc +++ b/logging/rtc_event_log/rtc_event_processor_unittest.cc @@ -29,7 +29,7 @@ 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_ms * 1000); // Convert ms to us. + v.emplace_back(Timestamp::Millis(timestamp_ms)); } return v; } @@ -41,7 +41,7 @@ CreateRandomEventLists(size_t num_lists, size_t num_elements, uint64_t seed) { 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_ms * 1000); + lists[i].emplace_back(Timestamp::Millis(timestamp_ms)); } return lists; } @@ -146,8 +146,8 @@ TEST(RtcEventProcessor, DifferentTypes) { result.push_back(elem.log_time_ms()); }; - std::vector<LoggedStartEvent> events1{LoggedStartEvent(2000)}; - std::vector<LoggedStopEvent> events2{LoggedStopEvent(1000)}; + 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); diff --git a/logging/rtc_event_log/rtc_stream_config.cc b/logging/rtc_event_log/rtc_stream_config.cc index d4d30d00bc..aa107c80bc 100644 --- a/logging/rtc_event_log/rtc_stream_config.cc +++ b/logging/rtc_event_log/rtc_stream_config.cc @@ -10,6 +10,8 @@ #include "logging/rtc_event_log/rtc_stream_config.h" +#include "absl/strings/string_view.h" + namespace webrtc { namespace rtclog { @@ -30,7 +32,7 @@ bool StreamConfig::operator!=(const StreamConfig& other) const { return !(*this == other); } -StreamConfig::Codec::Codec(const std::string& payload_name, +StreamConfig::Codec::Codec(absl::string_view payload_name, int payload_type, int rtx_payload_type) : payload_name(payload_name), diff --git a/logging/rtc_event_log/rtc_stream_config.h b/logging/rtc_event_log/rtc_stream_config.h index a81249aebf..d114332d34 100644 --- a/logging/rtc_event_log/rtc_stream_config.h +++ b/logging/rtc_event_log/rtc_stream_config.h @@ -16,6 +16,7 @@ #include <string> #include <vector> +#include "absl/strings/string_view.h" #include "api/rtp_headers.h" #include "api/rtp_parameters.h" @@ -41,7 +42,7 @@ struct StreamConfig { RtcpMode rtcp_mode = RtcpMode::kReducedSize; struct Codec { - Codec(const std::string& payload_name, + Codec(absl::string_view payload_name, int payload_type, int rtx_payload_type); |