blob: 8cd33c0cedcc124afc434f4d6002a02074e6ef8d [file] [log] [blame]
/*
* Copyright 2025 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 "rtc_tools/rtc_event_log_visualizer/log_scream_simulation.h"
#include <cstdint>
#include <optional>
#include <vector>
#include "api/environment/environment.h"
#include "api/transport/network_types.h"
#include "api/units/data_rate.h"
#include "api/units/data_size.h"
#include "api/units/time_delta.h"
#include "api/units/timestamp.h"
#include "logging/rtc_event_log/events/logged_rtp_rtcp.h"
#include "logging/rtc_event_log/events/rtc_event_ice_candidate_pair_config.h"
#include "logging/rtc_event_log/rtc_event_log_parser.h"
#include "logging/rtc_event_log/rtc_event_processor.h"
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
#include "rtc_base/checks.h"
#include "rtc_base/network/sent_packet.h"
namespace webrtc {
LogScreamSimulation::LogScreamSimulation(const Config& config,
const Environment& env)
: env_(env), send_rate_tracker_(config.rate_window) {}
void LogScreamSimulation::ProcessUntil(Timestamp to_time) {
current_time_ = to_time;
}
void LogScreamSimulation::OnPacketSent(const LoggedPacketInfo& packet) {
ProcessUntil(packet.log_packet_time);
RtpPacketToSend send_packet(/*extensions=*/nullptr);
int64_t packet_id = packet.has_transport_seq_no ? packet.transport_seq_no
: next_ccfb_packet_id_++;
send_packet.set_transport_sequence_number(packet_id);
send_packet.SetSsrc(packet.ssrc);
send_packet.SetSequenceNumber(packet.stream_seq_no);
send_packet.SetPayloadSize(packet.size - send_packet.headers_size());
RTC_DCHECK_EQ(send_packet.size(), packet.size);
transport_feedback_.AddPacket(send_packet, PacedPacketInfo(), packet.overhead,
packet.log_packet_time);
SentPacketInfo sent_packet;
sent_packet.packet_id = packet_id;
sent_packet.send_time_ms = packet.log_packet_time.ms();
sent_packet.info.included_in_allocation = true;
sent_packet.info.packet_size_bytes = packet.size + packet.overhead;
sent_packet.info.included_in_feedback = true;
send_rate_tracker_.Update(DataSize::Bytes(sent_packet.info.packet_size_bytes),
packet.log_packet_time);
transport_feedback_.ProcessSentPacket(sent_packet);
}
void LogScreamSimulation::OnTransportFeedback(
const LoggedRtcpPacketTransportFeedback& feedback) {
auto feedback_time = Timestamp::Millis(feedback.log_time_ms());
ProcessUntil(feedback_time);
std::optional<TransportPacketsFeedback> msg =
transport_feedback_.ProcessTransportFeedback(feedback.transport_feedback,
feedback_time);
if (msg.has_value()) {
scream_->OnTransportPacketsFeedback(*msg);
LogState(*msg);
}
}
void LogScreamSimulation::OnCongestionControlFeedback(
const LoggedRtcpCongestionControlFeedback& feedback) {
auto feedback_time = Timestamp::Millis(feedback.log_time_ms());
ProcessUntil(feedback_time);
std::optional<TransportPacketsFeedback> msg =
transport_feedback_.ProcessCongestionControlFeedback(
feedback.congestion_feedback, feedback_time);
if (msg.has_value()) {
scream_->OnTransportPacketsFeedback(*msg);
LogState(*msg);
}
}
void LogScreamSimulation::OnIceConfig(
const LoggedIceCandidatePairConfig& candidate) {
if (candidate.type == IceCandidatePairConfigType::kSelected) {
auto log_time = Timestamp::Micros(candidate.log_time_us());
ProcessUntil(log_time);
// This may be a simplification. See
// RtpTransportControllerSend::IsRelevantRouteChange
if (local_candidate_type_ != candidate.local_candidate_type ||
remote_candidate_type_ != candidate.remote_candidate_type) {
// Recreate Scream. This is inline with behaviour in
// ScreamNetworkController::OnNetworkRouteChange.
scream_.emplace(env_);
scream_->SetFirstTargetRate(DataRate::KilobitsPerSec(300));
local_candidate_type_ = candidate.local_candidate_type;
remote_candidate_type_ = candidate.remote_candidate_type;
}
}
}
void LogScreamSimulation::ProcessEventsInLog(
const ParsedRtcEventLog& parsed_log_) {
std::vector<LoggedPacketInfo> packet_infos =
parsed_log_.GetOutgoingPacketInfos();
RtcEventProcessor processor;
processor.AddEvents(
packet_infos,
[this](const LoggedPacketInfo& packet) { OnPacketSent(packet); },
PacketDirection::kOutgoingPacket);
processor.AddEvents(
parsed_log_.transport_feedbacks(PacketDirection::kIncomingPacket),
[this](const LoggedRtcpPacketTransportFeedback& feedback) {
OnTransportFeedback(feedback);
},
PacketDirection::kIncomingPacket);
processor.AddEvents(
parsed_log_.congestion_feedback(PacketDirection::kIncomingPacket),
[this](const LoggedRtcpCongestionControlFeedback& report) {
OnCongestionControlFeedback(report);
},
PacketDirection::kIncomingPacket);
processor.AddEvents(parsed_log_.ice_candidate_pair_configs(),
[this](const LoggedIceCandidatePairConfig& candidate) {
OnIceConfig(candidate);
});
processor.ProcessEventsInOrder();
}
void LogScreamSimulation::LogState(const TransportPacketsFeedback& msg) {
state_.emplace_back(State{
.time = msg.feedback_time,
.target_rate = scream_->target_rate(),
.pacing_rate = scream_->pacing_rate(),
.send_rate =
send_rate_tracker_.Rate(msg.feedback_time).value_or(DataRate::Zero()),
.ref_window = scream_->ref_window(),
.ref_window_i = scream_->ref_window_i(),
.max_data_in_flight = scream_->max_data_in_flight(),
.data_in_flight = msg.data_in_flight,
.queue_delay_dev_norm =
scream_->delay_based_congestion_control().queue_delay_dev_norm(),
.l4s_alpha = scream_->l4s_alpha(),
.l4s_alpha_v = scream_->delay_based_congestion_control().l4s_alpha_v()});
}
} // namespace webrtc