From 612872b29dc22272bca64e3ef1c2617248c7d517 Mon Sep 17 00:00:00 2001 From: Lionel Koenig Date: Tue, 13 Dec 2022 08:58:13 +0100 Subject: [PATCH] Add RtcEvent to store when MinimumSetDelay is set on NetEq MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To be able to simulate offline some scenario in which the javascript layer set the minimum base buffer size of neteq, it is required to record those API calls. This change introduces this. Bug: webrtc:14763 Change-Id: Ic817913eda60978d6fca3f8e12229aeec505ca25 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/287122 Auto-Submit: Lionel Koenig Reviewed-by: Per Kjellander Commit-Queue: Lionel Koenig Reviewed-by: Per Åhgren Reviewed-by: Björn Terelius Cr-Commit-Position: refs/heads/main@{#39104} --- api/rtc_event_log/rtc_event.h | 1 + audio/channel_receive.cc | 3 + logging/BUILD.gn | 3 + .../encoder/rtc_event_log_encoder_legacy.cc | 1 + .../rtc_event_log_encoder_new_format.cc | 77 +++++++++++++++++++ .../rtc_event_log_encoder_new_format.h | 7 ++ .../encoder/rtc_event_log_encoder_unittest.cc | 58 ++++++++++++++ .../rtc_event_neteq_set_minimum_delay.cc | 31 ++++++++ .../rtc_event_neteq_set_minimum_delay.h | 70 +++++++++++++++++ logging/rtc_event_log/rtc_event_log2.proto | 21 +++++ logging/rtc_event_log/rtc_event_log_parser.cc | 69 ++++++++++++++++- logging/rtc_event_log/rtc_event_log_parser.h | 10 +++ .../rtc_event_log_unittest_helper.cc | 14 ++++ .../rtc_event_log_unittest_helper.h | 6 ++ 14 files changed, 370 insertions(+), 1 deletion(-) create mode 100644 logging/rtc_event_log/events/rtc_event_neteq_set_minimum_delay.cc create mode 100644 logging/rtc_event_log/events/rtc_event_neteq_set_minimum_delay.h 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);