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 5246b217b6..4050758708 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 @@ -859,6 +859,46 @@ TEST_P(RtcEventLogEncoderTest, RtcEventRtcpTransportFeedback) { } } +TEST_P(RtcEventLogEncoderTest, RtcEventRtcpLossNotification) { + if (force_repeated_fields_) { + return; + } + + rtc::ScopedFakeClock fake_clock; + fake_clock.SetTimeMicros(static_cast(prng_.Rand()) * 1000); + + for (auto direction : {kIncomingPacket, kOutgoingPacket}) { + std::vector events; + events.reserve(event_count_); + std::vector timestamps_us(event_count_); + for (size_t i = 0; i < event_count_; ++i) { + timestamps_us[i] = rtc::TimeMicros(); + events.emplace_back(gen_.NewLossNotification()); + rtc::Buffer buffer = events[i].Build(); + if (direction == kIncomingPacket) { + history_.push_back( + absl::make_unique(buffer)); + } else { + history_.push_back( + absl::make_unique(buffer)); + } + fake_clock.AdvanceTimeMicros(prng_.Rand(0, 1000) * 1000); + } + + std::string encoded = + encoder_->EncodeBatch(history_.begin(), history_.end()); + ASSERT_TRUE(parsed_log_.ParseString(encoded)); + + const auto& loss_notifications = parsed_log_.loss_notifications(direction); + ASSERT_EQ(loss_notifications.size(), event_count_); + + for (size_t i = 0; i < event_count_; ++i) { + verifier_.VerifyLoggedLossNotification(timestamps_us[i], events[i], + loss_notifications[i]); + } + } +} + TEST_P(RtcEventLogEncoderTest, RtcEventRtpPacketIncoming) { TestRtpPackets(); } diff --git a/logging/rtc_event_log/logged_events.h b/logging/rtc_event_log/logged_events.h index b8c925639f..83978e09ea 100644 --- a/logging/rtc_event_log/logged_events.h +++ b/logging/rtc_event_log/logged_events.h @@ -25,6 +25,7 @@ #include "logging/rtc_event_log/rtc_stream_config.h" #include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor_config.h" #include "modules/remote_bitrate_estimator/include/bwe_defines.h" +#include "modules/rtp_rtcp/source/rtcp_packet/loss_notification.h" #include "modules/rtp_rtcp/source/rtcp_packet/nack.h" #include "modules/rtp_rtcp/source/rtcp_packet/receiver_report.h" #include "modules/rtp_rtcp/source/rtcp_packet/remb.h" @@ -345,8 +346,6 @@ struct LoggedRtcpPacketRemb { rtcp::Remb remb; }; -// TODO(eladalon): Add LossNotification. - struct LoggedRtcpPacketNack { LoggedRtcpPacketNack() = default; LoggedRtcpPacketNack(int64_t timestamp_us, const rtcp::Nack& nack) @@ -373,6 +372,20 @@ struct LoggedRtcpPacketTransportFeedback { rtcp::TransportFeedback transport_feedback; }; +struct LoggedRtcpPacketLossNotification { + LoggedRtcpPacketLossNotification() = default; + LoggedRtcpPacketLossNotification( + int64_t timestamp_us, + const rtcp::LossNotification& loss_notification) + : timestamp_us(timestamp_us), loss_notification(loss_notification) {} + + int64_t log_time_us() const { return timestamp_us; } + int64_t log_time_ms() const { return timestamp_us / 1000; } + + int64_t timestamp_us; + rtcp::LossNotification loss_notification; +}; + struct LoggedStartEvent { explicit LoggedStartEvent(int64_t timestamp_us) : LoggedStartEvent(timestamp_us, timestamp_us / 1000) {} diff --git a/logging/rtc_event_log/rtc_event_log_parser.cc b/logging/rtc_event_log/rtc_event_log_parser.cc index b68e58dc4c..e7e31a4906 100644 --- a/logging/rtc_event_log/rtc_event_log_parser.cc +++ b/logging/rtc_event_log/rtc_event_log_parser.cc @@ -782,7 +782,8 @@ void StoreRtcpBlocks( std::vector* sr_list, std::vector* rr_list, std::vector* remb_list, - std::vector* nack_list) { + std::vector* nack_list, + std::vector* loss_notification_list) { rtcp::CommonHeader header; for (const uint8_t* block = packet_begin; block < packet_end; block = header.NextPacket()) { @@ -807,10 +808,22 @@ void StoreRtcpBlocks( } } else if (header.type() == rtcp::Remb::kPacketType && header.fmt() == rtcp::Remb::kFeedbackMessageType) { - LoggedRtcpPacketRemb parsed_block; - parsed_block.timestamp_us = timestamp_us; - if (parsed_block.remb.Parse(header)) { - remb_list->push_back(std::move(parsed_block)); + bool type_found = false; + if (!type_found) { + LoggedRtcpPacketRemb parsed_block; + parsed_block.timestamp_us = timestamp_us; + if (parsed_block.remb.Parse(header)) { + remb_list->push_back(std::move(parsed_block)); + type_found = true; + } + } + if (!type_found) { + LoggedRtcpPacketLossNotification parsed_block; + parsed_block.timestamp_us = timestamp_us; + if (parsed_block.loss_notification.Parse(header)) { + loss_notification_list->push_back(std::move(parsed_block)); + type_found = true; + } } } else if (header.type() == rtcp::Nack::kPacketType && header.fmt() == rtcp::Nack::kFeedbackMessageType) { @@ -937,6 +950,8 @@ void ParsedRtcEventLog::Clear() { outgoing_remb_.clear(); incoming_transport_feedback_.clear(); outgoing_transport_feedback_.clear(); + incoming_loss_notification_.clear(); + outgoing_loss_notification_.clear(); start_log_events_.clear(); stop_log_events_.clear(); @@ -1046,7 +1061,8 @@ bool ParsedRtcEventLog::ParseStream( const uint8_t* packet_end = packet_begin + incoming.rtcp.raw_data.size(); StoreRtcpBlocks(timestamp_us, packet_begin, packet_end, &incoming_transport_feedback_, &incoming_sr_, &incoming_rr_, - &incoming_remb_, &incoming_nack_); + &incoming_remb_, &incoming_nack_, + &incoming_loss_notification_); } for (const auto& outgoing : outgoing_rtcp_packets_) { @@ -1055,7 +1071,8 @@ bool ParsedRtcEventLog::ParseStream( const uint8_t* packet_end = packet_begin + outgoing.rtcp.raw_data.size(); StoreRtcpBlocks(timestamp_us, packet_begin, packet_end, &outgoing_transport_feedback_, &outgoing_sr_, &outgoing_rr_, - &outgoing_remb_, &outgoing_nack_); + &outgoing_remb_, &outgoing_nack_, + &outgoing_loss_notification_); } // Store first and last timestamp events that might happen before the call is diff --git a/logging/rtc_event_log/rtc_event_log_parser.h b/logging/rtc_event_log/rtc_event_log_parser.h index 02fcbec890..d0c15a1337 100644 --- a/logging/rtc_event_log/rtc_event_log_parser.h +++ b/logging/rtc_event_log/rtc_event_log_parser.h @@ -461,6 +461,15 @@ class ParsedRtcEventLog { } } + const std::vector& loss_notifications( + PacketDirection direction) { + if (direction == kIncomingPacket) { + return incoming_loss_notification_; + } else { + return outgoing_loss_notification_; + } + } + int64_t first_timestamp() const { return first_timestamp_; } int64_t last_timestamp() const { return last_timestamp_; } @@ -635,6 +644,8 @@ class ParsedRtcEventLog { std::vector outgoing_remb_; std::vector incoming_transport_feedback_; std::vector outgoing_transport_feedback_; + std::vector incoming_loss_notification_; + std::vector outgoing_loss_notification_; std::vector start_log_events_; std::vector stop_log_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 dff2952f4c..dc694b566a 100644 --- a/logging/rtc_event_log/rtc_event_log_unittest_helper.cc +++ b/logging/rtc_event_log/rtc_event_log_unittest_helper.cc @@ -296,6 +296,17 @@ rtcp::Remb EventGenerator::NewRemb() { return remb; } +rtcp::LossNotification EventGenerator::NewLossNotification() { + rtcp::LossNotification loss_notification; + const uint16_t last_decoded = prng_.Rand(); + const uint16_t last_received = + last_decoded + (prng_.Rand() & 0x7fff); + const bool decodability_flag = prng_.Rand(); + EXPECT_TRUE( + loss_notification.Set(last_decoded, last_received, decodability_flag)); + return loss_notification; +} + std::unique_ptr EventGenerator::NewRtcpPacketIncoming() { enum class SupportedRtcpTypes { @@ -957,6 +968,19 @@ void EventVerifier::VerifyLoggedRemb(int64_t log_time_us, EXPECT_EQ(original_remb.bitrate_bps(), logged_remb.remb.bitrate_bps()); } +void EventVerifier::VerifyLoggedLossNotification( + int64_t log_time_us, + const rtcp::LossNotification& original_loss_notification, + const LoggedRtcpPacketLossNotification& logged_loss_notification) { + EXPECT_EQ(log_time_us, logged_loss_notification.log_time_us()); + 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, 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 61b202c26d..2a05ac5e93 100644 --- a/logging/rtc_event_log/rtc_event_log_unittest_helper.h +++ b/logging/rtc_event_log/rtc_event_log_unittest_helper.h @@ -38,6 +38,7 @@ #include "logging/rtc_event_log/rtc_event_log_parser.h" #include "logging/rtc_event_log/rtc_stream_config.h" #include "modules/rtp_rtcp/include/rtp_header_extension_map.h" +#include "modules/rtp_rtcp/source/rtcp_packet/loss_notification.h" #include "modules/rtp_rtcp/source/rtcp_packet/receiver_report.h" #include "modules/rtp_rtcp/source/rtcp_packet/report_block.h" #include "modules/rtp_rtcp/source/rtcp_packet/sender_report.h" @@ -85,6 +86,7 @@ class EventGenerator { rtcp::Nack NewNack(); rtcp::TransportFeedback NewTransportFeedback(); rtcp::Remb NewRemb(); + rtcp::LossNotification NewLossNotification(); // |all_configured_exts| determines whether the RTP packet exhibits all // configured extensions, or a random subset thereof. @@ -240,6 +242,10 @@ class EventVerifier { void VerifyLoggedRemb(int64_t log_time_us, const rtcp::Remb& original_remb, const LoggedRtcpPacketRemb& logged_remb); + void VerifyLoggedLossNotification( + int64_t log_time_us, + const rtcp::LossNotification& original_loss_notification, + const LoggedRtcpPacketLossNotification& logged_loss_notification); void VerifyLoggedStartEvent(int64_t start_time_us, int64_t utc_start_time_us,