|  | /* | 
|  | *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. | 
|  | * | 
|  | *  Use of this source code is governed by a BSD-style license | 
|  | *  that can be found in the LICENSE file in the root of the source | 
|  | *  tree. An additional intellectual property rights grant can be found | 
|  | *  in the file PATENTS.  All contributing project authors may | 
|  | *  be found in the AUTHORS file in the root of the source tree. | 
|  | */ | 
|  |  | 
|  | #include "logging/rtc_event_log/rtc_event_log_unittest_helper.h" | 
|  |  | 
|  | #include <cmath> | 
|  | #include <cstdint> | 
|  | #include <cstring> | 
|  | #include <limits> | 
|  | #include <memory> | 
|  | #include <numeric> | 
|  | #include <optional> | 
|  | #include <utility> | 
|  | #include <vector> | 
|  |  | 
|  | #include "absl/algorithm/container.h" | 
|  | #include "absl/strings/string_view.h" | 
|  | #include "api/array_view.h" | 
|  | #include "api/candidate.h" | 
|  | #include "api/dtls_transport_interface.h" | 
|  | #include "api/rtc_event_log/rtc_event_log.h" | 
|  | #include "api/rtp_headers.h" | 
|  | #include "api/rtp_parameters.h" | 
|  | #include "api/transport/bandwidth_usage.h" | 
|  | #include "api/units/data_rate.h" | 
|  | #include "api/units/time_delta.h" | 
|  | #include "api/units/timestamp.h" | 
|  | #include "api/video/video_codec_type.h" | 
|  | #include "logging/rtc_event_log/events/logged_rtp_rtcp.h" | 
|  | #include "logging/rtc_event_log/events/rtc_event_alr_state.h" | 
|  | #include "logging/rtc_event_log/events/rtc_event_audio_network_adaptation.h" | 
|  | #include "logging/rtc_event_log/events/rtc_event_audio_playout.h" | 
|  | #include "logging/rtc_event_log/events/rtc_event_audio_receive_stream_config.h" | 
|  | #include "logging/rtc_event_log/events/rtc_event_audio_send_stream_config.h" | 
|  | #include "logging/rtc_event_log/events/rtc_event_begin_log.h" | 
|  | #include "logging/rtc_event_log/events/rtc_event_bwe_update_delay_based.h" | 
|  | #include "logging/rtc_event_log/events/rtc_event_bwe_update_loss_based.h" | 
|  | #include "logging/rtc_event_log/events/rtc_event_dtls_transport_state.h" | 
|  | #include "logging/rtc_event_log/events/rtc_event_dtls_writable_state.h" | 
|  | #include "logging/rtc_event_log/events/rtc_event_end_log.h" | 
|  | #include "logging/rtc_event_log/events/rtc_event_frame_decoded.h" | 
|  | #include "logging/rtc_event_log/events/rtc_event_generic_ack_received.h" | 
|  | #include "logging/rtc_event_log/events/rtc_event_generic_packet_received.h" | 
|  | #include "logging/rtc_event_log/events/rtc_event_generic_packet_sent.h" | 
|  | #include "logging/rtc_event_log/events/rtc_event_ice_candidate_pair.h" | 
|  | #include "logging/rtc_event_log/events/rtc_event_ice_candidate_pair_config.h" | 
|  | #include "logging/rtc_event_log/events/rtc_event_neteq_set_minimum_delay.h" | 
|  | #include "logging/rtc_event_log/events/rtc_event_probe_cluster_created.h" | 
|  | #include "logging/rtc_event_log/events/rtc_event_probe_result_failure.h" | 
|  | #include "logging/rtc_event_log/events/rtc_event_probe_result_success.h" | 
|  | #include "logging/rtc_event_log/events/rtc_event_remote_estimate.h" | 
|  | #include "logging/rtc_event_log/events/rtc_event_route_change.h" | 
|  | #include "logging/rtc_event_log/events/rtc_event_rtcp_packet_incoming.h" | 
|  | #include "logging/rtc_event_log/events/rtc_event_rtcp_packet_outgoing.h" | 
|  | #include "logging/rtc_event_log/events/rtc_event_rtp_packet_incoming.h" | 
|  | #include "logging/rtc_event_log/events/rtc_event_rtp_packet_outgoing.h" | 
|  | #include "logging/rtc_event_log/events/rtc_event_video_receive_stream_config.h" | 
|  | #include "logging/rtc_event_log/events/rtc_event_video_send_stream_config.h" | 
|  | #include "logging/rtc_event_log/rtc_stream_config.h" | 
|  | #include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor_config.h" | 
|  | #include "modules/rtp_rtcp/include/rtp_cvo.h" | 
|  | #include "modules/rtp_rtcp/include/rtp_header_extension_map.h" | 
|  | #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" | 
|  | #include "modules/rtp_rtcp/source/rtcp_packet/bye.h" | 
|  | #include "modules/rtp_rtcp/source/rtcp_packet/dlrr.h" | 
|  | #include "modules/rtp_rtcp/source/rtcp_packet/extended_reports.h" | 
|  | #include "modules/rtp_rtcp/source/rtcp_packet/fir.h" | 
|  | #include "modules/rtp_rtcp/source/rtcp_packet/loss_notification.h" | 
|  | #include "modules/rtp_rtcp/source/rtcp_packet/nack.h" | 
|  | #include "modules/rtp_rtcp/source/rtcp_packet/pli.h" | 
|  | #include "modules/rtp_rtcp/source/rtcp_packet/receiver_report.h" | 
|  | #include "modules/rtp_rtcp/source/rtcp_packet/remb.h" | 
|  | #include "modules/rtp_rtcp/source/rtcp_packet/report_block.h" | 
|  | #include "modules/rtp_rtcp/source/rtcp_packet/rrtr.h" | 
|  | #include "modules/rtp_rtcp/source/rtcp_packet/sender_report.h" | 
|  | #include "modules/rtp_rtcp/source/rtcp_packet/target_bitrate.h" | 
|  | #include "modules/rtp_rtcp/source/rtp_dependency_descriptor_extension.h" | 
|  | #include "modules/rtp_rtcp/source/rtp_header_extensions.h" | 
|  | #include "modules/rtp_rtcp/source/rtp_packet_received.h" | 
|  | #include "modules/rtp_rtcp/source/rtp_packet_to_send.h" | 
|  | #include "rtc_base/buffer.h" | 
|  | #include "rtc_base/checks.h" | 
|  | #include "rtc_base/random.h" | 
|  | #include "rtc_base/time_utils.h" | 
|  | #include "system_wrappers/include/ntp_time.h" | 
|  | #include "test/gmock.h" | 
|  | #include "test/gtest.h" | 
|  |  | 
|  | namespace webrtc { | 
|  |  | 
|  | namespace test { | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | using ::testing::ElementsAreArray; | 
|  | using ::testing::IsEmpty; | 
|  |  | 
|  | struct ExtensionPair { | 
|  | RTPExtensionType type; | 
|  | const char* name; | 
|  | }; | 
|  |  | 
|  | constexpr int kMaxCsrcs = 3; | 
|  |  | 
|  | // Maximum serialized size of a header extension, including 1 byte ID. | 
|  | constexpr int kMaxExtensionSizeBytes = 10; | 
|  | constexpr int kMaxNumExtensions = 6; | 
|  |  | 
|  | constexpr ExtensionPair kExtensions[kMaxNumExtensions] = { | 
|  | {.type = RTPExtensionType::kRtpExtensionTransmissionTimeOffset, | 
|  | .name = RtpExtension::kTimestampOffsetUri}, | 
|  | {.type = RTPExtensionType::kRtpExtensionAbsoluteSendTime, | 
|  | .name = RtpExtension::kAbsSendTimeUri}, | 
|  | {.type = RTPExtensionType::kRtpExtensionTransportSequenceNumber, | 
|  | .name = RtpExtension::kTransportSequenceNumberUri}, | 
|  | {.type = RTPExtensionType::kRtpExtensionAudioLevel, | 
|  | .name = RtpExtension::kAudioLevelUri}, | 
|  | {.type = RTPExtensionType::kRtpExtensionVideoRotation, | 
|  | .name = RtpExtension::kVideoRotationUri}, | 
|  | {.type = RTPExtensionType::kRtpExtensionDependencyDescriptor, | 
|  | .name = RtpExtension::kDependencyDescriptorUri}}; | 
|  |  | 
|  | MATCHER_P2(Near, value, margin, "") { | 
|  | return value - margin < arg && arg < value + margin; | 
|  | } | 
|  |  | 
|  | template <typename T> | 
|  | void ShuffleInPlace(Random* prng, ArrayView<T> array) { | 
|  | RTC_DCHECK_LE(array.size(), std::numeric_limits<uint32_t>::max()); | 
|  | for (uint32_t i = 0; i + 1 < array.size(); i++) { | 
|  | uint32_t other = prng->Rand(i, static_cast<uint32_t>(array.size() - 1)); | 
|  | std::swap(array[i], array[other]); | 
|  | } | 
|  | } | 
|  |  | 
|  | std::optional<int> GetExtensionId(const std::vector<RtpExtension>& extensions, | 
|  | absl::string_view uri) { | 
|  | for (const auto& extension : extensions) { | 
|  | if (extension.uri == uri) | 
|  | return extension.id; | 
|  | } | 
|  | return std::nullopt; | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | std::unique_ptr<RtcEventAlrState> EventGenerator::NewAlrState() { | 
|  | return std::make_unique<RtcEventAlrState>(prng_.Rand<bool>()); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<RtcEventAudioPlayout> EventGenerator::NewAudioPlayout( | 
|  | uint32_t ssrc) { | 
|  | return std::make_unique<RtcEventAudioPlayout>(ssrc); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<RtcEventAudioNetworkAdaptation> | 
|  | EventGenerator::NewAudioNetworkAdaptation() { | 
|  | std::unique_ptr<AudioEncoderRuntimeConfig> config = | 
|  | std::make_unique<AudioEncoderRuntimeConfig>(); | 
|  |  | 
|  | config->bitrate_bps = prng_.Rand(0, 3000000); | 
|  | config->enable_fec = prng_.Rand<bool>(); | 
|  | config->enable_dtx = prng_.Rand<bool>(); | 
|  | config->frame_length_ms = prng_.Rand(10, 120); | 
|  | config->num_channels = prng_.Rand(1, 2); | 
|  | config->uplink_packet_loss_fraction = prng_.Rand<float>(); | 
|  |  | 
|  | return std::make_unique<RtcEventAudioNetworkAdaptation>(std::move(config)); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<RtcEventNetEqSetMinimumDelay> | 
|  | EventGenerator::NewNetEqSetMinimumDelay(uint32_t ssrc) { | 
|  | return std::make_unique<RtcEventNetEqSetMinimumDelay>( | 
|  | ssrc, prng_.Rand(std::numeric_limits<int>::max())); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<RtcEventBweUpdateDelayBased> | 
|  | EventGenerator::NewBweUpdateDelayBased() { | 
|  | constexpr int32_t kMaxBweBps = 20000000; | 
|  | int32_t bitrate_bps = prng_.Rand(0, kMaxBweBps); | 
|  | BandwidthUsage state = static_cast<BandwidthUsage>( | 
|  | prng_.Rand(static_cast<uint32_t>(BandwidthUsage::kLast) - 1)); | 
|  | return std::make_unique<RtcEventBweUpdateDelayBased>(bitrate_bps, state); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<RtcEventBweUpdateLossBased> | 
|  | EventGenerator::NewBweUpdateLossBased() { | 
|  | constexpr int32_t kMaxBweBps = 20000000; | 
|  | constexpr int32_t kMaxPackets = 1000; | 
|  | int32_t bitrate_bps = prng_.Rand(0, kMaxBweBps); | 
|  | uint8_t fraction_lost = prng_.Rand<uint8_t>(); | 
|  | int32_t total_packets = prng_.Rand(1, kMaxPackets); | 
|  |  | 
|  | return std::make_unique<RtcEventBweUpdateLossBased>( | 
|  | bitrate_bps, fraction_lost, total_packets); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<RtcEventDtlsTransportState> | 
|  | EventGenerator::NewDtlsTransportState() { | 
|  | DtlsTransportState state = static_cast<DtlsTransportState>( | 
|  | prng_.Rand(static_cast<uint32_t>(DtlsTransportState::kNumValues) - 1)); | 
|  |  | 
|  | return std::make_unique<RtcEventDtlsTransportState>(state); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<RtcEventDtlsWritableState> | 
|  | EventGenerator::NewDtlsWritableState() { | 
|  | bool writable = prng_.Rand<bool>(); | 
|  | return std::make_unique<RtcEventDtlsWritableState>(writable); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<RtcEventFrameDecoded> EventGenerator::NewFrameDecodedEvent( | 
|  | uint32_t ssrc) { | 
|  | constexpr int kMinRenderDelayMs = 1; | 
|  | constexpr int kMaxRenderDelayMs = 2000000; | 
|  | constexpr int kMaxWidth = 15360; | 
|  | constexpr int kMaxHeight = 8640; | 
|  | constexpr int kMinWidth = 16; | 
|  | constexpr int kMinHeight = 16; | 
|  | constexpr int kNumCodecTypes = 6; | 
|  |  | 
|  | constexpr VideoCodecType kCodecList[kNumCodecTypes] = { | 
|  | kVideoCodecGeneric, kVideoCodecVP8,  kVideoCodecVP9, | 
|  | kVideoCodecAV1,     kVideoCodecH264, kVideoCodecH265}; | 
|  | const int64_t render_time_ms = | 
|  | TimeMillis() + prng_.Rand(kMinRenderDelayMs, kMaxRenderDelayMs); | 
|  | const int width = prng_.Rand(kMinWidth, kMaxWidth); | 
|  | const int height = prng_.Rand(kMinHeight, kMaxHeight); | 
|  | const VideoCodecType codec = kCodecList[prng_.Rand(0, kNumCodecTypes - 1)]; | 
|  | const uint8_t qp = prng_.Rand<uint8_t>(); | 
|  | return std::make_unique<RtcEventFrameDecoded>(render_time_ms, ssrc, width, | 
|  | height, codec, qp); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<RtcEventProbeClusterCreated> | 
|  | EventGenerator::NewProbeClusterCreated() { | 
|  | constexpr int kMaxBweBps = 20000000; | 
|  | constexpr int kMaxNumProbes = 10000; | 
|  | int id = prng_.Rand(1, kMaxNumProbes); | 
|  | int bitrate_bps = prng_.Rand(0, kMaxBweBps); | 
|  | int min_probes = prng_.Rand(5, 50); | 
|  | int min_bytes = prng_.Rand(500, 50000); | 
|  |  | 
|  | return std::make_unique<RtcEventProbeClusterCreated>(id, bitrate_bps, | 
|  | min_probes, min_bytes); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<RtcEventProbeResultFailure> | 
|  | EventGenerator::NewProbeResultFailure() { | 
|  | constexpr int kMaxNumProbes = 10000; | 
|  | int id = prng_.Rand(1, kMaxNumProbes); | 
|  | ProbeFailureReason reason = static_cast<ProbeFailureReason>( | 
|  | prng_.Rand(static_cast<uint32_t>(ProbeFailureReason::kLast) - 1)); | 
|  |  | 
|  | return std::make_unique<RtcEventProbeResultFailure>(id, reason); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<RtcEventProbeResultSuccess> | 
|  | EventGenerator::NewProbeResultSuccess() { | 
|  | constexpr int kMaxBweBps = 20000000; | 
|  | constexpr int kMaxNumProbes = 10000; | 
|  | int id = prng_.Rand(1, kMaxNumProbes); | 
|  | int bitrate_bps = prng_.Rand(0, kMaxBweBps); | 
|  |  | 
|  | return std::make_unique<RtcEventProbeResultSuccess>(id, bitrate_bps); | 
|  | } | 
|  |  | 
|  | constexpr uint32_t CandidateTypeCount() { | 
|  | // This switch statement only exists to catch changes to the IceCandidateType | 
|  | // enumeration. If you get an error here, please update the switch statement | 
|  | // and the return value. | 
|  | IceCandidateType type = IceCandidateType::kHost; | 
|  | switch (type) { | 
|  | case IceCandidateType::kHost: | 
|  | case IceCandidateType::kSrflx: | 
|  | case IceCandidateType::kPrflx: | 
|  | case IceCandidateType::kRelay: | 
|  | break; | 
|  | } | 
|  | return 4u; | 
|  | } | 
|  |  | 
|  | std::unique_ptr<RtcEventIceCandidatePairConfig> | 
|  | EventGenerator::NewIceCandidatePairConfig() { | 
|  | static_assert(static_cast<int>(IceCandidateType::kHost) == 0, | 
|  | "Expect kLocal to be the first enum value, equal to 0"); | 
|  | IceCandidateType local_candidate_type = | 
|  | static_cast<IceCandidateType>(prng_.Rand(CandidateTypeCount() - 1)); | 
|  | IceCandidateNetworkType local_network_type = | 
|  | static_cast<IceCandidateNetworkType>(prng_.Rand( | 
|  | static_cast<uint32_t>(IceCandidateNetworkType::kNumValues) - 1)); | 
|  | IceCandidatePairAddressFamily local_address_family = | 
|  | static_cast<IceCandidatePairAddressFamily>(prng_.Rand( | 
|  | static_cast<uint32_t>(IceCandidatePairAddressFamily::kNumValues) - | 
|  | 1)); | 
|  | IceCandidateType remote_candidate_type = | 
|  | static_cast<IceCandidateType>(prng_.Rand(CandidateTypeCount() - 1)); | 
|  | IceCandidatePairAddressFamily remote_address_family = | 
|  | static_cast<IceCandidatePairAddressFamily>(prng_.Rand( | 
|  | static_cast<uint32_t>(IceCandidatePairAddressFamily::kNumValues) - | 
|  | 1)); | 
|  | IceCandidatePairProtocol protocol_type = | 
|  | static_cast<IceCandidatePairProtocol>(prng_.Rand( | 
|  | static_cast<uint32_t>(IceCandidatePairProtocol::kNumValues) - 1)); | 
|  |  | 
|  | IceCandidatePairDescription desc(local_candidate_type, remote_candidate_type); | 
|  | desc.local_relay_protocol = protocol_type; | 
|  | desc.local_network_type = local_network_type; | 
|  | desc.local_address_family = local_address_family; | 
|  | desc.remote_address_family = remote_address_family; | 
|  | desc.candidate_pair_protocol = protocol_type; | 
|  |  | 
|  | IceCandidatePairConfigType type = | 
|  | static_cast<IceCandidatePairConfigType>(prng_.Rand( | 
|  | static_cast<uint32_t>(IceCandidatePairConfigType::kNumValues) - 1)); | 
|  | uint32_t pair_id = prng_.Rand<uint32_t>(); | 
|  | return std::make_unique<RtcEventIceCandidatePairConfig>(type, pair_id, desc); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<RtcEventIceCandidatePair> | 
|  | EventGenerator::NewIceCandidatePair() { | 
|  | IceCandidatePairEventType type = | 
|  | static_cast<IceCandidatePairEventType>(prng_.Rand( | 
|  | static_cast<uint32_t>(IceCandidatePairEventType::kNumValues) - 1)); | 
|  | uint32_t pair_id = prng_.Rand<uint32_t>(); | 
|  | uint32_t transaction_id = prng_.Rand<uint32_t>(); | 
|  |  | 
|  | return std::make_unique<RtcEventIceCandidatePair>(type, pair_id, | 
|  | transaction_id); | 
|  | } | 
|  |  | 
|  | rtcp::ReportBlock EventGenerator::NewReportBlock() { | 
|  | rtcp::ReportBlock report_block; | 
|  | report_block.SetMediaSsrc(prng_.Rand<uint32_t>()); | 
|  | report_block.SetFractionLost(prng_.Rand<uint8_t>()); | 
|  | // cumulative_lost is a 3-byte signed value. | 
|  | RTC_DCHECK(report_block.SetCumulativeLost( | 
|  | prng_.Rand(-(1 << 23) + 1, (1 << 23) - 1))); | 
|  | report_block.SetExtHighestSeqNum(prng_.Rand<uint32_t>()); | 
|  | report_block.SetJitter(prng_.Rand<uint32_t>()); | 
|  | report_block.SetLastSr(prng_.Rand<uint32_t>()); | 
|  | report_block.SetDelayLastSr(prng_.Rand<uint32_t>()); | 
|  | return report_block; | 
|  | } | 
|  |  | 
|  | rtcp::SenderReport EventGenerator::NewSenderReport() { | 
|  | rtcp::SenderReport sender_report; | 
|  | sender_report.SetSenderSsrc(prng_.Rand<uint32_t>()); | 
|  | sender_report.SetNtp(NtpTime(prng_.Rand<uint32_t>(), prng_.Rand<uint32_t>())); | 
|  | sender_report.SetRtpTimestamp(prng_.Rand<uint32_t>()); | 
|  | sender_report.SetPacketCount(prng_.Rand<uint32_t>()); | 
|  | sender_report.SetOctetCount(prng_.Rand<uint32_t>()); | 
|  | sender_report.AddReportBlock(NewReportBlock()); | 
|  | return sender_report; | 
|  | } | 
|  |  | 
|  | rtcp::ReceiverReport EventGenerator::NewReceiverReport() { | 
|  | rtcp::ReceiverReport receiver_report; | 
|  | receiver_report.SetSenderSsrc(prng_.Rand<uint32_t>()); | 
|  | receiver_report.AddReportBlock(NewReportBlock()); | 
|  | return receiver_report; | 
|  | } | 
|  |  | 
|  | rtcp::ExtendedReports EventGenerator::NewExtendedReports() { | 
|  | rtcp::ExtendedReports extended_report; | 
|  | extended_report.SetSenderSsrc(prng_.Rand<uint32_t>()); | 
|  |  | 
|  | rtcp::Rrtr rrtr; | 
|  | rrtr.SetNtp(NtpTime(prng_.Rand<uint32_t>(), prng_.Rand<uint32_t>())); | 
|  | extended_report.SetRrtr(rrtr); | 
|  |  | 
|  | rtcp::ReceiveTimeInfo time_info( | 
|  | prng_.Rand<uint32_t>(), prng_.Rand<uint32_t>(), prng_.Rand<uint32_t>()); | 
|  | extended_report.AddDlrrItem(time_info); | 
|  |  | 
|  | rtcp::TargetBitrate target_bitrate; | 
|  | target_bitrate.AddTargetBitrate(/*spatial layer*/ prng_.Rand(0, 3), | 
|  | /*temporal layer*/ prng_.Rand(0, 3), | 
|  | /*bitrate kbps*/ prng_.Rand(0, 50000)); | 
|  | target_bitrate.AddTargetBitrate(/*spatial layer*/ prng_.Rand(4, 7), | 
|  | /*temporal layer*/ prng_.Rand(4, 7), | 
|  | /*bitrate kbps*/ prng_.Rand(0, 50000)); | 
|  | extended_report.SetTargetBitrate(target_bitrate); | 
|  | return extended_report; | 
|  | } | 
|  |  | 
|  | rtcp::Nack EventGenerator::NewNack() { | 
|  | rtcp::Nack nack; | 
|  | uint16_t base_seq_no = prng_.Rand<uint16_t>(); | 
|  | std::vector<uint16_t> nack_list; | 
|  | nack_list.push_back(base_seq_no); | 
|  | for (uint16_t i = 1u; i < 10u; i++) { | 
|  | if (prng_.Rand<bool>()) | 
|  | nack_list.push_back(base_seq_no + i); | 
|  | } | 
|  | nack.SetPacketIds(nack_list); | 
|  | return nack; | 
|  | } | 
|  |  | 
|  | rtcp::Fir EventGenerator::NewFir() { | 
|  | rtcp::Fir fir; | 
|  | fir.SetSenderSsrc(prng_.Rand<uint32_t>()); | 
|  | fir.AddRequestTo(/*ssrc*/ prng_.Rand<uint32_t>(), | 
|  | /*seq num*/ prng_.Rand<uint8_t>()); | 
|  | fir.AddRequestTo(/*ssrc*/ prng_.Rand<uint32_t>(), | 
|  | /*seq num*/ prng_.Rand<uint8_t>()); | 
|  | return fir; | 
|  | } | 
|  |  | 
|  | rtcp::Pli EventGenerator::NewPli() { | 
|  | rtcp::Pli pli; | 
|  | pli.SetSenderSsrc(prng_.Rand<uint32_t>()); | 
|  | pli.SetMediaSsrc(prng_.Rand<uint32_t>()); | 
|  | return pli; | 
|  | } | 
|  |  | 
|  | rtcp::Bye EventGenerator::NewBye() { | 
|  | rtcp::Bye bye; | 
|  | bye.SetSenderSsrc(prng_.Rand<uint32_t>()); | 
|  | std::vector<uint32_t> csrcs{prng_.Rand<uint32_t>(), prng_.Rand<uint32_t>()}; | 
|  | bye.SetCsrcs(csrcs); | 
|  | if (prng_.Rand(0, 2)) { | 
|  | bye.SetReason("foo"); | 
|  | } else { | 
|  | bye.SetReason("bar"); | 
|  | } | 
|  | return bye; | 
|  | } | 
|  |  | 
|  | rtcp::TransportFeedback EventGenerator::NewTransportFeedback() { | 
|  | rtcp::TransportFeedback transport_feedback; | 
|  | uint16_t base_seq_no = prng_.Rand<uint16_t>(); | 
|  | Timestamp base_time = Timestamp::Micros(prng_.Rand<uint32_t>()); | 
|  | transport_feedback.SetBase(base_seq_no, base_time); | 
|  | transport_feedback.AddReceivedPacket(base_seq_no, base_time); | 
|  | Timestamp time = base_time; | 
|  | for (uint16_t i = 1u; i < 10u; i++) { | 
|  | time += TimeDelta::Micros(prng_.Rand(0, 100'000)); | 
|  | if (prng_.Rand<bool>()) { | 
|  | transport_feedback.AddReceivedPacket(base_seq_no + i, time); | 
|  | } | 
|  | } | 
|  | return transport_feedback; | 
|  | } | 
|  |  | 
|  | rtcp::Remb EventGenerator::NewRemb() { | 
|  | rtcp::Remb remb; | 
|  | // The remb bitrate is transported as a 16-bit mantissa and an 8-bit exponent. | 
|  | uint64_t bitrate_bps = prng_.Rand(0, (1 << 16) - 1) << prng_.Rand(7); | 
|  | std::vector<uint32_t> ssrcs{prng_.Rand<uint32_t>(), prng_.Rand<uint32_t>()}; | 
|  | remb.SetSsrcs(ssrcs); | 
|  | remb.SetBitrateBps(bitrate_bps); | 
|  | return remb; | 
|  | } | 
|  |  | 
|  | rtcp::LossNotification EventGenerator::NewLossNotification() { | 
|  | rtcp::LossNotification loss_notification; | 
|  | const uint16_t last_decoded = prng_.Rand<uint16_t>(); | 
|  | const uint16_t last_received = | 
|  | last_decoded + (prng_.Rand<uint16_t>() & 0x7fff); | 
|  | const bool decodability_flag = prng_.Rand<bool>(); | 
|  | EXPECT_TRUE( | 
|  | loss_notification.Set(last_decoded, last_received, decodability_flag)); | 
|  | return loss_notification; | 
|  | } | 
|  |  | 
|  | std::unique_ptr<RtcEventRouteChange> EventGenerator::NewRouteChange() { | 
|  | return std::make_unique<RtcEventRouteChange>(prng_.Rand<bool>(), | 
|  | prng_.Rand(0, 128)); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<RtcEventRemoteEstimate> EventGenerator::NewRemoteEstimate() { | 
|  | return std::make_unique<RtcEventRemoteEstimate>( | 
|  | DataRate::KilobitsPerSec(prng_.Rand(0, 100000)), | 
|  | DataRate::KilobitsPerSec(prng_.Rand(0, 100000))); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<RtcEventRtcpPacketIncoming> | 
|  | EventGenerator::NewRtcpPacketIncoming() { | 
|  | enum class SupportedRtcpTypes { | 
|  | kSenderReport = 0, | 
|  | kReceiverReport, | 
|  | kExtendedReports, | 
|  | kFir, | 
|  | kPli, | 
|  | kNack, | 
|  | kRemb, | 
|  | kBye, | 
|  | kTransportFeedback, | 
|  | kNumValues | 
|  | }; | 
|  | SupportedRtcpTypes type = static_cast<SupportedRtcpTypes>( | 
|  | prng_.Rand(0, static_cast<int>(SupportedRtcpTypes::kNumValues) - 1)); | 
|  | switch (type) { | 
|  | case SupportedRtcpTypes::kSenderReport: { | 
|  | rtcp::SenderReport sender_report = NewSenderReport(); | 
|  | Buffer buffer = sender_report.Build(); | 
|  | return std::make_unique<RtcEventRtcpPacketIncoming>(buffer); | 
|  | } | 
|  | case SupportedRtcpTypes::kReceiverReport: { | 
|  | rtcp::ReceiverReport receiver_report = NewReceiverReport(); | 
|  | Buffer buffer = receiver_report.Build(); | 
|  | return std::make_unique<RtcEventRtcpPacketIncoming>(buffer); | 
|  | } | 
|  | case SupportedRtcpTypes::kExtendedReports: { | 
|  | rtcp::ExtendedReports extended_report = NewExtendedReports(); | 
|  | Buffer buffer = extended_report.Build(); | 
|  | return std::make_unique<RtcEventRtcpPacketIncoming>(buffer); | 
|  | } | 
|  | case SupportedRtcpTypes::kFir: { | 
|  | rtcp::Fir fir = NewFir(); | 
|  | Buffer buffer = fir.Build(); | 
|  | return std::make_unique<RtcEventRtcpPacketIncoming>(buffer); | 
|  | } | 
|  | case SupportedRtcpTypes::kPli: { | 
|  | rtcp::Pli pli = NewPli(); | 
|  | Buffer buffer = pli.Build(); | 
|  | return std::make_unique<RtcEventRtcpPacketIncoming>(buffer); | 
|  | } | 
|  | case SupportedRtcpTypes::kNack: { | 
|  | rtcp::Nack nack = NewNack(); | 
|  | Buffer buffer = nack.Build(); | 
|  | return std::make_unique<RtcEventRtcpPacketIncoming>(buffer); | 
|  | } | 
|  | case SupportedRtcpTypes::kRemb: { | 
|  | rtcp::Remb remb = NewRemb(); | 
|  | Buffer buffer = remb.Build(); | 
|  | return std::make_unique<RtcEventRtcpPacketIncoming>(buffer); | 
|  | } | 
|  | case SupportedRtcpTypes::kBye: { | 
|  | rtcp::Bye bye = NewBye(); | 
|  | Buffer buffer = bye.Build(); | 
|  | return std::make_unique<RtcEventRtcpPacketIncoming>(buffer); | 
|  | } | 
|  | case SupportedRtcpTypes::kTransportFeedback: { | 
|  | rtcp::TransportFeedback transport_feedback = NewTransportFeedback(); | 
|  | Buffer buffer = transport_feedback.Build(); | 
|  | return std::make_unique<RtcEventRtcpPacketIncoming>(buffer); | 
|  | } | 
|  | default: | 
|  | RTC_DCHECK_NOTREACHED(); | 
|  | Buffer buffer; | 
|  | return std::make_unique<RtcEventRtcpPacketIncoming>(buffer); | 
|  | } | 
|  | } | 
|  |  | 
|  | std::unique_ptr<RtcEventRtcpPacketOutgoing> | 
|  | EventGenerator::NewRtcpPacketOutgoing() { | 
|  | enum class SupportedRtcpTypes { | 
|  | kSenderReport = 0, | 
|  | kReceiverReport, | 
|  | kExtendedReports, | 
|  | kFir, | 
|  | kPli, | 
|  | kNack, | 
|  | kRemb, | 
|  | kBye, | 
|  | kTransportFeedback, | 
|  | kNumValues | 
|  | }; | 
|  | SupportedRtcpTypes type = static_cast<SupportedRtcpTypes>( | 
|  | prng_.Rand(0, static_cast<int>(SupportedRtcpTypes::kNumValues) - 1)); | 
|  | switch (type) { | 
|  | case SupportedRtcpTypes::kSenderReport: { | 
|  | rtcp::SenderReport sender_report = NewSenderReport(); | 
|  | Buffer buffer = sender_report.Build(); | 
|  | return std::make_unique<RtcEventRtcpPacketOutgoing>(buffer); | 
|  | } | 
|  | case SupportedRtcpTypes::kReceiverReport: { | 
|  | rtcp::ReceiverReport receiver_report = NewReceiverReport(); | 
|  | Buffer buffer = receiver_report.Build(); | 
|  | return std::make_unique<RtcEventRtcpPacketOutgoing>(buffer); | 
|  | } | 
|  | case SupportedRtcpTypes::kExtendedReports: { | 
|  | rtcp::ExtendedReports extended_report = NewExtendedReports(); | 
|  | Buffer buffer = extended_report.Build(); | 
|  | return std::make_unique<RtcEventRtcpPacketOutgoing>(buffer); | 
|  | } | 
|  | case SupportedRtcpTypes::kFir: { | 
|  | rtcp::Fir fir = NewFir(); | 
|  | Buffer buffer = fir.Build(); | 
|  | return std::make_unique<RtcEventRtcpPacketOutgoing>(buffer); | 
|  | } | 
|  | case SupportedRtcpTypes::kPli: { | 
|  | rtcp::Pli pli = NewPli(); | 
|  | Buffer buffer = pli.Build(); | 
|  | return std::make_unique<RtcEventRtcpPacketOutgoing>(buffer); | 
|  | } | 
|  | case SupportedRtcpTypes::kNack: { | 
|  | rtcp::Nack nack = NewNack(); | 
|  | Buffer buffer = nack.Build(); | 
|  | return std::make_unique<RtcEventRtcpPacketOutgoing>(buffer); | 
|  | } | 
|  | case SupportedRtcpTypes::kRemb: { | 
|  | rtcp::Remb remb = NewRemb(); | 
|  | Buffer buffer = remb.Build(); | 
|  | return std::make_unique<RtcEventRtcpPacketOutgoing>(buffer); | 
|  | } | 
|  | case SupportedRtcpTypes::kBye: { | 
|  | rtcp::Bye bye = NewBye(); | 
|  | Buffer buffer = bye.Build(); | 
|  | return std::make_unique<RtcEventRtcpPacketOutgoing>(buffer); | 
|  | } | 
|  | case SupportedRtcpTypes::kTransportFeedback: { | 
|  | rtcp::TransportFeedback transport_feedback = NewTransportFeedback(); | 
|  | Buffer buffer = transport_feedback.Build(); | 
|  | return std::make_unique<RtcEventRtcpPacketOutgoing>(buffer); | 
|  | } | 
|  | default: | 
|  | RTC_DCHECK_NOTREACHED(); | 
|  | Buffer buffer; | 
|  | return std::make_unique<RtcEventRtcpPacketOutgoing>(buffer); | 
|  | } | 
|  | } | 
|  |  | 
|  | std::unique_ptr<RtcEventGenericPacketSent> | 
|  | EventGenerator::NewGenericPacketSent() { | 
|  | return std::make_unique<RtcEventGenericPacketSent>( | 
|  | sent_packet_number_++, prng_.Rand(40, 50), prng_.Rand(0, 150), | 
|  | prng_.Rand(0, 1000)); | 
|  | } | 
|  | std::unique_ptr<RtcEventGenericPacketReceived> | 
|  | EventGenerator::NewGenericPacketReceived() { | 
|  | return std::make_unique<RtcEventGenericPacketReceived>( | 
|  | received_packet_number_++, prng_.Rand(40, 250)); | 
|  | } | 
|  | std::unique_ptr<RtcEventGenericAckReceived> | 
|  | EventGenerator::NewGenericAckReceived() { | 
|  | std::optional<int64_t> receive_timestamp = std::nullopt; | 
|  | if (prng_.Rand(0, 2) > 0) { | 
|  | receive_timestamp = prng_.Rand(0, 100000); | 
|  | } | 
|  | AckedPacket packet[1] = {{.packet_number = prng_.Rand(40, 250), | 
|  | .receive_acked_packet_time_ms = receive_timestamp}}; | 
|  | return std::move(RtcEventGenericAckReceived::CreateLogs( | 
|  | received_packet_number_++, packet)[0]); | 
|  | } | 
|  |  | 
|  | void EventGenerator::RandomizeRtpPacket( | 
|  | size_t payload_size, | 
|  | size_t padding_size, | 
|  | uint32_t ssrc, | 
|  | const RtpHeaderExtensionMap& extension_map, | 
|  | RtpPacket* rtp_packet, | 
|  | bool all_configured_exts) { | 
|  | constexpr int kMaxPayloadType = 127; | 
|  | rtp_packet->SetPayloadType(prng_.Rand(kMaxPayloadType)); | 
|  | rtp_packet->SetMarker(prng_.Rand<bool>()); | 
|  | rtp_packet->SetSequenceNumber(prng_.Rand<uint16_t>()); | 
|  | rtp_packet->SetSsrc(ssrc); | 
|  | rtp_packet->SetTimestamp(prng_.Rand<uint32_t>()); | 
|  |  | 
|  | uint32_t csrcs_count = prng_.Rand(0, kMaxCsrcs); | 
|  | std::vector<uint32_t> csrcs; | 
|  | for (size_t i = 0; i < csrcs_count; i++) { | 
|  | csrcs.push_back(prng_.Rand<uint32_t>()); | 
|  | } | 
|  | rtp_packet->SetCsrcs(csrcs); | 
|  |  | 
|  | if (extension_map.IsRegistered(TransmissionOffset::kId) && | 
|  | (all_configured_exts || prng_.Rand<bool>())) { | 
|  | rtp_packet->SetExtension<TransmissionOffset>(prng_.Rand(0x00ffffff)); | 
|  | } | 
|  |  | 
|  | if (extension_map.IsRegistered(AudioLevelExtension::kId) && | 
|  | (all_configured_exts || prng_.Rand<bool>())) { | 
|  | rtp_packet->SetExtension<AudioLevelExtension>( | 
|  | AudioLevel(prng_.Rand<bool>(), prng_.Rand(127))); | 
|  | } | 
|  |  | 
|  | if (extension_map.IsRegistered(AbsoluteSendTime::kId) && | 
|  | (all_configured_exts || prng_.Rand<bool>())) { | 
|  | rtp_packet->SetExtension<AbsoluteSendTime>(prng_.Rand(0x00ffffff)); | 
|  | } | 
|  |  | 
|  | if (extension_map.IsRegistered(VideoOrientation::kId) && | 
|  | (all_configured_exts || prng_.Rand<bool>())) { | 
|  | rtp_packet->SetExtension<VideoOrientation>(prng_.Rand(3)); | 
|  | } | 
|  |  | 
|  | if (extension_map.IsRegistered(TransportSequenceNumber::kId) && | 
|  | (all_configured_exts || prng_.Rand<bool>())) { | 
|  | rtp_packet->SetExtension<TransportSequenceNumber>(prng_.Rand<uint16_t>()); | 
|  | } | 
|  |  | 
|  | if (extension_map.IsRegistered(RtpDependencyDescriptorExtension::kId) && | 
|  | (all_configured_exts || prng_.Rand<bool>())) { | 
|  | std::vector<uint8_t> raw_data(3 + prng_.Rand(6)); | 
|  | for (uint8_t& d : raw_data) { | 
|  | d = prng_.Rand<uint8_t>(); | 
|  | } | 
|  | rtp_packet->SetRawExtension<RtpDependencyDescriptorExtension>(raw_data); | 
|  | } | 
|  |  | 
|  | RTC_CHECK_LE(rtp_packet->headers_size() + payload_size, IP_PACKET_SIZE); | 
|  |  | 
|  | uint8_t* payload = rtp_packet->AllocatePayload(payload_size); | 
|  | RTC_DCHECK(payload != nullptr); | 
|  | for (size_t i = 0; i < payload_size; i++) { | 
|  | payload[i] = prng_.Rand<uint8_t>(); | 
|  | } | 
|  | RTC_CHECK(rtp_packet->SetPadding(padding_size)); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<RtcEventRtpPacketIncoming> EventGenerator::NewRtpPacketIncoming( | 
|  | uint32_t ssrc, | 
|  | const RtpHeaderExtensionMap& extension_map, | 
|  | bool all_configured_exts) { | 
|  | constexpr size_t kMaxPaddingLength = 224; | 
|  | const bool padding = prng_.Rand(0, 9) == 0;  // Let padding be 10% probable. | 
|  | const size_t padding_size = !padding ? 0u : prng_.Rand(0u, kMaxPaddingLength); | 
|  |  | 
|  | // 12 bytes RTP header, 4 bytes for 0xBEDE + alignment, 4 bytes per CSRC. | 
|  | constexpr size_t kMaxHeaderSize = | 
|  | 16 + 4 * kMaxCsrcs + kMaxExtensionSizeBytes * kMaxNumExtensions; | 
|  |  | 
|  | // In principle, a packet can contain both padding and other payload. | 
|  | // Currently, RTC eventlog encoder-parser can only maintain padding length if | 
|  | // packet is full padding. | 
|  | // TODO(webrtc:9730): Remove the deterministic logic for padding_size > 0. | 
|  | size_t payload_size = | 
|  | padding_size > 0 ? 0 | 
|  | : prng_.Rand(0u, static_cast<uint32_t>(IP_PACKET_SIZE - | 
|  | 1 - padding_size - | 
|  | kMaxHeaderSize)); | 
|  |  | 
|  | RtpPacketReceived rtp_packet(&extension_map); | 
|  | RandomizeRtpPacket(payload_size, padding_size, ssrc, extension_map, | 
|  | &rtp_packet, all_configured_exts); | 
|  |  | 
|  | return std::make_unique<RtcEventRtpPacketIncoming>(rtp_packet); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<RtcEventRtpPacketOutgoing> EventGenerator::NewRtpPacketOutgoing( | 
|  | uint32_t ssrc, | 
|  | const RtpHeaderExtensionMap& extension_map, | 
|  | bool all_configured_exts) { | 
|  | constexpr size_t kMaxPaddingLength = 224; | 
|  | const bool padding = prng_.Rand(0, 9) == 0;  // Let padding be 10% probable. | 
|  | const size_t padding_size = !padding ? 0u : prng_.Rand(0u, kMaxPaddingLength); | 
|  |  | 
|  | // 12 bytes RTP header, 4 bytes for 0xBEDE + alignment, 4 bytes per CSRC. | 
|  | constexpr size_t kMaxHeaderSize = | 
|  | 16 + 4 * kMaxCsrcs + kMaxExtensionSizeBytes * kMaxNumExtensions; | 
|  |  | 
|  | // In principle,a packet can contain both padding and other payload. | 
|  | // Currently, RTC eventlog encoder-parser can only maintain padding length if | 
|  | // packet is full padding. | 
|  | // TODO(webrtc:9730): Remove the deterministic logic for padding_size > 0. | 
|  | size_t payload_size = | 
|  | padding_size > 0 ? 0 | 
|  | : prng_.Rand(0u, static_cast<uint32_t>(IP_PACKET_SIZE - | 
|  | 1 - padding_size - | 
|  | kMaxHeaderSize)); | 
|  |  | 
|  | RtpPacketToSend rtp_packet(&extension_map); | 
|  | RandomizeRtpPacket(payload_size, padding_size, ssrc, extension_map, | 
|  | &rtp_packet, all_configured_exts); | 
|  |  | 
|  | int probe_cluster_id = prng_.Rand(0, 100000); | 
|  | return std::make_unique<RtcEventRtpPacketOutgoing>(rtp_packet, | 
|  | probe_cluster_id); | 
|  | } | 
|  |  | 
|  | RtpHeaderExtensionMap EventGenerator::NewRtpHeaderExtensionMap( | 
|  | bool configure_all, | 
|  | const std::vector<RTPExtensionType>& excluded_extensions) { | 
|  | RtpHeaderExtensionMap extension_map; | 
|  | std::vector<int> id(RtpExtension::kOneByteHeaderExtensionMaxId - | 
|  | RtpExtension::kMinId + 1); | 
|  | std::iota(id.begin(), id.end(), RtpExtension::kMinId); | 
|  | ShuffleInPlace(&prng_, ArrayView<int>(id)); | 
|  |  | 
|  | auto not_excluded = [&](RTPExtensionType type) -> bool { | 
|  | return !absl::c_linear_search(excluded_extensions, type); | 
|  | }; | 
|  |  | 
|  | if (not_excluded(AudioLevelExtension::kId) && | 
|  | (configure_all || prng_.Rand<bool>())) { | 
|  | extension_map.Register<AudioLevelExtension>(id[0]); | 
|  | } | 
|  | if (not_excluded(TransmissionOffset::kId) && | 
|  | (configure_all || prng_.Rand<bool>())) { | 
|  | extension_map.Register<TransmissionOffset>(id[1]); | 
|  | } | 
|  | if (not_excluded(AbsoluteSendTime::kId) && | 
|  | (configure_all || prng_.Rand<bool>())) { | 
|  | extension_map.Register<AbsoluteSendTime>(id[2]); | 
|  | } | 
|  | if (not_excluded(VideoOrientation::kId) && | 
|  | (configure_all || prng_.Rand<bool>())) { | 
|  | extension_map.Register<VideoOrientation>(id[3]); | 
|  | } | 
|  | if (not_excluded(TransportSequenceNumber::kId) && | 
|  | (configure_all || prng_.Rand<bool>())) { | 
|  | extension_map.Register<TransportSequenceNumber>(id[4]); | 
|  | } | 
|  | if (not_excluded(RtpDependencyDescriptorExtension::kId) && | 
|  | (configure_all || prng_.Rand<bool>())) { | 
|  | extension_map.Register<RtpDependencyDescriptorExtension>(id[5]); | 
|  | } | 
|  |  | 
|  | return extension_map; | 
|  | } | 
|  |  | 
|  | std::unique_ptr<RtcEventAudioReceiveStreamConfig> | 
|  | EventGenerator::NewAudioReceiveStreamConfig( | 
|  | uint32_t ssrc, | 
|  | const RtpHeaderExtensionMap& extensions) { | 
|  | auto config = std::make_unique<rtclog::StreamConfig>(); | 
|  | // Add SSRCs for the stream. | 
|  | config->remote_ssrc = ssrc; | 
|  | config->local_ssrc = prng_.Rand<uint32_t>(); | 
|  | // Add header extensions. | 
|  | for (size_t i = 0; i < kMaxNumExtensions; i++) { | 
|  | uint8_t id = extensions.GetId(kExtensions[i].type); | 
|  | if (id != RtpHeaderExtensionMap::kInvalidId) { | 
|  | config->rtp_extensions.emplace_back(kExtensions[i].name, id); | 
|  | } | 
|  | } | 
|  |  | 
|  | return std::make_unique<RtcEventAudioReceiveStreamConfig>(std::move(config)); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<RtcEventAudioSendStreamConfig> | 
|  | EventGenerator::NewAudioSendStreamConfig( | 
|  | uint32_t ssrc, | 
|  | const RtpHeaderExtensionMap& extensions) { | 
|  | auto config = std::make_unique<rtclog::StreamConfig>(); | 
|  | // Add SSRC to the stream. | 
|  | config->local_ssrc = ssrc; | 
|  | // Add header extensions. | 
|  | for (size_t i = 0; i < kMaxNumExtensions; i++) { | 
|  | uint8_t id = extensions.GetId(kExtensions[i].type); | 
|  | if (id != RtpHeaderExtensionMap::kInvalidId) { | 
|  | config->rtp_extensions.emplace_back(kExtensions[i].name, id); | 
|  | } | 
|  | } | 
|  | return std::make_unique<RtcEventAudioSendStreamConfig>(std::move(config)); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<RtcEventVideoReceiveStreamConfig> | 
|  | EventGenerator::NewVideoReceiveStreamConfig( | 
|  | uint32_t ssrc, | 
|  | const RtpHeaderExtensionMap& extensions) { | 
|  | auto config = std::make_unique<rtclog::StreamConfig>(); | 
|  |  | 
|  | // Add SSRCs for the stream. | 
|  | config->remote_ssrc = ssrc; | 
|  | config->local_ssrc = prng_.Rand<uint32_t>(); | 
|  | // Add extensions and settings for RTCP. | 
|  | config->rtcp_mode = | 
|  | prng_.Rand<bool>() ? RtcpMode::kCompound : RtcpMode::kReducedSize; | 
|  | config->remb = prng_.Rand<bool>(); | 
|  | config->rtx_ssrc = prng_.Rand<uint32_t>(); | 
|  | config->codecs.emplace_back(prng_.Rand<bool>() ? "VP8" : "H264", | 
|  | prng_.Rand(127), prng_.Rand(127)); | 
|  | // Add header extensions. | 
|  | for (size_t i = 0; i < kMaxNumExtensions; i++) { | 
|  | uint8_t id = extensions.GetId(kExtensions[i].type); | 
|  | if (id != RtpHeaderExtensionMap::kInvalidId) { | 
|  | config->rtp_extensions.emplace_back(kExtensions[i].name, id); | 
|  | } | 
|  | } | 
|  | return std::make_unique<RtcEventVideoReceiveStreamConfig>(std::move(config)); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<RtcEventVideoSendStreamConfig> | 
|  | EventGenerator::NewVideoSendStreamConfig( | 
|  | uint32_t ssrc, | 
|  | const RtpHeaderExtensionMap& extensions) { | 
|  | auto config = std::make_unique<rtclog::StreamConfig>(); | 
|  |  | 
|  | config->codecs.emplace_back(prng_.Rand<bool>() ? "VP8" : "H264", | 
|  | prng_.Rand(127), prng_.Rand(127)); | 
|  | config->local_ssrc = ssrc; | 
|  | config->rtx_ssrc = prng_.Rand<uint32_t>(); | 
|  | // Add header extensions. | 
|  | for (size_t i = 0; i < kMaxNumExtensions; i++) { | 
|  | uint8_t id = extensions.GetId(kExtensions[i].type); | 
|  | if (id != RtpHeaderExtensionMap::kInvalidId) { | 
|  | config->rtp_extensions.emplace_back(kExtensions[i].name, id); | 
|  | } | 
|  | } | 
|  | return std::make_unique<RtcEventVideoSendStreamConfig>(std::move(config)); | 
|  | } | 
|  |  | 
|  | void EventVerifier::VerifyLoggedAlrStateEvent( | 
|  | const RtcEventAlrState& original_event, | 
|  | const LoggedAlrStateEvent& logged_event) const { | 
|  | EXPECT_EQ(original_event.timestamp_ms(), logged_event.log_time_ms()); | 
|  | EXPECT_EQ(original_event.in_alr(), logged_event.in_alr); | 
|  | } | 
|  |  | 
|  | void EventVerifier::VerifyLoggedAudioPlayoutEvent( | 
|  | const RtcEventAudioPlayout& original_event, | 
|  | const LoggedAudioPlayoutEvent& logged_event) const { | 
|  | EXPECT_EQ(original_event.timestamp_ms(), logged_event.log_time_ms()); | 
|  | EXPECT_EQ(original_event.ssrc(), logged_event.ssrc); | 
|  | } | 
|  |  | 
|  | void EventVerifier::VerifyLoggedAudioNetworkAdaptationEvent( | 
|  | const RtcEventAudioNetworkAdaptation& original_event, | 
|  | const LoggedAudioNetworkAdaptationEvent& logged_event) const { | 
|  | EXPECT_EQ(original_event.timestamp_ms(), logged_event.log_time_ms()); | 
|  |  | 
|  | EXPECT_EQ(original_event.config().bitrate_bps, | 
|  | logged_event.config.bitrate_bps); | 
|  | EXPECT_EQ(original_event.config().enable_dtx, logged_event.config.enable_dtx); | 
|  | EXPECT_EQ(original_event.config().enable_fec, logged_event.config.enable_fec); | 
|  | EXPECT_EQ(original_event.config().frame_length_ms, | 
|  | logged_event.config.frame_length_ms); | 
|  | EXPECT_EQ(original_event.config().num_channels, | 
|  | logged_event.config.num_channels); | 
|  |  | 
|  | // uplink_packet_loss_fraction | 
|  | ASSERT_EQ(original_event.config().uplink_packet_loss_fraction.has_value(), | 
|  | logged_event.config.uplink_packet_loss_fraction.has_value()); | 
|  | if (original_event.config().uplink_packet_loss_fraction.has_value()) { | 
|  | const float original = | 
|  | original_event.config().uplink_packet_loss_fraction.value(); | 
|  | const float logged = | 
|  | logged_event.config.uplink_packet_loss_fraction.value(); | 
|  | const float uplink_packet_loss_fraction_delta = std::abs(original - logged); | 
|  | EXPECT_LE(uplink_packet_loss_fraction_delta, 0.0001f); | 
|  | } | 
|  | } | 
|  |  | 
|  | void EventVerifier::VerifyLoggedBweDelayBasedUpdate( | 
|  | const RtcEventBweUpdateDelayBased& original_event, | 
|  | const LoggedBweDelayBasedUpdate& logged_event) const { | 
|  | EXPECT_EQ(original_event.timestamp_ms(), logged_event.log_time_ms()); | 
|  | EXPECT_EQ(original_event.bitrate_bps(), logged_event.bitrate_bps); | 
|  | EXPECT_EQ(original_event.detector_state(), logged_event.detector_state); | 
|  | } | 
|  |  | 
|  | void EventVerifier::VerifyLoggedBweLossBasedUpdate( | 
|  | const RtcEventBweUpdateLossBased& original_event, | 
|  | const LoggedBweLossBasedUpdate& logged_event) const { | 
|  | EXPECT_EQ(original_event.timestamp_ms(), logged_event.log_time_ms()); | 
|  | EXPECT_EQ(original_event.bitrate_bps(), logged_event.bitrate_bps); | 
|  | EXPECT_EQ(original_event.fraction_loss(), logged_event.fraction_lost); | 
|  | EXPECT_EQ(original_event.total_packets(), logged_event.expected_packets); | 
|  | } | 
|  |  | 
|  | void EventVerifier::VerifyLoggedBweProbeClusterCreatedEvent( | 
|  | const RtcEventProbeClusterCreated& original_event, | 
|  | const LoggedBweProbeClusterCreatedEvent& logged_event) const { | 
|  | EXPECT_EQ(original_event.timestamp_ms(), logged_event.log_time_ms()); | 
|  | EXPECT_EQ(original_event.id(), logged_event.id); | 
|  | EXPECT_EQ(original_event.bitrate_bps(), logged_event.bitrate_bps); | 
|  | EXPECT_EQ(original_event.min_probes(), logged_event.min_packets); | 
|  | EXPECT_EQ(original_event.min_bytes(), logged_event.min_bytes); | 
|  | } | 
|  |  | 
|  | void EventVerifier::VerifyLoggedBweProbeFailureEvent( | 
|  | const RtcEventProbeResultFailure& original_event, | 
|  | const LoggedBweProbeFailureEvent& logged_event) const { | 
|  | EXPECT_EQ(original_event.timestamp_ms(), logged_event.log_time_ms()); | 
|  | EXPECT_EQ(original_event.id(), logged_event.id); | 
|  | EXPECT_EQ(original_event.failure_reason(), logged_event.failure_reason); | 
|  | } | 
|  |  | 
|  | void EventVerifier::VerifyLoggedBweProbeSuccessEvent( | 
|  | const RtcEventProbeResultSuccess& original_event, | 
|  | const LoggedBweProbeSuccessEvent& logged_event) const { | 
|  | EXPECT_EQ(original_event.timestamp_ms(), logged_event.log_time_ms()); | 
|  | EXPECT_EQ(original_event.id(), logged_event.id); | 
|  | EXPECT_EQ(original_event.bitrate_bps(), logged_event.bitrate_bps); | 
|  | } | 
|  |  | 
|  | void EventVerifier::VerifyLoggedDtlsTransportState( | 
|  | const RtcEventDtlsTransportState& original_event, | 
|  | const LoggedDtlsTransportState& logged_event) const { | 
|  | EXPECT_EQ(original_event.timestamp_ms(), logged_event.log_time_ms()); | 
|  | EXPECT_EQ(original_event.dtls_transport_state(), | 
|  | logged_event.dtls_transport_state); | 
|  | } | 
|  |  | 
|  | void EventVerifier::VerifyLoggedDtlsWritableState( | 
|  | const RtcEventDtlsWritableState& original_event, | 
|  | const LoggedDtlsWritableState& logged_event) const { | 
|  | EXPECT_EQ(original_event.timestamp_ms(), logged_event.log_time_ms()); | 
|  | EXPECT_EQ(original_event.writable(), logged_event.writable); | 
|  | } | 
|  |  | 
|  | void EventVerifier::VerifyLoggedFrameDecoded( | 
|  | const RtcEventFrameDecoded& original_event, | 
|  | const LoggedFrameDecoded& logged_event) const { | 
|  | EXPECT_EQ(original_event.timestamp_ms(), logged_event.log_time_ms()); | 
|  | EXPECT_EQ(original_event.ssrc(), logged_event.ssrc); | 
|  | EXPECT_EQ(original_event.render_time_ms(), logged_event.render_time_ms); | 
|  | EXPECT_EQ(original_event.width(), logged_event.width); | 
|  | EXPECT_EQ(original_event.height(), logged_event.height); | 
|  | EXPECT_EQ(original_event.codec(), logged_event.codec); | 
|  | EXPECT_EQ(original_event.qp(), logged_event.qp); | 
|  | } | 
|  |  | 
|  | void EventVerifier::VerifyLoggedIceCandidatePairConfig( | 
|  | const RtcEventIceCandidatePairConfig& original_event, | 
|  | const LoggedIceCandidatePairConfig& logged_event) const { | 
|  | EXPECT_EQ(original_event.timestamp_ms(), logged_event.log_time_ms()); | 
|  |  | 
|  | EXPECT_EQ(original_event.type(), logged_event.type); | 
|  | EXPECT_EQ(original_event.candidate_pair_id(), logged_event.candidate_pair_id); | 
|  | EXPECT_EQ(original_event.candidate_pair_desc().local_candidate_type, | 
|  | logged_event.local_candidate_type); | 
|  | EXPECT_EQ(original_event.candidate_pair_desc().local_relay_protocol, | 
|  | logged_event.local_relay_protocol); | 
|  | EXPECT_EQ(original_event.candidate_pair_desc().local_network_type, | 
|  | logged_event.local_network_type); | 
|  | EXPECT_EQ(original_event.candidate_pair_desc().local_address_family, | 
|  | logged_event.local_address_family); | 
|  | EXPECT_EQ(original_event.candidate_pair_desc().remote_candidate_type, | 
|  | logged_event.remote_candidate_type); | 
|  | EXPECT_EQ(original_event.candidate_pair_desc().remote_address_family, | 
|  | logged_event.remote_address_family); | 
|  | EXPECT_EQ(original_event.candidate_pair_desc().candidate_pair_protocol, | 
|  | logged_event.candidate_pair_protocol); | 
|  | } | 
|  |  | 
|  | void EventVerifier::VerifyLoggedIceCandidatePairEvent( | 
|  | const RtcEventIceCandidatePair& original_event, | 
|  | const LoggedIceCandidatePairEvent& logged_event) const { | 
|  | EXPECT_EQ(original_event.timestamp_ms(), logged_event.log_time_ms()); | 
|  |  | 
|  | EXPECT_EQ(original_event.type(), logged_event.type); | 
|  | EXPECT_EQ(original_event.candidate_pair_id(), logged_event.candidate_pair_id); | 
|  | if (encoding_type_ == RtcEventLog::EncodingType::NewFormat) { | 
|  | EXPECT_EQ(original_event.transaction_id(), logged_event.transaction_id); | 
|  | } | 
|  | } | 
|  |  | 
|  | template <typename Event> | 
|  | void VerifyLoggedRtpHeader(const Event& original_header, | 
|  | const RTPHeader& logged_header) { | 
|  | // Standard RTP header. | 
|  | EXPECT_EQ(original_header.Marker(), logged_header.markerBit); | 
|  | EXPECT_EQ(original_header.PayloadType(), logged_header.payloadType); | 
|  | EXPECT_EQ(original_header.SequenceNumber(), logged_header.sequenceNumber); | 
|  | EXPECT_EQ(original_header.Timestamp(), logged_header.timestamp); | 
|  | EXPECT_EQ(original_header.Ssrc(), logged_header.ssrc); | 
|  |  | 
|  | EXPECT_EQ(original_header.header_length(), logged_header.headerLength); | 
|  |  | 
|  | // TransmissionOffset header extension. | 
|  | ASSERT_EQ(original_header.template HasExtension<TransmissionOffset>(), | 
|  | logged_header.extension.hasTransmissionTimeOffset); | 
|  | if (logged_header.extension.hasTransmissionTimeOffset) { | 
|  | int32_t offset; | 
|  | ASSERT_TRUE( | 
|  | original_header.template GetExtension<TransmissionOffset>(&offset)); | 
|  | EXPECT_EQ(offset, logged_header.extension.transmissionTimeOffset); | 
|  | } | 
|  |  | 
|  | // AbsoluteSendTime header extension. | 
|  | ASSERT_EQ(original_header.template HasExtension<AbsoluteSendTime>(), | 
|  | logged_header.extension.hasAbsoluteSendTime); | 
|  | if (logged_header.extension.hasAbsoluteSendTime) { | 
|  | uint32_t sendtime; | 
|  | ASSERT_TRUE( | 
|  | original_header.template GetExtension<AbsoluteSendTime>(&sendtime)); | 
|  | EXPECT_EQ(sendtime, logged_header.extension.absoluteSendTime); | 
|  | } | 
|  |  | 
|  | // TransportSequenceNumber header extension. | 
|  | ASSERT_EQ(original_header.template HasExtension<TransportSequenceNumber>(), | 
|  | logged_header.extension.hasTransportSequenceNumber); | 
|  | if (logged_header.extension.hasTransportSequenceNumber) { | 
|  | uint16_t seqnum; | 
|  | ASSERT_TRUE(original_header.template GetExtension<TransportSequenceNumber>( | 
|  | &seqnum)); | 
|  | EXPECT_EQ(seqnum, logged_header.extension.transportSequenceNumber); | 
|  | } | 
|  |  | 
|  | // AudioLevel header extension. | 
|  | ASSERT_EQ(original_header.template HasExtension<AudioLevelExtension>(), | 
|  | logged_header.extension.audio_level().has_value()); | 
|  | if (logged_header.extension.audio_level()) { | 
|  | AudioLevel audio_level; | 
|  | ASSERT_TRUE(original_header.template GetExtension<AudioLevelExtension>( | 
|  | &audio_level)); | 
|  | EXPECT_EQ(audio_level.voice_activity(), | 
|  | logged_header.extension.audio_level()->voice_activity()); | 
|  | EXPECT_EQ(audio_level.level(), | 
|  | logged_header.extension.audio_level()->level()); | 
|  | } | 
|  |  | 
|  | // VideoOrientation header extension. | 
|  | ASSERT_EQ(original_header.template HasExtension<VideoOrientation>(), | 
|  | logged_header.extension.hasVideoRotation); | 
|  | if (logged_header.extension.hasVideoRotation) { | 
|  | uint8_t rotation; | 
|  | ASSERT_TRUE( | 
|  | original_header.template GetExtension<VideoOrientation>(&rotation)); | 
|  | EXPECT_EQ(ConvertCVOByteToVideoRotation(rotation), | 
|  | logged_header.extension.videoRotation); | 
|  | } | 
|  | } | 
|  |  | 
|  | template <typename Event> | 
|  | void EventVerifier::VerifyLoggedDependencyDescriptor( | 
|  | const Event& packet, | 
|  | const std::vector<uint8_t>& logged_dd) const { | 
|  | if (expect_dependency_descriptor_rtp_header_extension_is_set_) { | 
|  | ArrayView<const uint8_t> original = | 
|  | packet.template GetRawExtension<RtpDependencyDescriptorExtension>(); | 
|  | EXPECT_THAT(logged_dd, ElementsAreArray(original)); | 
|  | } else { | 
|  | EXPECT_THAT(logged_dd, IsEmpty()); | 
|  | } | 
|  | } | 
|  |  | 
|  | void EventVerifier::VerifyLoggedRouteChangeEvent( | 
|  | const RtcEventRouteChange& original_event, | 
|  | const LoggedRouteChangeEvent& logged_event) const { | 
|  | EXPECT_EQ(original_event.timestamp_ms(), logged_event.log_time_ms()); | 
|  | EXPECT_EQ(original_event.connected(), logged_event.connected); | 
|  | EXPECT_EQ(original_event.overhead(), logged_event.overhead); | 
|  | } | 
|  |  | 
|  | void EventVerifier::VerifyLoggedRemoteEstimateEvent( | 
|  | const RtcEventRemoteEstimate& original_event, | 
|  | const LoggedRemoteEstimateEvent& logged_event) const { | 
|  | EXPECT_EQ(original_event.timestamp_ms(), logged_event.log_time_ms()); | 
|  | EXPECT_EQ(original_event.link_capacity_lower_, | 
|  | logged_event.link_capacity_lower); | 
|  | EXPECT_EQ(original_event.link_capacity_upper_, | 
|  | logged_event.link_capacity_upper); | 
|  | } | 
|  |  | 
|  | void EventVerifier::VerifyLoggedRtpPacketIncoming( | 
|  | const RtcEventRtpPacketIncoming& original_event, | 
|  | const LoggedRtpPacketIncoming& logged_event) const { | 
|  | EXPECT_EQ(original_event.timestamp_ms(), logged_event.log_time_ms()); | 
|  |  | 
|  | EXPECT_EQ(original_event.header_length(), logged_event.rtp.header_length); | 
|  |  | 
|  | EXPECT_EQ(original_event.packet_length(), logged_event.rtp.total_length); | 
|  |  | 
|  | // Currently, RTC eventlog encoder-parser can only maintain padding length | 
|  | // if packet is full padding. | 
|  | EXPECT_EQ(original_event.padding_length(), | 
|  | logged_event.rtp.header.paddingLength); | 
|  |  | 
|  | VerifyLoggedRtpHeader(original_event, logged_event.rtp.header); | 
|  | VerifyLoggedDependencyDescriptor( | 
|  | original_event, logged_event.rtp.dependency_descriptor_wire_format); | 
|  | } | 
|  |  | 
|  | void EventVerifier::VerifyLoggedRtpPacketOutgoing( | 
|  | const RtcEventRtpPacketOutgoing& original_event, | 
|  | const LoggedRtpPacketOutgoing& logged_event) const { | 
|  | EXPECT_EQ(original_event.timestamp_ms(), logged_event.log_time_ms()); | 
|  |  | 
|  | EXPECT_EQ(original_event.header_length(), logged_event.rtp.header_length); | 
|  |  | 
|  | EXPECT_EQ(original_event.packet_length(), logged_event.rtp.total_length); | 
|  |  | 
|  | // Currently, RTC eventlog encoder-parser can only maintain padding length | 
|  | // if packet is full padding. | 
|  | EXPECT_EQ(original_event.padding_length(), | 
|  | logged_event.rtp.header.paddingLength); | 
|  |  | 
|  | // TODO(terelius): Probe cluster ID isn't parsed, used or tested. Unless | 
|  | // someone has a strong reason to keep it, it'll be removed. | 
|  |  | 
|  | VerifyLoggedRtpHeader(original_event, logged_event.rtp.header); | 
|  | VerifyLoggedDependencyDescriptor( | 
|  | original_event, logged_event.rtp.dependency_descriptor_wire_format); | 
|  | } | 
|  |  | 
|  | void EventVerifier::VerifyLoggedGenericPacketSent( | 
|  | const RtcEventGenericPacketSent& original_event, | 
|  | const LoggedGenericPacketSent& logged_event) const { | 
|  | EXPECT_EQ(original_event.timestamp_ms(), logged_event.log_time_ms()); | 
|  | EXPECT_EQ(original_event.packet_number(), logged_event.packet_number); | 
|  | EXPECT_EQ(original_event.overhead_length(), logged_event.overhead_length); | 
|  | EXPECT_EQ(original_event.payload_length(), logged_event.payload_length); | 
|  | EXPECT_EQ(original_event.padding_length(), logged_event.padding_length); | 
|  | } | 
|  |  | 
|  | void EventVerifier::VerifyLoggedGenericPacketReceived( | 
|  | const RtcEventGenericPacketReceived& original_event, | 
|  | const LoggedGenericPacketReceived& logged_event) const { | 
|  | EXPECT_EQ(original_event.timestamp_ms(), logged_event.log_time_ms()); | 
|  | EXPECT_EQ(original_event.packet_number(), logged_event.packet_number); | 
|  | EXPECT_EQ(static_cast<int>(original_event.packet_length()), | 
|  | logged_event.packet_length); | 
|  | } | 
|  |  | 
|  | void EventVerifier::VerifyLoggedGenericAckReceived( | 
|  | const RtcEventGenericAckReceived& original_event, | 
|  | const LoggedGenericAckReceived& logged_event) const { | 
|  | EXPECT_EQ(original_event.timestamp_ms(), logged_event.log_time_ms()); | 
|  | EXPECT_EQ(original_event.packet_number(), logged_event.packet_number); | 
|  | EXPECT_EQ(original_event.acked_packet_number(), | 
|  | logged_event.acked_packet_number); | 
|  | EXPECT_EQ(original_event.receive_acked_packet_time_ms(), | 
|  | logged_event.receive_acked_packet_time_ms); | 
|  | } | 
|  |  | 
|  | void EventVerifier::VerifyLoggedRtcpPacketIncoming( | 
|  | const RtcEventRtcpPacketIncoming& original_event, | 
|  | const LoggedRtcpPacketIncoming& logged_event) const { | 
|  | EXPECT_EQ(original_event.timestamp_ms(), logged_event.log_time_ms()); | 
|  |  | 
|  | ASSERT_EQ(original_event.packet().size(), logged_event.rtcp.raw_data.size()); | 
|  | EXPECT_EQ( | 
|  | memcmp(original_event.packet().data(), logged_event.rtcp.raw_data.data(), | 
|  | original_event.packet().size()), | 
|  | 0); | 
|  | } | 
|  |  | 
|  | void EventVerifier::VerifyLoggedRtcpPacketOutgoing( | 
|  | const RtcEventRtcpPacketOutgoing& original_event, | 
|  | const LoggedRtcpPacketOutgoing& logged_event) const { | 
|  | EXPECT_EQ(original_event.timestamp_ms(), logged_event.log_time_ms()); | 
|  |  | 
|  | ASSERT_EQ(original_event.packet().size(), logged_event.rtcp.raw_data.size()); | 
|  | EXPECT_EQ( | 
|  | memcmp(original_event.packet().data(), logged_event.rtcp.raw_data.data(), | 
|  | original_event.packet().size()), | 
|  | 0); | 
|  | } | 
|  |  | 
|  | void EventVerifier::VerifyReportBlock( | 
|  | const rtcp::ReportBlock& original_report_block, | 
|  | const rtcp::ReportBlock& logged_report_block) { | 
|  | EXPECT_EQ(original_report_block.source_ssrc(), | 
|  | logged_report_block.source_ssrc()); | 
|  | EXPECT_EQ(original_report_block.fraction_lost(), | 
|  | logged_report_block.fraction_lost()); | 
|  | EXPECT_EQ(original_report_block.cumulative_lost(), | 
|  | logged_report_block.cumulative_lost()); | 
|  | EXPECT_EQ(original_report_block.extended_high_seq_num(), | 
|  | logged_report_block.extended_high_seq_num()); | 
|  | EXPECT_EQ(original_report_block.jitter(), logged_report_block.jitter()); | 
|  | EXPECT_EQ(original_report_block.last_sr(), logged_report_block.last_sr()); | 
|  | EXPECT_EQ(original_report_block.delay_since_last_sr(), | 
|  | logged_report_block.delay_since_last_sr()); | 
|  | } | 
|  |  | 
|  | void EventVerifier::VerifyLoggedSenderReport( | 
|  | int64_t log_time_ms, | 
|  | const rtcp::SenderReport& original_sr, | 
|  | const LoggedRtcpPacketSenderReport& logged_sr) { | 
|  | EXPECT_EQ(log_time_ms, logged_sr.log_time_ms()); | 
|  | EXPECT_EQ(original_sr.sender_ssrc(), logged_sr.sr.sender_ssrc()); | 
|  | EXPECT_EQ(original_sr.ntp(), logged_sr.sr.ntp()); | 
|  | EXPECT_EQ(original_sr.rtp_timestamp(), logged_sr.sr.rtp_timestamp()); | 
|  | EXPECT_EQ(original_sr.sender_packet_count(), | 
|  | logged_sr.sr.sender_packet_count()); | 
|  | EXPECT_EQ(original_sr.sender_octet_count(), | 
|  | logged_sr.sr.sender_octet_count()); | 
|  | ASSERT_EQ(original_sr.report_blocks().size(), | 
|  | logged_sr.sr.report_blocks().size()); | 
|  | for (size_t i = 0; i < original_sr.report_blocks().size(); i++) { | 
|  | VerifyReportBlock(original_sr.report_blocks()[i], | 
|  | logged_sr.sr.report_blocks()[i]); | 
|  | } | 
|  | } | 
|  |  | 
|  | void EventVerifier::VerifyLoggedReceiverReport( | 
|  | int64_t log_time_ms, | 
|  | const rtcp::ReceiverReport& original_rr, | 
|  | const LoggedRtcpPacketReceiverReport& logged_rr) { | 
|  | EXPECT_EQ(log_time_ms, logged_rr.log_time_ms()); | 
|  | EXPECT_EQ(original_rr.sender_ssrc(), logged_rr.rr.sender_ssrc()); | 
|  | ASSERT_EQ(original_rr.report_blocks().size(), | 
|  | logged_rr.rr.report_blocks().size()); | 
|  | for (size_t i = 0; i < original_rr.report_blocks().size(); i++) { | 
|  | VerifyReportBlock(original_rr.report_blocks()[i], | 
|  | logged_rr.rr.report_blocks()[i]); | 
|  | } | 
|  | } | 
|  |  | 
|  | void EventVerifier::VerifyLoggedExtendedReports( | 
|  | int64_t log_time_ms, | 
|  | const rtcp::ExtendedReports& original_xr, | 
|  | const LoggedRtcpPacketExtendedReports& logged_xr) { | 
|  | EXPECT_EQ(log_time_ms, logged_xr.log_time_ms()); | 
|  | EXPECT_EQ(original_xr.sender_ssrc(), logged_xr.xr.sender_ssrc()); | 
|  |  | 
|  | EXPECT_EQ(original_xr.rrtr().has_value(), logged_xr.xr.rrtr().has_value()); | 
|  | if (original_xr.rrtr().has_value() && logged_xr.xr.rrtr().has_value()) { | 
|  | EXPECT_EQ(original_xr.rrtr()->ntp(), logged_xr.xr.rrtr()->ntp()); | 
|  | } | 
|  |  | 
|  | const auto& original_subblocks = original_xr.dlrr().sub_blocks(); | 
|  | const auto& logged_subblocks = logged_xr.xr.dlrr().sub_blocks(); | 
|  | ASSERT_EQ(original_subblocks.size(), logged_subblocks.size()); | 
|  | for (size_t i = 0; i < original_subblocks.size(); i++) { | 
|  | EXPECT_EQ(original_subblocks[i].ssrc, logged_subblocks[i].ssrc); | 
|  | EXPECT_EQ(original_subblocks[i].last_rr, logged_subblocks[i].last_rr); | 
|  | EXPECT_EQ(original_subblocks[i].delay_since_last_rr, | 
|  | logged_subblocks[i].delay_since_last_rr); | 
|  | } | 
|  |  | 
|  | EXPECT_EQ(original_xr.target_bitrate().has_value(), | 
|  | logged_xr.xr.target_bitrate().has_value()); | 
|  | if (original_xr.target_bitrate().has_value() && | 
|  | logged_xr.xr.target_bitrate().has_value()) { | 
|  | const auto& original_bitrates = | 
|  | original_xr.target_bitrate()->GetTargetBitrates(); | 
|  | const auto& logged_bitrates = | 
|  | logged_xr.xr.target_bitrate()->GetTargetBitrates(); | 
|  | ASSERT_EQ(original_bitrates.size(), logged_bitrates.size()); | 
|  | for (size_t i = 0; i < original_bitrates.size(); i++) { | 
|  | EXPECT_EQ(original_bitrates[i].spatial_layer, | 
|  | logged_bitrates[i].spatial_layer); | 
|  | EXPECT_EQ(original_bitrates[i].temporal_layer, | 
|  | logged_bitrates[i].temporal_layer); | 
|  | EXPECT_EQ(original_bitrates[i].target_bitrate_kbps, | 
|  | logged_bitrates[i].target_bitrate_kbps); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void EventVerifier::VerifyLoggedFir(int64_t log_time_ms, | 
|  | const rtcp::Fir& original_fir, | 
|  | const LoggedRtcpPacketFir& logged_fir) { | 
|  | EXPECT_EQ(log_time_ms, logged_fir.log_time_ms()); | 
|  | EXPECT_EQ(original_fir.sender_ssrc(), logged_fir.fir.sender_ssrc()); | 
|  | const auto& original_requests = original_fir.requests(); | 
|  | const auto& logged_requests = logged_fir.fir.requests(); | 
|  | ASSERT_EQ(original_requests.size(), logged_requests.size()); | 
|  | for (size_t i = 0; i < original_requests.size(); i++) { | 
|  | EXPECT_EQ(original_requests[i].ssrc, logged_requests[i].ssrc); | 
|  | EXPECT_EQ(original_requests[i].seq_nr, logged_requests[i].seq_nr); | 
|  | } | 
|  | } | 
|  |  | 
|  | void EventVerifier::VerifyLoggedPli(int64_t log_time_ms, | 
|  | const rtcp::Pli& original_pli, | 
|  | const LoggedRtcpPacketPli& logged_pli) { | 
|  | EXPECT_EQ(log_time_ms, logged_pli.log_time_ms()); | 
|  | EXPECT_EQ(original_pli.sender_ssrc(), logged_pli.pli.sender_ssrc()); | 
|  | EXPECT_EQ(original_pli.media_ssrc(), logged_pli.pli.media_ssrc()); | 
|  | } | 
|  |  | 
|  | void EventVerifier::VerifyLoggedBye(int64_t log_time_ms, | 
|  | const rtcp::Bye& original_bye, | 
|  | const LoggedRtcpPacketBye& logged_bye) { | 
|  | EXPECT_EQ(log_time_ms, logged_bye.log_time_ms()); | 
|  | EXPECT_EQ(original_bye.sender_ssrc(), logged_bye.bye.sender_ssrc()); | 
|  | EXPECT_EQ(original_bye.csrcs(), logged_bye.bye.csrcs()); | 
|  | EXPECT_EQ(original_bye.reason(), logged_bye.bye.reason()); | 
|  | } | 
|  |  | 
|  | void EventVerifier::VerifyLoggedNack(int64_t log_time_ms, | 
|  | const rtcp::Nack& original_nack, | 
|  | const LoggedRtcpPacketNack& logged_nack) { | 
|  | EXPECT_EQ(log_time_ms, logged_nack.log_time_ms()); | 
|  | EXPECT_EQ(original_nack.packet_ids(), logged_nack.nack.packet_ids()); | 
|  | } | 
|  |  | 
|  | void EventVerifier::VerifyLoggedTransportFeedback( | 
|  | int64_t log_time_ms, | 
|  | const rtcp::TransportFeedback& original_transport_feedback, | 
|  | const LoggedRtcpPacketTransportFeedback& logged_transport_feedback) { | 
|  | EXPECT_EQ(log_time_ms, logged_transport_feedback.log_time_ms()); | 
|  | ASSERT_EQ( | 
|  | original_transport_feedback.GetReceivedPackets().size(), | 
|  | logged_transport_feedback.transport_feedback.GetReceivedPackets().size()); | 
|  | for (size_t i = 0; | 
|  | i < original_transport_feedback.GetReceivedPackets().size(); i++) { | 
|  | EXPECT_EQ( | 
|  | original_transport_feedback.GetReceivedPackets()[i].sequence_number(), | 
|  | logged_transport_feedback.transport_feedback.GetReceivedPackets()[i] | 
|  | .sequence_number()); | 
|  | EXPECT_EQ( | 
|  | original_transport_feedback.GetReceivedPackets()[i].delta(), | 
|  | logged_transport_feedback.transport_feedback.GetReceivedPackets()[i] | 
|  | .delta()); | 
|  | } | 
|  | } | 
|  |  | 
|  | void EventVerifier::VerifyLoggedRemb(int64_t log_time_ms, | 
|  | const rtcp::Remb& original_remb, | 
|  | const LoggedRtcpPacketRemb& logged_remb) { | 
|  | EXPECT_EQ(log_time_ms, logged_remb.log_time_ms()); | 
|  | EXPECT_EQ(original_remb.ssrcs(), logged_remb.remb.ssrcs()); | 
|  | EXPECT_EQ(original_remb.bitrate_bps(), logged_remb.remb.bitrate_bps()); | 
|  | } | 
|  |  | 
|  | void EventVerifier::VerifyLoggedLossNotification( | 
|  | int64_t log_time_ms, | 
|  | const rtcp::LossNotification& original_loss_notification, | 
|  | const LoggedRtcpPacketLossNotification& logged_loss_notification) { | 
|  | EXPECT_EQ(log_time_ms, logged_loss_notification.log_time_ms()); | 
|  | EXPECT_EQ(original_loss_notification.last_decoded(), | 
|  | logged_loss_notification.loss_notification.last_decoded()); | 
|  | EXPECT_EQ(original_loss_notification.last_received(), | 
|  | logged_loss_notification.loss_notification.last_received()); | 
|  | EXPECT_EQ(original_loss_notification.decodability_flag(), | 
|  | logged_loss_notification.loss_notification.decodability_flag()); | 
|  | } | 
|  |  | 
|  | void EventVerifier::VerifyLoggedStartEvent( | 
|  | int64_t start_time_us, | 
|  | int64_t utc_start_time_us, | 
|  | const LoggedStartEvent& logged_event) const { | 
|  | // Use approximate comparison to support various roundings to milliseconds. | 
|  | EXPECT_THAT(logged_event.log_time(), | 
|  | Near(Timestamp::Micros(start_time_us), TimeDelta::Millis(1))); | 
|  | if (encoding_type_ == RtcEventLog::EncodingType::NewFormat) { | 
|  | EXPECT_THAT( | 
|  | logged_event.utc_start_time, | 
|  | Near(Timestamp::Micros(utc_start_time_us), TimeDelta::Millis(1))); | 
|  | } | 
|  | } | 
|  |  | 
|  | void EventVerifier::VerifyLoggedStopEvent( | 
|  | int64_t stop_time_us, | 
|  | const LoggedStopEvent& logged_event) const { | 
|  | // Use approximate comparison to support various roundings to milliseconds. | 
|  | EXPECT_THAT(logged_event.log_time(), | 
|  | Near(Timestamp::Micros(stop_time_us), TimeDelta::Millis(1))); | 
|  | } | 
|  |  | 
|  | void VerifyLoggedStreamConfig(const rtclog::StreamConfig& original_config, | 
|  | const rtclog::StreamConfig& logged_config) { | 
|  | EXPECT_EQ(original_config.local_ssrc, logged_config.local_ssrc); | 
|  | EXPECT_EQ(original_config.remote_ssrc, logged_config.remote_ssrc); | 
|  | EXPECT_EQ(original_config.rtx_ssrc, logged_config.rtx_ssrc); | 
|  |  | 
|  | EXPECT_EQ(original_config.rtp_extensions.size(), | 
|  | logged_config.rtp_extensions.size()); | 
|  | size_t recognized_extensions = 0; | 
|  | for (size_t i = 0; i < kMaxNumExtensions; i++) { | 
|  | auto original_id = | 
|  | GetExtensionId(original_config.rtp_extensions, kExtensions[i].name); | 
|  | auto logged_id = | 
|  | GetExtensionId(logged_config.rtp_extensions, kExtensions[i].name); | 
|  | EXPECT_EQ(original_id, logged_id) | 
|  | << "IDs for " << kExtensions[i].name << " don't match. Original ID " | 
|  | << original_id.value_or(-1) << ". Parsed ID " << logged_id.value_or(-1) | 
|  | << "."; | 
|  | if (original_id) { | 
|  | recognized_extensions++; | 
|  | } | 
|  | } | 
|  | EXPECT_EQ(recognized_extensions, original_config.rtp_extensions.size()); | 
|  | } | 
|  |  | 
|  | void EventVerifier::VerifyLoggedAudioRecvConfig( | 
|  | const RtcEventAudioReceiveStreamConfig& original_event, | 
|  | const LoggedAudioRecvConfig& logged_event) const { | 
|  | EXPECT_EQ(original_event.timestamp_ms(), logged_event.log_time_ms()); | 
|  | VerifyLoggedStreamConfig(original_event.config(), logged_event.config); | 
|  | } | 
|  |  | 
|  | void EventVerifier::VerifyLoggedAudioSendConfig( | 
|  | const RtcEventAudioSendStreamConfig& original_event, | 
|  | const LoggedAudioSendConfig& logged_event) const { | 
|  | EXPECT_EQ(original_event.timestamp_ms(), logged_event.log_time_ms()); | 
|  | VerifyLoggedStreamConfig(original_event.config(), logged_event.config); | 
|  | } | 
|  |  | 
|  | void EventVerifier::VerifyLoggedVideoRecvConfig( | 
|  | const RtcEventVideoReceiveStreamConfig& original_event, | 
|  | const LoggedVideoRecvConfig& logged_event) const { | 
|  | EXPECT_EQ(original_event.timestamp_ms(), logged_event.log_time_ms()); | 
|  | VerifyLoggedStreamConfig(original_event.config(), logged_event.config); | 
|  | } | 
|  |  | 
|  | void EventVerifier::VerifyLoggedVideoSendConfig( | 
|  | const RtcEventVideoSendStreamConfig& original_event, | 
|  | const LoggedVideoSendConfig& logged_event) const { | 
|  | EXPECT_EQ(original_event.timestamp_ms(), logged_event.log_time_ms()); | 
|  | VerifyLoggedStreamConfig(original_event.config(), logged_event.config); | 
|  | } | 
|  |  | 
|  | void EventVerifier::VerifyLoggedNetEqSetMinimumDelay( | 
|  | const RtcEventNetEqSetMinimumDelay& original_event, | 
|  | const LoggedNetEqSetMinimumDelayEvent& logged_event) const { | 
|  | EXPECT_EQ(original_event.timestamp_ms(), logged_event.timestamp.ms()); | 
|  | EXPECT_EQ(original_event.remote_ssrc(), logged_event.remote_ssrc); | 
|  | EXPECT_EQ(original_event.minimum_delay_ms(), logged_event.minimum_delay_ms); | 
|  | } | 
|  |  | 
|  | }  // namespace test | 
|  | }  // namespace webrtc |