|  | /* | 
|  | *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. | 
|  | * | 
|  | *  Use of this source code is governed by a BSD-style license | 
|  | *  that can be found in the LICENSE file in the root of the source | 
|  | *  tree. An additional intellectual property rights grant can be found | 
|  | *  in the file PATENTS.  All contributing project authors may | 
|  | *  be found in the AUTHORS file in the root of the source tree. | 
|  | */ | 
|  |  | 
|  | #include "logging/rtc_event_log/rtc_event_log_unittest_helper.h" | 
|  |  | 
|  | #include <string.h>  // memcmp | 
|  |  | 
|  | #include <limits> | 
|  | #include <memory> | 
|  | #include <numeric> | 
|  | #include <utility> | 
|  | #include <vector> | 
|  |  | 
|  | #include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor.h" | 
|  | #include "modules/remote_bitrate_estimator/include/bwe_defines.h" | 
|  | #include "modules/rtp_rtcp/include/rtp_cvo.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/checks.h" | 
|  |  | 
|  | namespace webrtc { | 
|  |  | 
|  | namespace test { | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | struct ExtensionPair { | 
|  | RTPExtensionType type; | 
|  | const char* name; | 
|  | }; | 
|  |  | 
|  | constexpr int kMaxCsrcs = 3; | 
|  |  | 
|  | // Maximum serialized size of a header extension, including 1 byte ID. | 
|  | constexpr int kMaxExtensionSizeBytes = 4; | 
|  | constexpr int kMaxNumExtensions = 5; | 
|  |  | 
|  | constexpr ExtensionPair kExtensions[kMaxNumExtensions] = { | 
|  | {RTPExtensionType::kRtpExtensionTransmissionTimeOffset, | 
|  | RtpExtension::kTimestampOffsetUri}, | 
|  | {RTPExtensionType::kRtpExtensionAbsoluteSendTime, | 
|  | RtpExtension::kAbsSendTimeUri}, | 
|  | {RTPExtensionType::kRtpExtensionTransportSequenceNumber, | 
|  | RtpExtension::kTransportSequenceNumberUri}, | 
|  | {RTPExtensionType::kRtpExtensionAudioLevel, RtpExtension::kAudioLevelUri}, | 
|  | {RTPExtensionType::kRtpExtensionVideoRotation, | 
|  | RtpExtension::kVideoRotationUri}}; | 
|  |  | 
|  | template <typename T> | 
|  | void ShuffleInPlace(Random* prng, rtc::ArrayView<T> array) { | 
|  | RTC_DCHECK_LE(array.size(), std::numeric_limits<uint32_t>::max()); | 
|  | for (uint32_t i = 0; i + 1 < array.size(); i++) { | 
|  | uint32_t other = prng->Rand(i, static_cast<uint32_t>(array.size() - 1)); | 
|  | std::swap(array[i], array[other]); | 
|  | } | 
|  | } | 
|  | }  // namespace | 
|  |  | 
|  | std::unique_ptr<RtcEventAlrState> EventGenerator::NewAlrState() { | 
|  | return absl::make_unique<RtcEventAlrState>(prng_.Rand<bool>()); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<RtcEventAudioPlayout> EventGenerator::NewAudioPlayout( | 
|  | uint32_t ssrc) { | 
|  | return absl::make_unique<RtcEventAudioPlayout>(ssrc); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<RtcEventAudioNetworkAdaptation> | 
|  | EventGenerator::NewAudioNetworkAdaptation() { | 
|  | std::unique_ptr<AudioEncoderRuntimeConfig> config = | 
|  | absl::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 absl::make_unique<RtcEventAudioNetworkAdaptation>(std::move(config)); | 
|  | } | 
|  |  | 
|  | 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 absl::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 absl::make_unique<RtcEventBweUpdateLossBased>( | 
|  | bitrate_bps, fraction_lost, total_packets); | 
|  | } | 
|  |  | 
|  | 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 absl::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 absl::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 absl::make_unique<RtcEventProbeResultSuccess>(id, bitrate_bps); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<RtcEventIceCandidatePairConfig> | 
|  | EventGenerator::NewIceCandidatePairConfig() { | 
|  | IceCandidateType local_candidate_type = static_cast<IceCandidateType>( | 
|  | prng_.Rand(static_cast<uint32_t>(IceCandidateType::kNumValues) - 1)); | 
|  | IceCandidateNetworkType local_network_type = | 
|  | static_cast<IceCandidateNetworkType>(prng_.Rand( | 
|  | static_cast<uint32_t>(IceCandidateNetworkType::kNumValues) - 1)); | 
|  | IceCandidatePairAddressFamily local_address_family = | 
|  | static_cast<IceCandidatePairAddressFamily>(prng_.Rand( | 
|  | static_cast<uint32_t>(IceCandidatePairAddressFamily::kNumValues) - | 
|  | 1)); | 
|  | IceCandidateType remote_candidate_type = static_cast<IceCandidateType>( | 
|  | prng_.Rand(static_cast<uint32_t>(IceCandidateType::kNumValues) - 1)); | 
|  | IceCandidatePairAddressFamily remote_address_family = | 
|  | static_cast<IceCandidatePairAddressFamily>(prng_.Rand( | 
|  | static_cast<uint32_t>(IceCandidatePairAddressFamily::kNumValues) - | 
|  | 1)); | 
|  | IceCandidatePairProtocol protocol_type = | 
|  | static_cast<IceCandidatePairProtocol>(prng_.Rand( | 
|  | static_cast<uint32_t>(IceCandidatePairProtocol::kNumValues) - 1)); | 
|  |  | 
|  | IceCandidatePairDescription desc; | 
|  | desc.local_candidate_type = local_candidate_type; | 
|  | desc.local_relay_protocol = protocol_type; | 
|  | desc.local_network_type = local_network_type; | 
|  | desc.local_address_family = local_address_family; | 
|  | desc.remote_candidate_type = remote_candidate_type; | 
|  | desc.remote_address_family = remote_address_family; | 
|  | desc.candidate_pair_protocol = protocol_type; | 
|  |  | 
|  | IceCandidatePairConfigType type = | 
|  | static_cast<IceCandidatePairConfigType>(prng_.Rand( | 
|  | static_cast<uint32_t>(IceCandidatePairConfigType::kNumValues) - 1)); | 
|  | uint32_t pair_id = prng_.Rand<uint32_t>(); | 
|  | return absl::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>(); | 
|  |  | 
|  | return absl::make_unique<RtcEventIceCandidatePair>(type, pair_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.SetPacketCount(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; | 
|  | } | 
|  |  | 
|  | std::unique_ptr<RtcEventRtcpPacketIncoming> | 
|  | EventGenerator::NewRtcpPacketIncoming() { | 
|  | // TODO(terelius): Test the other RTCP types too. | 
|  | switch (prng_.Rand(0, 1)) { | 
|  | case 0: { | 
|  | rtcp::SenderReport sender_report = NewSenderReport(); | 
|  | rtc::Buffer buffer = sender_report.Build(); | 
|  | return absl::make_unique<RtcEventRtcpPacketIncoming>(buffer); | 
|  | } | 
|  | case 1: { | 
|  | rtcp::ReceiverReport receiver_report = NewReceiverReport(); | 
|  | rtc::Buffer buffer = receiver_report.Build(); | 
|  | return absl::make_unique<RtcEventRtcpPacketIncoming>(buffer); | 
|  | } | 
|  | default: | 
|  | RTC_NOTREACHED(); | 
|  | rtc::Buffer buffer; | 
|  | return absl::make_unique<RtcEventRtcpPacketIncoming>(buffer); | 
|  | } | 
|  | } | 
|  |  | 
|  | std::unique_ptr<RtcEventRtcpPacketOutgoing> | 
|  | EventGenerator::NewRtcpPacketOutgoing() { | 
|  | // TODO(terelius): Test the other RTCP types too. | 
|  | switch (prng_.Rand(0, 1)) { | 
|  | case 0: { | 
|  | rtcp::SenderReport sender_report = NewSenderReport(); | 
|  | rtc::Buffer buffer = sender_report.Build(); | 
|  | return absl::make_unique<RtcEventRtcpPacketOutgoing>(buffer); | 
|  | } | 
|  | case 1: { | 
|  | rtcp::ReceiverReport receiver_report = NewReceiverReport(); | 
|  | rtc::Buffer buffer = receiver_report.Build(); | 
|  | return absl::make_unique<RtcEventRtcpPacketOutgoing>(buffer); | 
|  | } | 
|  | default: | 
|  | RTC_NOTREACHED(); | 
|  | rtc::Buffer buffer; | 
|  | return absl::make_unique<RtcEventRtcpPacketOutgoing>(buffer); | 
|  | } | 
|  | } | 
|  |  | 
|  | void EventGenerator::RandomizeRtpPacket( | 
|  | size_t packet_size, | 
|  | uint32_t ssrc, | 
|  | const RtpHeaderExtensionMap& extension_map, | 
|  | RtpPacket* rtp_packet) { | 
|  | 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)) | 
|  | rtp_packet->SetExtension<TransmissionOffset>(prng_.Rand(0x00ffffff)); | 
|  | if (extension_map.IsRegistered(AudioLevel::kId)) | 
|  | rtp_packet->SetExtension<AudioLevel>(prng_.Rand<bool>(), prng_.Rand(127)); | 
|  | if (extension_map.IsRegistered(AbsoluteSendTime::kId)) | 
|  | rtp_packet->SetExtension<AbsoluteSendTime>(prng_.Rand(0x00ffffff)); | 
|  | if (extension_map.IsRegistered(VideoOrientation::kId)) | 
|  | rtp_packet->SetExtension<VideoOrientation>(prng_.Rand(3)); | 
|  | if (extension_map.IsRegistered(TransportSequenceNumber::kId)) | 
|  | rtp_packet->SetExtension<TransportSequenceNumber>(prng_.Rand<uint16_t>()); | 
|  |  | 
|  | RTC_DCHECK_GE(packet_size, rtp_packet->headers_size()); | 
|  | size_t payload_size = packet_size - rtp_packet->headers_size(); | 
|  | 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>(); | 
|  | } | 
|  | } | 
|  |  | 
|  | std::unique_ptr<RtcEventRtpPacketIncoming> EventGenerator::NewRtpPacketIncoming( | 
|  | uint32_t ssrc, | 
|  | const RtpHeaderExtensionMap& extension_map) { | 
|  | // 12 bytes RTP header, 4 bytes for 0xBEDE + alignment, 4 bytes per CSRC. | 
|  | constexpr size_t kMaxHeaderSize = | 
|  | 16 + 4 * kMaxCsrcs + kMaxExtensionSizeBytes * kMaxNumExtensions; | 
|  | size_t packet_size = | 
|  | prng_.Rand(kMaxHeaderSize, static_cast<uint32_t>(IP_PACKET_SIZE - 1)); | 
|  |  | 
|  | RtpPacketReceived rtp_packet(&extension_map); | 
|  | RandomizeRtpPacket(packet_size, ssrc, extension_map, &rtp_packet); | 
|  |  | 
|  | return absl::make_unique<RtcEventRtpPacketIncoming>(rtp_packet); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<RtcEventRtpPacketOutgoing> EventGenerator::NewRtpPacketOutgoing( | 
|  | uint32_t ssrc, | 
|  | const RtpHeaderExtensionMap& extension_map) { | 
|  | // 12 bytes RTP header, 4 bytes for 0xBEDE + alignment, 4 bytes per CSRC. | 
|  | constexpr size_t kMaxHeaderSize = | 
|  | 16 + 4 * kMaxCsrcs + kMaxExtensionSizeBytes * kMaxNumExtensions; | 
|  | size_t packet_size = | 
|  | prng_.Rand(kMaxHeaderSize, static_cast<uint32_t>(IP_PACKET_SIZE - 1)); | 
|  |  | 
|  | RtpPacketToSend rtp_packet(&extension_map, packet_size); | 
|  | RandomizeRtpPacket(packet_size, ssrc, extension_map, &rtp_packet); | 
|  |  | 
|  | int probe_cluster_id = prng_.Rand(0, 100000); | 
|  | return absl::make_unique<RtcEventRtpPacketOutgoing>(rtp_packet, | 
|  | probe_cluster_id); | 
|  | } | 
|  |  | 
|  | RtpHeaderExtensionMap EventGenerator::NewRtpHeaderExtensionMap() { | 
|  | RtpHeaderExtensionMap extension_map; | 
|  | std::vector<int> id(RtpExtension::kMaxId - RtpExtension::kMinId + 1); | 
|  | std::iota(id.begin(), id.end(), RtpExtension::kMinId); | 
|  | ShuffleInPlace(&prng_, rtc::ArrayView<int>(id)); | 
|  |  | 
|  | if (prng_.Rand<bool>()) { | 
|  | extension_map.Register<AudioLevel>(id[0]); | 
|  | } | 
|  | if (prng_.Rand<bool>()) { | 
|  | extension_map.Register<TransmissionOffset>(id[1]); | 
|  | } | 
|  | if (prng_.Rand<bool>()) { | 
|  | extension_map.Register<AbsoluteSendTime>(id[2]); | 
|  | } | 
|  | if (prng_.Rand<bool>()) { | 
|  | extension_map.Register<VideoOrientation>(id[3]); | 
|  | } | 
|  | if (prng_.Rand<bool>()) { | 
|  | extension_map.Register<TransportSequenceNumber>(id[4]); | 
|  | } | 
|  |  | 
|  | return extension_map; | 
|  | } | 
|  |  | 
|  | std::unique_ptr<RtcEventAudioReceiveStreamConfig> | 
|  | EventGenerator::NewAudioReceiveStreamConfig( | 
|  | uint32_t ssrc, | 
|  | const RtpHeaderExtensionMap& extensions) { | 
|  | auto config = absl::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 absl::make_unique<RtcEventAudioReceiveStreamConfig>(std::move(config)); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<RtcEventAudioSendStreamConfig> | 
|  | EventGenerator::NewAudioSendStreamConfig( | 
|  | uint32_t ssrc, | 
|  | const RtpHeaderExtensionMap& extensions) { | 
|  | auto config = absl::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 absl::make_unique<RtcEventAudioSendStreamConfig>(std::move(config)); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<RtcEventVideoReceiveStreamConfig> | 
|  | EventGenerator::NewVideoReceiveStreamConfig( | 
|  | uint32_t ssrc, | 
|  | const RtpHeaderExtensionMap& extensions) { | 
|  | auto config = absl::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 absl::make_unique<RtcEventVideoReceiveStreamConfig>(std::move(config)); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<RtcEventVideoSendStreamConfig> | 
|  | EventGenerator::NewVideoSendStreamConfig( | 
|  | uint32_t ssrc, | 
|  | const RtpHeaderExtensionMap& extensions) { | 
|  | auto config = absl::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 absl::make_unique<RtcEventVideoSendStreamConfig>(std::move(config)); | 
|  | } | 
|  |  | 
|  | bool VerifyLoggedAlrStateEvent(const RtcEventAlrState& original_event, | 
|  | const LoggedAlrStateEvent& logged_event) { | 
|  | if (original_event.timestamp_us_ != logged_event.log_time_us()) | 
|  | return false; | 
|  | if (original_event.in_alr_ != logged_event.in_alr) | 
|  | return false; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool VerifyLoggedAudioPlayoutEvent( | 
|  | const RtcEventAudioPlayout& original_event, | 
|  | const LoggedAudioPlayoutEvent& logged_event) { | 
|  | if (original_event.timestamp_us_ != logged_event.log_time_us()) | 
|  | return false; | 
|  | if (original_event.ssrc_ != logged_event.ssrc) | 
|  | return false; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool VerifyLoggedAudioNetworkAdaptationEvent( | 
|  | const RtcEventAudioNetworkAdaptation& original_event, | 
|  | const LoggedAudioNetworkAdaptationEvent& logged_event) { | 
|  | if (original_event.timestamp_us_ != logged_event.log_time_us()) | 
|  | return false; | 
|  |  | 
|  | if (original_event.config_->bitrate_bps != logged_event.config.bitrate_bps) | 
|  | return false; | 
|  | if (original_event.config_->enable_dtx != logged_event.config.enable_dtx) | 
|  | return false; | 
|  | if (original_event.config_->enable_fec != logged_event.config.enable_fec) | 
|  | return false; | 
|  | if (original_event.config_->frame_length_ms != | 
|  | logged_event.config.frame_length_ms) | 
|  | return false; | 
|  | if (original_event.config_->num_channels != logged_event.config.num_channels) | 
|  | return false; | 
|  | if (original_event.config_->uplink_packet_loss_fraction != | 
|  | logged_event.config.uplink_packet_loss_fraction) | 
|  | return false; | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool VerifyLoggedBweDelayBasedUpdate( | 
|  | const RtcEventBweUpdateDelayBased& original_event, | 
|  | const LoggedBweDelayBasedUpdate& logged_event) { | 
|  | if (original_event.timestamp_us_ != logged_event.log_time_us()) | 
|  | return false; | 
|  | if (original_event.bitrate_bps_ != logged_event.bitrate_bps) | 
|  | return false; | 
|  | if (original_event.detector_state_ != logged_event.detector_state) | 
|  | return false; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool VerifyLoggedBweLossBasedUpdate( | 
|  | const RtcEventBweUpdateLossBased& original_event, | 
|  | const LoggedBweLossBasedUpdate& logged_event) { | 
|  | if (original_event.timestamp_us_ != logged_event.log_time_us()) | 
|  | return false; | 
|  | if (original_event.bitrate_bps_ != logged_event.bitrate_bps) | 
|  | return false; | 
|  | if (original_event.fraction_loss_ != logged_event.fraction_lost) | 
|  | return false; | 
|  | if (original_event.total_packets_ != logged_event.expected_packets) | 
|  | return false; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool VerifyLoggedBweProbeClusterCreatedEvent( | 
|  | const RtcEventProbeClusterCreated& original_event, | 
|  | const LoggedBweProbeClusterCreatedEvent& logged_event) { | 
|  | if (original_event.timestamp_us_ != logged_event.log_time_us()) | 
|  | return false; | 
|  | if (original_event.id_ != logged_event.id) | 
|  | return false; | 
|  | if (original_event.bitrate_bps_ != logged_event.bitrate_bps) | 
|  | return false; | 
|  | if (original_event.min_probes_ != logged_event.min_packets) | 
|  | return false; | 
|  | if (original_event.min_bytes_ != logged_event.min_bytes) | 
|  | return false; | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool VerifyLoggedBweProbeFailureEvent( | 
|  | const RtcEventProbeResultFailure& original_event, | 
|  | const LoggedBweProbeFailureEvent& logged_event) { | 
|  | if (original_event.timestamp_us_ != logged_event.log_time_us()) | 
|  | return false; | 
|  | if (original_event.id_ != logged_event.id) | 
|  | return false; | 
|  | if (original_event.failure_reason_ != logged_event.failure_reason) | 
|  | return false; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool VerifyLoggedBweProbeSuccessEvent( | 
|  | const RtcEventProbeResultSuccess& original_event, | 
|  | const LoggedBweProbeSuccessEvent& logged_event) { | 
|  | if (original_event.timestamp_us_ != logged_event.log_time_us()) | 
|  | return false; | 
|  | if (original_event.id_ != logged_event.id) | 
|  | return false; | 
|  | if (original_event.bitrate_bps_ != logged_event.bitrate_bps) | 
|  | return false; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool VerifyLoggedIceCandidatePairConfig( | 
|  | const RtcEventIceCandidatePairConfig& original_event, | 
|  | const LoggedIceCandidatePairConfig& logged_event) { | 
|  | if (original_event.timestamp_us_ != logged_event.log_time_us()) | 
|  | return false; | 
|  |  | 
|  | if (original_event.type_ != logged_event.type) | 
|  | return false; | 
|  | if (original_event.candidate_pair_id_ != logged_event.candidate_pair_id) | 
|  | return false; | 
|  | if (original_event.candidate_pair_desc_.local_candidate_type != | 
|  | logged_event.local_candidate_type) | 
|  | return false; | 
|  | if (original_event.candidate_pair_desc_.local_relay_protocol != | 
|  | logged_event.local_relay_protocol) | 
|  | return false; | 
|  | if (original_event.candidate_pair_desc_.local_network_type != | 
|  | logged_event.local_network_type) | 
|  | return false; | 
|  | if (original_event.candidate_pair_desc_.local_address_family != | 
|  | logged_event.local_address_family) | 
|  | return false; | 
|  | if (original_event.candidate_pair_desc_.remote_candidate_type != | 
|  | logged_event.remote_candidate_type) | 
|  | return false; | 
|  | if (original_event.candidate_pair_desc_.remote_address_family != | 
|  | logged_event.remote_address_family) | 
|  | return false; | 
|  | if (original_event.candidate_pair_desc_.candidate_pair_protocol != | 
|  | logged_event.candidate_pair_protocol) | 
|  | return false; | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool VerifyLoggedIceCandidatePairEvent( | 
|  | const RtcEventIceCandidatePair& original_event, | 
|  | const LoggedIceCandidatePairEvent& logged_event) { | 
|  | if (original_event.timestamp_us_ != logged_event.log_time_us()) | 
|  | return false; | 
|  |  | 
|  | if (original_event.type_ != logged_event.type) | 
|  | return false; | 
|  | if (original_event.candidate_pair_id_ != logged_event.candidate_pair_id) | 
|  | return false; | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool VerifyLoggedRtpHeader(const RtpPacket& original_header, | 
|  | const RTPHeader& logged_header) { | 
|  | // Standard RTP header. | 
|  | if (original_header.Marker() != logged_header.markerBit) | 
|  | return false; | 
|  | if (original_header.PayloadType() != logged_header.payloadType) | 
|  | return false; | 
|  | if (original_header.SequenceNumber() != logged_header.sequenceNumber) | 
|  | return false; | 
|  | if (original_header.Timestamp() != logged_header.timestamp) | 
|  | return false; | 
|  | if (original_header.Ssrc() != logged_header.ssrc) | 
|  | return false; | 
|  | if (original_header.Csrcs().size() != logged_header.numCSRCs) | 
|  | return false; | 
|  | for (size_t i = 0; i < logged_header.numCSRCs; i++) { | 
|  | if (original_header.Csrcs()[i] != logged_header.arrOfCSRCs[i]) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | if (original_header.padding_size() != logged_header.paddingLength) | 
|  | return false; | 
|  | if (original_header.headers_size() != logged_header.headerLength) | 
|  | return false; | 
|  |  | 
|  | // TransmissionOffset header extension. | 
|  | if (original_header.HasExtension<TransmissionOffset>() != | 
|  | logged_header.extension.hasTransmissionTimeOffset) | 
|  | return false; | 
|  | if (logged_header.extension.hasTransmissionTimeOffset) { | 
|  | int32_t offset; | 
|  | original_header.GetExtension<TransmissionOffset>(&offset); | 
|  | if (offset != logged_header.extension.transmissionTimeOffset) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // AbsoluteSendTime header extension. | 
|  | if (original_header.HasExtension<AbsoluteSendTime>() != | 
|  | logged_header.extension.hasAbsoluteSendTime) | 
|  | return false; | 
|  | if (logged_header.extension.hasAbsoluteSendTime) { | 
|  | uint32_t sendtime; | 
|  | original_header.GetExtension<AbsoluteSendTime>(&sendtime); | 
|  | if (sendtime != logged_header.extension.absoluteSendTime) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // TransportSequenceNumber header extension. | 
|  | if (original_header.HasExtension<TransportSequenceNumber>() != | 
|  | logged_header.extension.hasTransportSequenceNumber) | 
|  | return false; | 
|  | if (logged_header.extension.hasTransportSequenceNumber) { | 
|  | uint16_t seqnum; | 
|  | original_header.GetExtension<TransportSequenceNumber>(&seqnum); | 
|  | if (seqnum != logged_header.extension.transportSequenceNumber) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // AudioLevel header extension. | 
|  | if (original_header.HasExtension<AudioLevel>() != | 
|  | logged_header.extension.hasAudioLevel) | 
|  | return false; | 
|  | if (logged_header.extension.hasAudioLevel) { | 
|  | bool voice_activity; | 
|  | uint8_t audio_level; | 
|  | original_header.GetExtension<AudioLevel>(&voice_activity, &audio_level); | 
|  | if (voice_activity != logged_header.extension.voiceActivity) | 
|  | return false; | 
|  | if (audio_level != logged_header.extension.audioLevel) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // VideoOrientation header extension. | 
|  | if (original_header.HasExtension<VideoOrientation>() != | 
|  | logged_header.extension.hasVideoRotation) | 
|  | return false; | 
|  | if (logged_header.extension.hasVideoRotation) { | 
|  | uint8_t rotation; | 
|  | original_header.GetExtension<VideoOrientation>(&rotation); | 
|  | if (ConvertCVOByteToVideoRotation(rotation) != | 
|  | logged_header.extension.videoRotation) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool VerifyLoggedRtpPacketIncoming( | 
|  | const RtcEventRtpPacketIncoming& original_event, | 
|  | const LoggedRtpPacketIncoming& logged_event) { | 
|  | if (original_event.timestamp_us_ != logged_event.log_time_us()) | 
|  | return false; | 
|  |  | 
|  | if (original_event.header_.headers_size() != logged_event.rtp.header_length) | 
|  | return false; | 
|  |  | 
|  | if (original_event.packet_length_ != logged_event.rtp.total_length) | 
|  | return false; | 
|  |  | 
|  | if (!VerifyLoggedRtpHeader(original_event.header_, logged_event.rtp.header)) | 
|  | return false; | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool VerifyLoggedRtpPacketOutgoing( | 
|  | const RtcEventRtpPacketOutgoing& original_event, | 
|  | const LoggedRtpPacketOutgoing& logged_event) { | 
|  | if (original_event.timestamp_us_ != logged_event.log_time_us()) | 
|  | return false; | 
|  |  | 
|  | if (original_event.header_.headers_size() != logged_event.rtp.header_length) | 
|  | return false; | 
|  |  | 
|  | if (original_event.packet_length_ != logged_event.rtp.total_length) | 
|  | return false; | 
|  |  | 
|  | // TODO(terelius): Probe cluster ID isn't parsed, used or tested. Unless | 
|  | // someone has a strong reason to keep it, it'll be removed. | 
|  |  | 
|  | if (!VerifyLoggedRtpHeader(original_event.header_, logged_event.rtp.header)) | 
|  | return false; | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool VerifyLoggedRtcpPacketIncoming( | 
|  | const RtcEventRtcpPacketIncoming& original_event, | 
|  | const LoggedRtcpPacketIncoming& logged_event) { | 
|  | if (original_event.timestamp_us_ != logged_event.log_time_us()) | 
|  | return false; | 
|  |  | 
|  | if (original_event.packet_.size() != logged_event.rtcp.raw_data.size()) | 
|  | return false; | 
|  | if (memcmp(original_event.packet_.data(), logged_event.rtcp.raw_data.data(), | 
|  | original_event.packet_.size()) != 0) { | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool VerifyLoggedRtcpPacketOutgoing( | 
|  | const RtcEventRtcpPacketOutgoing& original_event, | 
|  | const LoggedRtcpPacketOutgoing& logged_event) { | 
|  | if (original_event.timestamp_us_ != logged_event.log_time_us()) | 
|  | return false; | 
|  |  | 
|  | if (original_event.packet_.size() != logged_event.rtcp.raw_data.size()) | 
|  | return false; | 
|  | if (memcmp(original_event.packet_.data(), logged_event.rtcp.raw_data.data(), | 
|  | original_event.packet_.size()) != 0) { | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool VerifyLoggedStartEvent(int64_t start_time_us, | 
|  | const LoggedStartEvent& logged_event) { | 
|  | if (start_time_us != logged_event.log_time_us()) | 
|  | return false; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool VerifyLoggedStopEvent(int64_t stop_time_us, | 
|  | const LoggedStopEvent& logged_event) { | 
|  | if (stop_time_us != logged_event.log_time_us()) | 
|  | return false; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool VerifyLoggedAudioRecvConfig( | 
|  | const RtcEventAudioReceiveStreamConfig& original_event, | 
|  | const LoggedAudioRecvConfig& logged_event) { | 
|  | if (original_event.timestamp_us_ != logged_event.log_time_us()) | 
|  | return false; | 
|  | if (*original_event.config_ != logged_event.config) | 
|  | return false; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool VerifyLoggedAudioSendConfig( | 
|  | const RtcEventAudioSendStreamConfig& original_event, | 
|  | const LoggedAudioSendConfig& logged_event) { | 
|  | if (original_event.timestamp_us_ != logged_event.log_time_us()) | 
|  | return false; | 
|  | if (*original_event.config_ != logged_event.config) | 
|  | return false; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool VerifyLoggedVideoRecvConfig( | 
|  | const RtcEventVideoReceiveStreamConfig& original_event, | 
|  | const LoggedVideoRecvConfig& logged_event) { | 
|  | if (original_event.timestamp_us_ != logged_event.log_time_us()) | 
|  | return false; | 
|  | if (*original_event.config_ != logged_event.config) | 
|  | return false; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool VerifyLoggedVideoSendConfig( | 
|  | const RtcEventVideoSendStreamConfig& original_event, | 
|  | const LoggedVideoSendConfig& logged_event) { | 
|  | if (original_event.timestamp_us_ != logged_event.log_time_us()) | 
|  | return false; | 
|  | // TODO(terelius): In the past, we allowed storing multiple RtcStreamConfigs | 
|  | // in the same RtcEventVideoSendStreamConfig. Look into whether we should drop | 
|  | // backwards compatibility in the parser. | 
|  | if (logged_event.configs.size() != 1) | 
|  | return false; | 
|  | if (*original_event.config_ != logged_event.configs[0]) | 
|  | return false; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | }  // namespace test | 
|  | }  // namespace webrtc |