diff --git a/api/rtc_event_log/rtc_event.h b/api/rtc_event_log/rtc_event.h index 0bc11ce698..aa74944fe5 100644 --- a/api/rtc_event_log/rtc_event.h +++ b/api/rtc_event_log/rtc_event.h @@ -54,6 +54,7 @@ class RtcEvent { GenericPacketReceived, GenericAckReceived, FrameDecoded, + NetEqSetMinimumDelay, BeginV3Log = 0x2501580, EndV3Log = 0x2501581, FakeEvent, // For unit testing. diff --git a/audio/channel_receive.cc b/audio/channel_receive.cc index f884e39aa7..b95d98c20c 100644 --- a/audio/channel_receive.cc +++ b/audio/channel_receive.cc @@ -29,6 +29,7 @@ #include "audio/channel_send.h" #include "audio/utility/audio_frame_operations.h" #include "logging/rtc_event_log/events/rtc_event_audio_playout.h" +#include "logging/rtc_event_log/events/rtc_event_neteq_set_minimum_delay.h" #include "modules/audio_coding/acm2/acm_receiver.h" #include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor_config.h" #include "modules/audio_device/include/audio_device.h" @@ -1017,6 +1018,8 @@ ChannelReceive::GetCurrentEstimatedPlayoutNtpTimestampMs(int64_t now_ms) const { } bool ChannelReceive::SetBaseMinimumPlayoutDelayMs(int delay_ms) { + event_log_->Log( + std::make_unique(remote_ssrc_, delay_ms)); return acm_receiver_.SetBaseMinimumDelayMs(delay_ms); } diff --git a/logging/BUILD.gn b/logging/BUILD.gn index 3c3c825ec3..8a7f191454 100644 --- a/logging/BUILD.gn +++ b/logging/BUILD.gn @@ -101,6 +101,8 @@ rtc_library("rtc_event_audio") { "rtc_event_log/events/rtc_event_audio_receive_stream_config.h", "rtc_event_log/events/rtc_event_audio_send_stream_config.cc", "rtc_event_log/events/rtc_event_audio_send_stream_config.h", + "rtc_event_log/events/rtc_event_neteq_set_minimum_delay.cc", + "rtc_event_log/events/rtc_event_neteq_set_minimum_delay.h", ] deps = [ @@ -306,6 +308,7 @@ rtc_library("rtc_event_log_impl_encoder") { "../rtc_base:ignore_wundef", "../rtc_base:logging", "../rtc_base:safe_conversions", + "../system_wrappers:field_trial", ] absl_deps = [ "//third_party/abseil-cpp/absl/memory", diff --git a/logging/rtc_event_log/encoder/rtc_event_log_encoder_legacy.cc b/logging/rtc_event_log/encoder/rtc_event_log_encoder_legacy.cc index 7e137a50cf..5619827246 100644 --- a/logging/rtc_event_log/encoder/rtc_event_log_encoder_legacy.cc +++ b/logging/rtc_event_log/encoder/rtc_event_log_encoder_legacy.cc @@ -383,6 +383,7 @@ std::string RtcEventLogEncoderLegacy::Encode(const RtcEvent& event) { case RtcEvent::Type::GenericPacketSent: case RtcEvent::Type::GenericAckReceived: case RtcEvent::Type::FrameDecoded: + case RtcEvent::Type::NetEqSetMinimumDelay: // These are unsupported in the old format, but shouldn't crash. return ""; } diff --git a/logging/rtc_event_log/encoder/rtc_event_log_encoder_new_format.cc b/logging/rtc_event_log/encoder/rtc_event_log_encoder_new_format.cc index 4a0b7584f0..2e02f68213 100644 --- a/logging/rtc_event_log/encoder/rtc_event_log_encoder_new_format.cc +++ b/logging/rtc_event_log/encoder/rtc_event_log_encoder_new_format.cc @@ -31,6 +31,7 @@ #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" @@ -60,6 +61,7 @@ #include "rtc_base/checks.h" #include "rtc_base/ignore_wundef.h" #include "rtc_base/logging.h" +#include "system_wrappers/include/field_trial.h" // *.pb.h files are generated at build-time by the protobuf compiler. RTC_PUSH_IGNORING_WUNDEF() @@ -652,6 +654,14 @@ void EncodeRtpPacket(const std::vector& batch, } } // namespace +RtcEventLogEncoderNewFormat::RtcEventLogEncoderNewFormat() { + encode_neteq_set_minimum_delay_kill_switch_ = false; + if (webrtc::field_trial::IsEnabled( + "WebRTC-RtcEventLogEncodeNetEqSetMinimumDelayKillSwitch")) { + encode_neteq_set_minimum_delay_kill_switch_ = true; + } +} + std::string RtcEventLogEncoderNewFormat::EncodeLogStart(int64_t timestamp_us, int64_t utc_time_us) { rtclog2::EventStream event_stream; @@ -680,6 +690,8 @@ std::string RtcEventLogEncoderNewFormat::EncodeBatch( std::vector audio_network_adaptation_events; std::vector audio_playout_events; + std::vector + neteq_set_minimum_delay_events; std::vector audio_recv_stream_configs; std::vector audio_send_stream_configs; @@ -877,6 +889,12 @@ std::string RtcEventLogEncoderNewFormat::EncodeBatch( frames_decoded[rtc_event->ssrc()].emplace_back(rtc_event); break; } + case RtcEvent::Type::NetEqSetMinimumDelay: { + auto* rtc_event = + static_cast(it->get()); + neteq_set_minimum_delay_events.push_back(rtc_event); + break; + } case RtcEvent::Type::BeginV3Log: case RtcEvent::Type::EndV3Log: // These special events are written as part of starting @@ -896,6 +914,7 @@ std::string RtcEventLogEncoderNewFormat::EncodeBatch( EncodeAudioPlayout(audio_playout_events, &event_stream); EncodeAudioRecvStreamConfig(audio_recv_stream_configs, &event_stream); EncodeAudioSendStreamConfig(audio_send_stream_configs, &event_stream); + EncodeNetEqSetMinimumDelay(neteq_set_minimum_delay_events, &event_stream); EncodeBweUpdateDelayBased(bwe_delay_based_updates, &event_stream); EncodeBweUpdateLossBased(bwe_loss_based_updates, &event_stream); EncodeDtlsTransportState(dtls_transport_states, &event_stream); @@ -1129,6 +1148,64 @@ void RtcEventLogEncoderNewFormat::EncodeAudioPlayout( } } +void RtcEventLogEncoderNewFormat::EncodeNetEqSetMinimumDelay( + rtc::ArrayView batch, + rtclog2::EventStream* event_stream) { + if (encode_neteq_set_minimum_delay_kill_switch_) { + return; + } + if (batch.empty()) { + return; + } + + const RtcEventNetEqSetMinimumDelay* base_event = batch[0]; + + rtclog2::NetEqSetMinimumDelay* proto_batch = + event_stream->add_neteq_set_minimum_delay(); + proto_batch->set_timestamp_ms(base_event->timestamp_ms()); + proto_batch->set_remote_ssrc(base_event->remote_ssrc()); + proto_batch->set_minimum_delay_ms(base_event->minimum_delay_ms()); + + if (batch.size() == 1) + return; + + // Delta encoding + proto_batch->set_number_of_deltas(batch.size() - 1); + std::vector> values(batch.size() - 1); + std::string encoded_deltas; + + // timestamp_ms + for (size_t i = 0; i < values.size(); ++i) { + const RtcEventNetEqSetMinimumDelay* event = batch[i + 1]; + values[i] = ToUnsigned(event->timestamp_ms()); + } + encoded_deltas = EncodeDeltas(ToUnsigned(base_event->timestamp_ms()), values); + if (!encoded_deltas.empty()) { + proto_batch->set_timestamp_ms_deltas(encoded_deltas); + } + + // remote_ssrc + for (size_t i = 0; i < values.size(); ++i) { + const RtcEventNetEqSetMinimumDelay* event = batch[i + 1]; + values[i] = event->remote_ssrc(); + } + encoded_deltas = EncodeDeltas(base_event->remote_ssrc(), values); + if (!encoded_deltas.empty()) { + proto_batch->set_remote_ssrc_deltas(encoded_deltas); + } + + // minimum_delay_ms + for (size_t i = 0; i < values.size(); ++i) { + const RtcEventNetEqSetMinimumDelay* event = batch[i + 1]; + values[i] = ToUnsigned(event->minimum_delay_ms()); + } + encoded_deltas = + EncodeDeltas(ToUnsigned(base_event->minimum_delay_ms()), values); + if (!encoded_deltas.empty()) { + proto_batch->set_minimum_delay_ms_deltas(encoded_deltas); + } +} + void RtcEventLogEncoderNewFormat::EncodeAudioRecvStreamConfig( rtc::ArrayView batch, rtclog2::EventStream* event_stream) { diff --git a/logging/rtc_event_log/encoder/rtc_event_log_encoder_new_format.h b/logging/rtc_event_log/encoder/rtc_event_log_encoder_new_format.h index 6af34bc6cd..6747f41f07 100644 --- a/logging/rtc_event_log/encoder/rtc_event_log_encoder_new_format.h +++ b/logging/rtc_event_log/encoder/rtc_event_log_encoder_new_format.h @@ -39,6 +39,7 @@ class RtcEventDtlsTransportState; class RtcEventDtlsWritableState; class RtcEventLoggingStarted; class RtcEventLoggingStopped; +class RtcEventNetEqSetMinimumDelay; class RtcEventProbeClusterCreated; class RtcEventProbeResultFailure; class RtcEventProbeResultSuccess; @@ -58,6 +59,7 @@ class RtcEventGenericPacketSent; class RtcEventLogEncoderNewFormat final : public RtcEventLogEncoder { public: + RtcEventLogEncoderNewFormat(); ~RtcEventLogEncoderNewFormat() override = default; std::string EncodeBatch( @@ -69,6 +71,8 @@ class RtcEventLogEncoderNewFormat final : public RtcEventLogEncoder { std::string EncodeLogEnd(int64_t timestamp_us) override; private: + bool encode_neteq_set_minimum_delay_kill_switch_ = false; + // Encoding entry-point for the various RtcEvent subclasses. void EncodeAlrState(rtc::ArrayView batch, rtclog2::EventStream* event_stream); @@ -117,6 +121,9 @@ class RtcEventLogEncoderNewFormat final : public RtcEventLogEncoder { rtclog2::EventStream* event_stream); void EncodeLoggingStopped(rtc::ArrayView batch, rtclog2::EventStream* event_stream); + void EncodeNetEqSetMinimumDelay( + rtc::ArrayView batch, + rtclog2::EventStream* event_stream); void EncodeProbeClusterCreated( rtc::ArrayView batch, rtclog2::EventStream* event_stream); diff --git a/logging/rtc_event_log/encoder/rtc_event_log_encoder_unittest.cc b/logging/rtc_event_log/encoder/rtc_event_log_encoder_unittest.cc index c910003e29..7039fe7eb6 100644 --- a/logging/rtc_event_log/encoder/rtc_event_log_encoder_unittest.cc +++ b/logging/rtc_event_log/encoder/rtc_event_log_encoder_unittest.cc @@ -441,6 +441,64 @@ TEST_P(RtcEventLogEncoderTest, RtcEventAudioPlayout) { } } +TEST_P(RtcEventLogEncoderTest, RtcEventNetEqSetMinimumDelayDecoded) { + // SSRCs will be randomly assigned out of this small pool, significant only + // in that it also covers such edge cases as SSRC = 0 and SSRC = 0xffffffff. + // The pool is intentionally small, so as to produce collisions. + const std::vector kSsrcPool = {0x00000000, 0x12345678, 0xabcdef01, + 0xffffffff, 0x20171024, 0x19840730, + 0x19831230}; + std::map>> + original_events_by_ssrc; + for (size_t i = 0; i < event_count_; ++i) { + const uint32_t ssrc = kSsrcPool[prng_.Rand(kSsrcPool.size() - 1)]; + std::unique_ptr event = + (original_events_by_ssrc[ssrc].empty() || !force_repeated_fields_) + ? gen_.NewNetEqSetMinimumDelay(ssrc) + : original_events_by_ssrc[ssrc][0]->Copy(); + history_.push_back(event->Copy()); + original_events_by_ssrc[ssrc].push_back(std::move(event)); + } + + encoded_ += encoder_->EncodeBatch(history_.begin(), history_.end()); + ASSERT_TRUE(parsed_log_.ParseString(encoded_).ok()); + + const auto& parsed_neteq_set_minimum_delay_events_by_ssrc = + parsed_log_.neteq_set_minimum_delay_events(); + + if (encoding_type_ == RtcEventLog::EncodingType::Legacy) { + ASSERT_EQ(parsed_neteq_set_minimum_delay_events_by_ssrc.size(), 0u); + return; + } + + // Same number of distinct SSRCs. + ASSERT_EQ(parsed_neteq_set_minimum_delay_events_by_ssrc.size(), + original_events_by_ssrc.size()); + + for (auto& original_event_it : original_events_by_ssrc) { + const uint32_t ssrc = original_event_it.first; + const auto& original_neteq_set_minimum_delay_events = + original_event_it.second; + + const auto& parsed_event_it = + parsed_neteq_set_minimum_delay_events_by_ssrc.find(ssrc); + ASSERT_TRUE(parsed_event_it != + parsed_neteq_set_minimum_delay_events_by_ssrc.end()); + const auto& parsed_neteq_set_minimum_delay_events = parsed_event_it->second; + + // Same number playout events for the SSRC under examination. + ASSERT_EQ(original_neteq_set_minimum_delay_events.size(), + parsed_neteq_set_minimum_delay_events.size()); + + for (size_t i = 0; i < original_neteq_set_minimum_delay_events.size(); + ++i) { + verifier_.VerifyLoggedNetEqSetMinimumDelay( + *original_neteq_set_minimum_delay_events[i], + parsed_neteq_set_minimum_delay_events[i]); + } + } +} + // TODO(eladalon/terelius): Test with multiple events in the batch. TEST_P(RtcEventLogEncoderTest, RtcEventAudioReceiveStreamConfig) { uint32_t ssrc = prng_.Rand(); diff --git a/logging/rtc_event_log/events/rtc_event_neteq_set_minimum_delay.cc b/logging/rtc_event_log/events/rtc_event_neteq_set_minimum_delay.cc new file mode 100644 index 0000000000..7b958c181b --- /dev/null +++ b/logging/rtc_event_log/events/rtc_event_neteq_set_minimum_delay.cc @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2022 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "logging/rtc_event_log/events/rtc_event_neteq_set_minimum_delay.h" + +#include + +#include +#include +#include +#include + +#include "api/rtc_event_log/rtc_event.h" +#include "api/units/timestamp.h" +#include "logging/rtc_event_log/events/rtc_event_definition.h" + +namespace webrtc { + +RtcEventNetEqSetMinimumDelay::RtcEventNetEqSetMinimumDelay(uint32_t remote_ssrc, + int delay_ms) + : remote_ssrc_(remote_ssrc), minimum_delay_ms_(delay_ms) {} +RtcEventNetEqSetMinimumDelay::~RtcEventNetEqSetMinimumDelay() {} + +} // namespace webrtc diff --git a/logging/rtc_event_log/events/rtc_event_neteq_set_minimum_delay.h b/logging/rtc_event_log/events/rtc_event_neteq_set_minimum_delay.h new file mode 100644 index 0000000000..2e49adb36e --- /dev/null +++ b/logging/rtc_event_log/events/rtc_event_neteq_set_minimum_delay.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2022 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_NETEQ_SET_MINIMUM_DELAY_H_ +#define LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_NETEQ_SET_MINIMUM_DELAY_H_ + +#include + +#include +#include +#include +#include + +#include "absl/memory/memory.h" +#include "absl/strings/string_view.h" +#include "api/rtc_event_log/rtc_event.h" +#include "api/units/timestamp.h" +#include "logging/rtc_event_log/events/rtc_event_definition.h" + +namespace webrtc { + +struct LoggedNetEqSetMinimumDelayEvent { + LoggedNetEqSetMinimumDelayEvent() = default; + LoggedNetEqSetMinimumDelayEvent(Timestamp timestamp, + uint32_t remote_ssrc, + int minimum_delay_ms) + : timestamp(timestamp), + remote_ssrc(remote_ssrc), + minimum_delay_ms(minimum_delay_ms) {} + + int64_t log_time_us() const { return timestamp.us(); } + int64_t log_time_ms() const { return timestamp.ms(); } + Timestamp log_time() const { return timestamp; } + + Timestamp timestamp = Timestamp::MinusInfinity(); + uint32_t remote_ssrc; + int minimum_delay_ms; +}; + +class RtcEventNetEqSetMinimumDelay final : public RtcEvent { + public: + static constexpr Type kType = Type::NetEqSetMinimumDelay; + + explicit RtcEventNetEqSetMinimumDelay(uint32_t remote_ssrc, int delay_ms); + ~RtcEventNetEqSetMinimumDelay() override; + + Type GetType() const override { return kType; } + bool IsConfigEvent() const override { return false; } + uint32_t remote_ssrc() const { return remote_ssrc_; } + int minimum_delay_ms() const { return minimum_delay_ms_; } + + std::unique_ptr Copy() const { + return absl::WrapUnique( + new RtcEventNetEqSetMinimumDelay(*this)); + } + + private: + uint32_t remote_ssrc_; + int minimum_delay_ms_; +}; + +} // namespace webrtc +#endif // LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_NETEQ_SET_MINIMUM_DELAY_H_ diff --git a/logging/rtc_event_log/rtc_event_log2.proto b/logging/rtc_event_log/rtc_event_log2.proto index a541533dcc..2545be87e5 100644 --- a/logging/rtc_event_log/rtc_event_log2.proto +++ b/logging/rtc_event_log/rtc_event_log2.proto @@ -40,6 +40,7 @@ message EventStream { repeated GenericAckReceived generic_acks_received = 31; repeated RouteChange route_changes = 32; repeated RemoteEstimates remote_estimates = 33; + repeated NetEqSetMinimumDelay neteq_set_minimum_delay = 34; repeated AudioRecvStreamConfig audio_recv_stream_configs = 101; repeated AudioSendStreamConfig audio_send_stream_configs = 102; @@ -285,6 +286,26 @@ message AudioPlayoutEvents { optional bytes local_ssrc_deltas = 102; } +message NetEqSetMinimumDelay { + // required + optional int64 timestamp_ms = 1; + + // required - The SSRC of the remote stream associated with the MinimumDelay + // event. + optional fixed32 remote_ssrc = 2; + + // required - minimum delay passed to SetBaseMinimumDelay. + optional int32 minimum_delay_ms = 3; + + // optional - required if the batch contains delta encoded events. + optional uint32 number_of_deltas = 4; + + // Delta encodings. + optional bytes timestamp_ms_deltas = 101; + optional bytes remote_ssrc_deltas = 102; + optional bytes minimum_delay_ms_deltas = 103; +} + message FrameDecodedEvents { enum Codec { CODEC_UNKNOWN = 0; diff --git a/logging/rtc_event_log/rtc_event_log_parser.cc b/logging/rtc_event_log/rtc_event_log_parser.cc index 76d2d77726..34e89ab70d 100644 --- a/logging/rtc_event_log/rtc_event_log_parser.cc +++ b/logging/rtc_event_log/rtc_event_log_parser.cc @@ -1086,6 +1086,7 @@ void ParsedRtcEventLog::Clear() { start_log_events_.clear(); stop_log_events_.clear(); audio_playout_events_.clear(); + neteq_set_minimum_delay_events_.clear(); audio_network_adaptation_events_.clear(); bwe_probe_cluster_created_events_.clear(); bwe_probe_failure_events_.clear(); @@ -1235,6 +1236,10 @@ ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::ParseStream( // Audio playout events are grouped by SSRC. StoreFirstAndLastTimestamp(audio_stream.second); } + for (const auto& set_minimum_delay : neteq_set_minimum_delay_events()) { + // NetEq SetMinimumDelay grouped by SSRC. + StoreFirstAndLastTimestamp(set_minimum_delay.second); + } StoreFirstAndLastTimestamp(audio_network_adaptation_events()); StoreFirstAndLastTimestamp(bwe_probe_cluster_created_events()); StoreFirstAndLastTimestamp(bwe_probe_failure_events()); @@ -2522,7 +2527,8 @@ ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreParsedNewFormatEvent( stream.generic_packets_sent_size() + stream.generic_packets_received_size() + stream.generic_acks_received_size() + - stream.frame_decoded_events_size(), + stream.frame_decoded_events_size() + + stream.neteq_set_minimum_delay_size(), 1u); if (stream.incoming_rtp_packets_size() == 1) { @@ -2582,6 +2588,8 @@ ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreParsedNewFormatEvent( return StoreGenericAckReceivedEvent(stream.generic_acks_received(0)); } else if (stream.frame_decoded_events_size() == 1) { return StoreFrameDecodedEvents(stream.frame_decoded_events(0)); + } else if (stream.neteq_set_minimum_delay_size() == 1) { + return StoreNetEqSetMinimumDelay(stream.neteq_set_minimum_delay(0)); } else { RTC_DCHECK_NOTREACHED(); return ParseStatus::Success(); @@ -2726,6 +2734,65 @@ ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreAudioPlayoutEvent( return ParseStatus::Success(); } +ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreNetEqSetMinimumDelay( + const rtclog2::NetEqSetMinimumDelay& proto) { + RTC_PARSE_CHECK_OR_RETURN(proto.has_timestamp_ms()); + RTC_PARSE_CHECK_OR_RETURN(proto.has_remote_ssrc()); + RTC_PARSE_CHECK_OR_RETURN(proto.has_minimum_delay_ms()); + + // Base event + neteq_set_minimum_delay_events_[proto.remote_ssrc()].emplace_back( + Timestamp::Millis(proto.timestamp_ms()), proto.remote_ssrc(), + static_cast(proto.minimum_delay_ms())); + + const size_t number_of_deltas = + proto.has_number_of_deltas() ? proto.number_of_deltas() : 0u; + if (number_of_deltas == 0) { + return ParseStatus::Success(); + } + + // timestamp_ms + std::vector> timestamp_ms_values = + DecodeDeltas(proto.timestamp_ms_deltas(), + ToUnsigned(proto.timestamp_ms()), number_of_deltas); + RTC_PARSE_CHECK_OR_RETURN_EQ(timestamp_ms_values.size(), number_of_deltas); + + // remote_ssrc + std::vector> remote_ssrc_values = DecodeDeltas( + proto.remote_ssrc_deltas(), proto.remote_ssrc(), number_of_deltas); + RTC_PARSE_CHECK_OR_RETURN_EQ(remote_ssrc_values.size(), number_of_deltas); + + // minimum_delay_ms + std::vector> minimum_delay_ms_values = + DecodeDeltas(proto.minimum_delay_ms_deltas(), + ToUnsigned(proto.minimum_delay_ms()), number_of_deltas); + RTC_PARSE_CHECK_OR_RETURN_EQ(minimum_delay_ms_values.size(), + number_of_deltas); + + // Populate events from decoded deltas + for (size_t i = 0; i < number_of_deltas; ++i) { + RTC_PARSE_CHECK_OR_RETURN(timestamp_ms_values[i].has_value()); + RTC_PARSE_CHECK_OR_RETURN(remote_ssrc_values[i].has_value()); + RTC_PARSE_CHECK_OR_RETURN_LE(remote_ssrc_values[i].value(), + std::numeric_limits::max()); + RTC_PARSE_CHECK_OR_RETURN(minimum_delay_ms_values[i].has_value()); + + int64_t timestamp_ms; + RTC_PARSE_CHECK_OR_RETURN( + ToSigned(timestamp_ms_values[i].value(), ×tamp_ms)); + + const uint32_t remote_ssrc = + static_cast(remote_ssrc_values[i].value()); + int minimum_delay_ms; + RTC_PARSE_CHECK_OR_RETURN( + ToSigned(minimum_delay_ms_values[i].value(), &minimum_delay_ms)); + neteq_set_minimum_delay_events_[remote_ssrc].emplace_back( + Timestamp::Millis(timestamp_ms), remote_ssrc, minimum_delay_ms); + } + + return ParseStatus::Success(); +} + ParsedRtcEventLog::ParseStatus ParsedRtcEventLog::StoreIncomingRtpPackets( const rtclog2::IncomingRtpPackets& proto) { return StoreRtpPackets(proto, &incoming_rtp_packets_map_); diff --git a/logging/rtc_event_log/rtc_event_log_parser.h b/logging/rtc_event_log/rtc_event_log_parser.h index ae2d4fe586..9ad96274d3 100644 --- a/logging/rtc_event_log/rtc_event_log_parser.h +++ b/logging/rtc_event_log/rtc_event_log_parser.h @@ -40,6 +40,7 @@ #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" @@ -451,6 +452,11 @@ class ParsedRtcEventLog { return audio_playout_events_; } + const std::map>& + neteq_set_minimum_delay_events() const { + return neteq_set_minimum_delay_events_; + } + const std::vector& audio_network_adaptation_events() const { return audio_network_adaptation_events_; @@ -763,6 +769,8 @@ class ParsedRtcEventLog { ParseStatus StoreIncomingRtcpPackets( const rtclog2::IncomingRtcpPackets& proto); ParseStatus StoreIncomingRtpPackets(const rtclog2::IncomingRtpPackets& proto); + ParseStatus StoreNetEqSetMinimumDelay( + const rtclog2::NetEqSetMinimumDelay& proto); ParseStatus StoreOutgoingRtcpPackets( const rtclog2::OutgoingRtcpPackets& proto); ParseStatus StoreOutgoingRtpPackets(const rtclog2::OutgoingRtpPackets& proto); @@ -858,6 +866,8 @@ class ParsedRtcEventLog { std::map> audio_playout_events_; + std::map> + neteq_set_minimum_delay_events_; std::vector audio_network_adaptation_events_; diff --git a/logging/rtc_event_log/rtc_event_log_unittest_helper.cc b/logging/rtc_event_log/rtc_event_log_unittest_helper.cc index 2607028f60..43b6fc81dc 100644 --- a/logging/rtc_event_log/rtc_event_log_unittest_helper.cc +++ b/logging/rtc_event_log/rtc_event_log_unittest_helper.cc @@ -116,6 +116,12 @@ EventGenerator::NewAudioNetworkAdaptation() { return std::make_unique(std::move(config)); } +std::unique_ptr +EventGenerator::NewNetEqSetMinimumDelay(uint32_t ssrc) { + return std::make_unique( + ssrc, prng_.Rand(std::numeric_limits::max())); +} + std::unique_ptr EventGenerator::NewBweUpdateDelayBased() { constexpr int32_t kMaxBweBps = 20000000; @@ -1351,5 +1357,13 @@ void EventVerifier::VerifyLoggedVideoSendConfig( VerifyLoggedStreamConfig(original_event.config(), logged_event.config); } +void EventVerifier::VerifyLoggedNetEqSetMinimumDelay( + const RtcEventNetEqSetMinimumDelay& original_event, + const LoggedNetEqSetMinimumDelayEvent& logged_event) const { + EXPECT_EQ(original_event.timestamp_ms(), logged_event.timestamp.ms()); + EXPECT_EQ(original_event.remote_ssrc(), logged_event.remote_ssrc); + EXPECT_EQ(original_event.minimum_delay_ms(), logged_event.minimum_delay_ms); +} + } // namespace test } // namespace webrtc diff --git a/logging/rtc_event_log/rtc_event_log_unittest_helper.h b/logging/rtc_event_log/rtc_event_log_unittest_helper.h index 94a46c195c..7b863fd8a0 100644 --- a/logging/rtc_event_log/rtc_event_log_unittest_helper.h +++ b/logging/rtc_event_log/rtc_event_log_unittest_helper.h @@ -79,6 +79,8 @@ class EventGenerator { std::unique_ptr NewGenericPacketSent(); std::unique_ptr NewIceCandidatePair(); std::unique_ptr NewIceCandidatePairConfig(); + std::unique_ptr NewNetEqSetMinimumDelay( + uint32_t ssrc); std::unique_ptr NewProbeClusterCreated(); std::unique_ptr NewProbeResultFailure(); std::unique_ptr NewProbeResultSuccess(); @@ -317,6 +319,10 @@ class EventVerifier { const RtcEventVideoSendStreamConfig& original_event, const LoggedVideoSendConfig& logged_event) const; + void VerifyLoggedNetEqSetMinimumDelay( + const RtcEventNetEqSetMinimumDelay& original_event, + const LoggedNetEqSetMinimumDelayEvent& logged_event) const; + private: void VerifyReportBlock(const rtcp::ReportBlock& original_report_block, const rtcp::ReportBlock& logged_report_block);