|  | /* | 
|  | *  Copyright (c) 2024 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 "modules/remote_bitrate_estimator/congestion_control_feedback_tracker.h" | 
|  |  | 
|  | #include <cstdint> | 
|  | #include <vector> | 
|  |  | 
|  | #include "api/transport/ecn_marking.h" | 
|  | #include "api/units/time_delta.h" | 
|  | #include "api/units/timestamp.h" | 
|  | #include "modules/rtp_rtcp/source/rtcp_packet/congestion_control_feedback.h" | 
|  | #include "modules/rtp_rtcp/source/rtp_packet_received.h" | 
|  | #include "test/gmock.h" | 
|  | #include "test/gtest.h" | 
|  |  | 
|  | namespace webrtc { | 
|  | namespace { | 
|  |  | 
|  | using ::testing::AllOf; | 
|  | using ::testing::Field; | 
|  | using ::testing::Property; | 
|  | using ::testing::SizeIs; | 
|  |  | 
|  | RtpPacketReceived CreatePacket(Timestamp arrival_time, | 
|  | uint16_t seq = 1, | 
|  | EcnMarking ecn = EcnMarking::kNotEct) { | 
|  | RtpPacketReceived packet; | 
|  | packet.SetSsrc(1234); | 
|  | packet.SetSequenceNumber(seq); | 
|  | packet.set_arrival_time(arrival_time); | 
|  | packet.set_ecn(ecn); | 
|  | return packet; | 
|  | } | 
|  |  | 
|  | TEST(CongestionControlFeedbackTrackerTest, | 
|  | FeedbackIncludeReceivedPacketsInSequenceNumberOrder) { | 
|  | RtpPacketReceived packet_1 = | 
|  | CreatePacket(/*arrival_time=*/Timestamp::Millis(123), /*seq =*/2); | 
|  | RtpPacketReceived packet_2 = | 
|  | CreatePacket(/*arrival_time=*/Timestamp::Millis(125), /*seq=*/1); | 
|  |  | 
|  | CongestionControlFeedbackTracker tracker; | 
|  | tracker.ReceivedPacket(packet_1); | 
|  | tracker.ReceivedPacket(packet_2); | 
|  |  | 
|  | Timestamp feedback_time = Timestamp::Millis(567); | 
|  | std::vector<rtcp::CongestionControlFeedback::PacketInfo> feedback_info; | 
|  | tracker.AddPacketsToFeedback(feedback_time, feedback_info); | 
|  | ASSERT_THAT(feedback_info, SizeIs(2)); | 
|  | EXPECT_THAT( | 
|  | feedback_info[0], | 
|  | AllOf( | 
|  | Field(&rtcp::CongestionControlFeedback::PacketInfo::sequence_number, | 
|  | packet_2.SequenceNumber()), | 
|  | Field( | 
|  | &rtcp::CongestionControlFeedback::PacketInfo::arrival_time_offset, | 
|  | feedback_time - packet_2.arrival_time()))); | 
|  | EXPECT_THAT( | 
|  | feedback_info[1], | 
|  | AllOf( | 
|  | Field(&rtcp::CongestionControlFeedback::PacketInfo::sequence_number, | 
|  | packet_1.SequenceNumber()), | 
|  | Field( | 
|  | &rtcp::CongestionControlFeedback::PacketInfo::arrival_time_offset, | 
|  | feedback_time - packet_1.arrival_time()))); | 
|  | } | 
|  |  | 
|  | TEST(CongestionControlFeedbackTrackerTest, | 
|  | ReportsFirstReceivedPacketArrivalTimeButEcnFromCePacketIfDuplicate) { | 
|  | RtpPacketReceived packet_1 = CreatePacket( | 
|  | /*arrival_time=*/Timestamp::Millis(123), /*seq =*/1, EcnMarking::kEct1); | 
|  | RtpPacketReceived packet_2 = CreatePacket( | 
|  | /*arrival_time=*/Timestamp::Millis(125), /*seq=*/1, EcnMarking::kCe); | 
|  | RtpPacketReceived packet_3 = CreatePacket( | 
|  | /*arrival_time=*/Timestamp::Millis(126), /*seq=*/1, EcnMarking::kEct1); | 
|  |  | 
|  | CongestionControlFeedbackTracker tracker; | 
|  | tracker.ReceivedPacket(packet_1); | 
|  | tracker.ReceivedPacket(packet_2); | 
|  | tracker.ReceivedPacket(packet_3); | 
|  |  | 
|  | Timestamp feedback_time = Timestamp::Millis(567); | 
|  | std::vector<rtcp::CongestionControlFeedback::PacketInfo> feedback_info; | 
|  | tracker.AddPacketsToFeedback(feedback_time, feedback_info); | 
|  | ASSERT_THAT(feedback_info, SizeIs(1)); | 
|  | EXPECT_THAT( | 
|  | feedback_info[0], | 
|  | AllOf( | 
|  | Field( | 
|  | &rtcp::CongestionControlFeedback::PacketInfo::arrival_time_offset, | 
|  | feedback_time - packet_1.arrival_time()), | 
|  | Field(&rtcp::CongestionControlFeedback::PacketInfo::ecn, | 
|  | EcnMarking::kCe))); | 
|  | } | 
|  |  | 
|  | TEST(CongestionControlFeedbackTrackerTest, | 
|  | FeedbackGeneratesContinouseSequenceNumbers) { | 
|  | RtpPacketReceived packet_1 = | 
|  | CreatePacket(/*arrival_time=*/Timestamp::Millis(123), /*seq =*/1); | 
|  | // Packet with sequence number 2 is lost or reordered. | 
|  | RtpPacketReceived packet_2 = CreatePacket( | 
|  | /*arrival_time=*/Timestamp::Millis(125), /*seq=*/3); | 
|  |  | 
|  | CongestionControlFeedbackTracker tracker; | 
|  | tracker.ReceivedPacket(packet_1); | 
|  | tracker.ReceivedPacket(packet_2); | 
|  |  | 
|  | std::vector<rtcp::CongestionControlFeedback::PacketInfo> feedback_info; | 
|  | Timestamp feedback_time = Timestamp::Millis(567); | 
|  | tracker.AddPacketsToFeedback(feedback_time, feedback_info); | 
|  | ASSERT_THAT(feedback_info, SizeIs(3)); | 
|  | EXPECT_THAT(feedback_info[0].sequence_number, 1); | 
|  | EXPECT_THAT(feedback_info[0].arrival_time_offset, | 
|  | feedback_time - packet_1.arrival_time()); | 
|  | EXPECT_THAT(feedback_info[1].sequence_number, 2); | 
|  | EXPECT_THAT(feedback_info[1].arrival_time_offset, TimeDelta::MinusInfinity()); | 
|  | EXPECT_THAT(feedback_info[2].sequence_number, 3); | 
|  | EXPECT_THAT(feedback_info[2].arrival_time_offset, | 
|  | feedback_time - packet_2.arrival_time()); | 
|  | } | 
|  |  | 
|  | TEST(CongestionControlFeedbackTrackerTest, | 
|  | FeedbackGeneratesContinouseSequenceNumbersBetweenFeedbackPackets) { | 
|  | RtpPacketReceived packet_1 = | 
|  | CreatePacket(/*arrival_time=*/Timestamp::Millis(123), /*seq =*/1); | 
|  | RtpPacketReceived packet_2 = CreatePacket( | 
|  | /*arrival_time=*/Timestamp::Millis(125), /*seq=*/3); | 
|  |  | 
|  | CongestionControlFeedbackTracker tracker; | 
|  | tracker.ReceivedPacket(packet_1); | 
|  |  | 
|  | std::vector<rtcp::CongestionControlFeedback::PacketInfo> feedback_info; | 
|  | Timestamp feedback_time = Timestamp::Millis(567); | 
|  | tracker.AddPacketsToFeedback(feedback_time, feedback_info); | 
|  | ASSERT_THAT(feedback_info, SizeIs(1)); | 
|  | EXPECT_THAT(feedback_info[0].sequence_number, 1); | 
|  | EXPECT_THAT(feedback_info[0].arrival_time_offset, | 
|  | feedback_time - packet_1.arrival_time()); | 
|  |  | 
|  | feedback_info.clear(); | 
|  | feedback_time = Timestamp::Millis(678); | 
|  | tracker.ReceivedPacket(packet_2); | 
|  | tracker.AddPacketsToFeedback(feedback_time, feedback_info); | 
|  | ASSERT_THAT(feedback_info, SizeIs(2)); | 
|  | EXPECT_THAT(feedback_info[0].sequence_number, 2); | 
|  | EXPECT_THAT(feedback_info[0].arrival_time_offset, TimeDelta::MinusInfinity()); | 
|  | EXPECT_THAT(feedback_info[1].sequence_number, 3); | 
|  | EXPECT_THAT(feedback_info[1].arrival_time_offset, | 
|  | feedback_time - packet_2.arrival_time()); | 
|  | } | 
|  |  | 
|  | TEST(CongestionControlFeedbackTrackerTest, | 
|  | FeedbackGeneratesRepeatedSequenceNumbersOnReorderingBetweenFeedback) { | 
|  | RtpPacketReceived packet_1 = | 
|  | CreatePacket(/*arrival_time=*/Timestamp::Millis(123), /*seq =*/2); | 
|  | RtpPacketReceived packet_2 = CreatePacket( | 
|  | /*arrival_time=*/Timestamp::Millis(125), /*seq=*/1); | 
|  | RtpPacketReceived packet_3 = CreatePacket( | 
|  | /*arrival_time=*/Timestamp::Millis(125), /*seq=*/3); | 
|  |  | 
|  | CongestionControlFeedbackTracker tracker; | 
|  | tracker.ReceivedPacket(packet_1); | 
|  |  | 
|  | std::vector<rtcp::CongestionControlFeedback::PacketInfo> feedback_info; | 
|  | Timestamp feedback_time = Timestamp::Millis(567); | 
|  | tracker.AddPacketsToFeedback(feedback_time, feedback_info); | 
|  | ASSERT_THAT(feedback_info, SizeIs(1)); | 
|  | EXPECT_THAT(feedback_info[0].sequence_number, 2); | 
|  | EXPECT_THAT(feedback_info[0].arrival_time_offset, | 
|  | feedback_time - packet_1.arrival_time()); | 
|  |  | 
|  | feedback_info.clear(); | 
|  | feedback_time = Timestamp::Millis(678); | 
|  | tracker.ReceivedPacket(packet_2); | 
|  | tracker.ReceivedPacket(packet_3); | 
|  | tracker.AddPacketsToFeedback(feedback_time, feedback_info); | 
|  | ASSERT_THAT(feedback_info, SizeIs(3)); | 
|  | EXPECT_THAT(feedback_info[0].sequence_number, 1); | 
|  | EXPECT_THAT(feedback_info[0].arrival_time_offset, | 
|  | feedback_time - packet_2.arrival_time()); | 
|  | EXPECT_THAT(feedback_info[1].sequence_number, 2); | 
|  | // TODO: bugs.webrtc.org/374550342 -  This is against the spec. According to | 
|  | // the specification, we should have kept the history. | 
|  | EXPECT_THAT(feedback_info[1].arrival_time_offset, TimeDelta::MinusInfinity()); | 
|  | EXPECT_THAT(feedback_info[2].sequence_number, 3); | 
|  | EXPECT_THAT(feedback_info[2].arrival_time_offset, | 
|  | feedback_time - packet_3.arrival_time()); | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  | }  // namespace webrtc |