/* * Copyright 2026 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/congestion_controller/scream/scream_feedback.h" #include "api/transport/ecn_marking.h" #include "api/transport/network_types.h" #include "api/units/data_size.h" #include "api/units/time_delta.h" #include "api/units/timestamp.h" #include "test/gtest.h" namespace webrtc { namespace { TEST(ScreamFeedbackTest, ParsesEmptyFeedback) { TransportPacketsFeedback msg; msg.feedback_time = Timestamp::Millis(1000); msg.data_in_flight = DataSize::Bytes(5000); ScreamFeedback parsed = ParseScreamFeedback(msg); EXPECT_EQ(parsed.feedback_time, Timestamp::Millis(1000)); EXPECT_EQ(parsed.data_in_flight, DataSize::Bytes(5000)); EXPECT_EQ(parsed.num_received_packets, 0); EXPECT_EQ(parsed.num_ce_marked_packets, 0); EXPECT_EQ(parsed.acked_not_marked_size, DataSize::Zero()); EXPECT_EQ(parsed.min_one_way_delay, TimeDelta::PlusInfinity()); EXPECT_EQ(parsed.max_one_way_delay, TimeDelta::Zero()); EXPECT_EQ(parsed.feedback_hold_time, TimeDelta::Zero()); EXPECT_EQ(parsed.rtt_sample, TimeDelta::Zero()); EXPECT_EQ(parsed.num_lost_packets, 0); EXPECT_EQ(parsed.num_recovered_packets, 0); } TEST(ScreamFeedbackTest, ParsesReceivedPacketsMetrics) { TransportPacketsFeedback msg; msg.feedback_time = Timestamp::Millis(1050); msg.data_in_flight = DataSize::Bytes(2000); // Packet 1: Received, Not CE-marked PacketResult packet1; packet1.sent_packet.size = DataSize::Bytes(1000); packet1.sent_packet.send_time = Timestamp::Millis(900); packet1.receive_time = Timestamp::Millis(950); packet1.arrival_time_offset = TimeDelta::Millis(5); packet1.ecn = EcnMarking::kNotEct; // Packet 2: Received, CE-marked PacketResult packet2; packet2.sent_packet.size = DataSize::Bytes(1200); packet2.sent_packet.send_time = Timestamp::Millis(910); packet2.receive_time = Timestamp::Millis(970); packet2.arrival_time_offset = TimeDelta::Millis(10); packet2.ecn = EcnMarking::kCe; msg.packet_feedbacks.push_back(packet1); msg.packet_feedbacks.push_back(packet2); ScreamFeedback parsed = ParseScreamFeedback(msg); EXPECT_EQ(parsed.num_received_packets, 2); EXPECT_EQ(parsed.num_ce_marked_packets, 1); // Only packet1 is not CE-marked, so size should be 1000 bytes EXPECT_EQ(parsed.acked_not_marked_size, DataSize::Bytes(1000)); // Packet 1 one-way delay = 950 - 900 = 50ms // Packet 2 one-way delay = 970 - 910 = 60ms EXPECT_EQ(parsed.min_one_way_delay, TimeDelta::Millis(50)); EXPECT_EQ(parsed.max_one_way_delay, TimeDelta::Millis(60)); // hold_time = last_packet.receive_time + offset - first_packet.receive_time // hold_time = 970 + 10 - 950 = 30ms EXPECT_EQ(parsed.feedback_hold_time, TimeDelta::Millis(30)); // rtt_sample = feedback_time - last_packet.send_time - // last_packet.arrival_time_offset rtt_sample = 1050 - 910 - 10 = 130ms EXPECT_EQ(parsed.rtt_sample, TimeDelta::Millis(130)); } TEST(ScreamFeedbackTest, ParsesLostAndRecoveredPackets) { TransportPacketsFeedback msg; msg.feedback_time = Timestamp::Millis(1000); // Packet 1: Lost for the first time PacketResult packet1; packet1.receive_time = Timestamp::PlusInfinity(); packet1.reported_lost_for_the_first_time = true; // Packet 2: Recovered for the first time PacketResult packet2; packet2.receive_time = Timestamp::Millis(900); packet2.reported_recovered_for_the_first_time = true; msg.packet_feedbacks.push_back(packet1); msg.packet_feedbacks.push_back(packet2); ScreamFeedback parsed = ParseScreamFeedback(msg); EXPECT_EQ(parsed.num_lost_packets, 1); EXPECT_EQ(parsed.num_recovered_packets, 1); } } // namespace } // namespace webrtc