/* * Copyright 2019 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_simulation.h" #include #include #include "logging/rtc_event_log/rtc_event_processor.h" #include "modules/rtp_rtcp/source/time_util.h" #include "system_wrappers/include/clock.h" namespace webrtc { LogBasedNetworkControllerSimulation::LogBasedNetworkControllerSimulation( std::unique_ptr factory, std::function update_handler) : update_handler_(update_handler), factory_(std::move(factory)) {} LogBasedNetworkControllerSimulation::~LogBasedNetworkControllerSimulation() {} void LogBasedNetworkControllerSimulation::HandleStateUpdate( const NetworkControlUpdate& update) { update_handler_(update, current_time_); } void LogBasedNetworkControllerSimulation::ProcessUntil(Timestamp to_time) { if (last_process_.IsInfinite()) { NetworkControllerConfig config; config.constraints.at_time = to_time; config.constraints.min_data_rate = DataRate::KilobitsPerSec(30); config.constraints.starting_rate = DataRate::KilobitsPerSec(300); config.event_log = &null_event_log_; controller_ = factory_->Create(config); } if (last_process_.IsInfinite() || to_time - last_process_ > TimeDelta::Seconds(1)) { last_process_ = to_time; current_time_ = to_time; ProcessInterval msg; msg.at_time = to_time; HandleStateUpdate(controller_->OnProcessInterval(msg)); } else { while (last_process_ + factory_->GetProcessInterval() <= to_time) { last_process_ += factory_->GetProcessInterval(); current_time_ = last_process_; ProcessInterval msg; msg.at_time = current_time_; HandleStateUpdate(controller_->OnProcessInterval(msg)); } current_time_ = to_time; } } void LogBasedNetworkControllerSimulation::OnProbeCreated( const LoggedBweProbeClusterCreatedEvent& probe_cluster) { pending_probes_.push_back({probe_cluster, 0, 0}); } void LogBasedNetworkControllerSimulation::OnPacketSent( const LoggedPacketInfo& packet) { ProcessUntil(packet.log_packet_time); if (packet.has_transport_seq_no) { PacedPacketInfo probe_info; if (!pending_probes_.empty() && packet.media_type == LoggedMediaType::kVideo) { auto& probe = pending_probes_.front(); probe_info.probe_cluster_id = probe.event.id; probe_info.send_bitrate_bps = probe.event.bitrate_bps; probe_info.probe_cluster_min_bytes = probe.event.min_bytes; probe_info.probe_cluster_min_probes = probe.event.min_packets; probe.packets_sent++; probe.bytes_sent += packet.size + packet.overhead; if (probe.bytes_sent >= probe.event.min_bytes && probe.packets_sent >= probe.event.min_packets) { pending_probes_.pop_front(); } } RtpPacketSendInfo packet_info; packet_info.media_ssrc = packet.ssrc; packet_info.transport_sequence_number = packet.transport_seq_no; packet_info.rtp_sequence_number = packet.stream_seq_no; packet_info.length = packet.size; packet_info.pacing_info = probe_info; transport_feedback_.AddPacket(packet_info, packet.overhead, packet.log_packet_time); } rtc::SentPacket sent_packet; 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; if (packet.has_transport_seq_no) { sent_packet.packet_id = packet.transport_seq_no; sent_packet.info.included_in_feedback = true; } auto msg = transport_feedback_.ProcessSentPacket(sent_packet); if (msg) HandleStateUpdate(controller_->OnSentPacket(*msg)); } void LogBasedNetworkControllerSimulation::OnFeedback( const LoggedRtcpPacketTransportFeedback& feedback) { auto feedback_time = Timestamp::Millis(feedback.log_time_ms()); ProcessUntil(feedback_time); auto msg = transport_feedback_.ProcessTransportFeedback( feedback.transport_feedback, feedback_time); if (msg) HandleStateUpdate(controller_->OnTransportPacketsFeedback(*msg)); } void LogBasedNetworkControllerSimulation::OnReceiverReport( const LoggedRtcpPacketReceiverReport& report) { if (report.rr.report_blocks().empty()) return; auto report_time = Timestamp::Millis(report.log_time_ms()); ProcessUntil(report_time); int packets_delta = 0; int lost_delta = 0; for (auto& block : report.rr.report_blocks()) { auto it = last_report_blocks_.find(block.source_ssrc()); if (it != last_report_blocks_.end()) { packets_delta += block.extended_high_seq_num() - it->second.extended_high_seq_num(); lost_delta += block.cumulative_lost() - it->second.cumulative_lost(); } last_report_blocks_[block.source_ssrc()] = block; } if (packets_delta > lost_delta) { TransportLossReport msg; msg.packets_lost_delta = lost_delta; msg.packets_received_delta = packets_delta - lost_delta; msg.receive_time = report_time; msg.start_time = last_report_block_time_; msg.end_time = report_time; last_report_block_time_ = report_time; HandleStateUpdate(controller_->OnTransportLossReport(msg)); } Clock* clock = Clock::GetRealTimeClock(); TimeDelta rtt = TimeDelta::PlusInfinity(); for (auto& rb : report.rr.report_blocks()) { if (rb.last_sr()) { Timestamp report_log_time = Timestamp::Micros(report.log_time_us()); uint32_t receive_time_ntp = CompactNtp(clock->ConvertTimestampToNtpTime(report_log_time)); uint32_t rtt_ntp = receive_time_ntp - rb.delay_since_last_sr() - rb.last_sr(); rtt = std::min(rtt, CompactNtpRttToTimeDelta(rtt_ntp)); } } if (rtt.IsFinite()) { RoundTripTimeUpdate msg; msg.receive_time = report_time; msg.round_trip_time = rtt; HandleStateUpdate(controller_->OnRoundTripTimeUpdate(msg)); } } void LogBasedNetworkControllerSimulation::OnIceConfig( const LoggedIceCandidatePairConfig& candidate) { if (candidate.type == IceCandidatePairConfigType::kSelected) { auto log_time = Timestamp::Micros(candidate.log_time_us()); ProcessUntil(log_time); NetworkRouteChange msg; msg.at_time = log_time; msg.constraints.min_data_rate = DataRate::KilobitsPerSec(30); msg.constraints.starting_rate = DataRate::KilobitsPerSec(300); msg.constraints.at_time = log_time; HandleStateUpdate(controller_->OnNetworkRouteChange(msg)); } } void LogBasedNetworkControllerSimulation::ProcessEventsInLog( const ParsedRtcEventLog& parsed_log_) { auto packet_infos = parsed_log_.GetOutgoingPacketInfos(); RtcEventProcessor processor; processor.AddEvents( parsed_log_.bwe_probe_cluster_created_events(), [this](const LoggedBweProbeClusterCreatedEvent& probe_cluster) { OnProbeCreated(probe_cluster); }); processor.AddEvents(packet_infos, [this](const LoggedPacketInfo& packet) { OnPacketSent(packet); }); processor.AddEvents( parsed_log_.transport_feedbacks(PacketDirection::kIncomingPacket), [this](const LoggedRtcpPacketTransportFeedback& feedback) { OnFeedback(feedback); }); processor.AddEvents( parsed_log_.receiver_reports(PacketDirection::kIncomingPacket), [this](const LoggedRtcpPacketReceiverReport& report) { OnReceiverReport(report); }); processor.AddEvents(parsed_log_.ice_candidate_pair_configs(), [this](const LoggedIceCandidatePairConfig& candidate) { OnIceConfig(candidate); }); processor.ProcessEventsInOrder(); } } // namespace webrtc