| /* |
| * 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 <algorithm> |
| |
| #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" |
| |
| namespace webrtc { |
| |
| ScreamFeedback ParseScreamFeedback(const TransportPacketsFeedback& msg) { |
| ScreamFeedback parsed; |
| parsed.feedback_time = msg.feedback_time; |
| parsed.data_in_flight = msg.data_in_flight; |
| |
| const PacketResult* first_packet = nullptr; |
| const PacketResult* last_packet = nullptr; |
| PacketResult::ReceiveTimeOrder order; |
| |
| for (const PacketResult& packet : msg.packet_feedbacks) { |
| // Sum size of all packets in feedback that are not CE marked (includes |
| // lost). |
| if (packet.ecn != EcnMarking::kCe) { |
| parsed.acked_not_marked_size += packet.sent_packet.size; |
| } |
| |
| // Record loss and recovery events. |
| bool is_lost = |
| !packet.IsReceived() && packet.reported_lost_for_the_first_time; |
| bool is_recovered = packet.reported_recovered_for_the_first_time; |
| if (is_lost) { |
| parsed.num_lost_packets++; |
| } else if (is_recovered) { |
| parsed.num_recovered_packets++; |
| } |
| |
| // Update received-packet metrics. |
| if (packet.IsReceived()) { |
| parsed.num_received_packets++; |
| if (packet.ecn == EcnMarking::kCe) { |
| parsed.num_ce_marked_packets++; |
| } |
| |
| TimeDelta one_way_delay = |
| packet.receive_time - packet.sent_packet.send_time; |
| parsed.min_one_way_delay = |
| std::min(parsed.min_one_way_delay, one_way_delay); |
| parsed.max_one_way_delay = |
| std::max(parsed.max_one_way_delay, one_way_delay); |
| |
| // Replicate exact ReceiveTimeOrder tie-breaking logic to find first & |
| // last packets. |
| if (!first_packet || order(packet, *first_packet)) { |
| first_packet = &packet; |
| } |
| if (!last_packet || order(*last_packet, packet)) { |
| last_packet = &packet; |
| } |
| } |
| } |
| |
| // Directly calculate feedback hold time of this feedback. |
| if (first_packet && last_packet) { |
| parsed.feedback_hold_time = |
| last_packet->receive_time + |
| last_packet->arrival_time_offset.value_or(TimeDelta::Zero()) - |
| first_packet->receive_time; |
| } |
| |
| // Directly calculate the RTT sample of this feedback. |
| if (last_packet) { |
| parsed.rtt_sample = std::max( |
| msg.feedback_time - last_packet->sent_packet.send_time - |
| last_packet->arrival_time_offset.value_or(TimeDelta::Zero()), |
| TimeDelta::Zero()); |
| } |
| |
| return parsed; |
| } |
| |
| } // namespace webrtc |