| /* |
| * Copyright (c) 2018 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 "api/transport/test/network_control_tester.h" |
| |
| #include <algorithm> |
| |
| #include "api/transport/network_control.h" |
| #include "rtc_base/logging.h" |
| |
| namespace webrtc { |
| namespace test { |
| namespace { |
| void Update(NetworkControlUpdate* target, const NetworkControlUpdate& update) { |
| if (update.congestion_window) { |
| RTC_LOG(LS_INFO) << "Received window=" |
| << ToString(*update.congestion_window); |
| target->congestion_window = update.congestion_window; |
| } |
| if (update.pacer_config) { |
| RTC_LOG(LS_INFO) << "Received pacing at:" |
| << ToString(update.pacer_config->at_time) |
| << ": rate=" << ToString(update.pacer_config->data_rate()) |
| << ", pad=" << ToString(update.pacer_config->pad_rate()); |
| target->pacer_config = update.pacer_config; |
| } |
| if (update.target_rate) { |
| RTC_LOG(LS_INFO) |
| << "Received target at:" << ToString(update.target_rate->at_time) |
| << ": rate=" << ToString(update.target_rate->target_rate) << ", rtt=" |
| << ToString(update.target_rate->network_estimate.round_trip_time); |
| target->target_rate = update.target_rate; |
| } |
| for (const auto& probe : update.probe_cluster_configs) { |
| target->probe_cluster_configs.push_back(probe); |
| RTC_LOG(LS_INFO) << "Received probe at:" << ToString(probe.at_time) |
| << ": target=" << ToString(probe.target_data_rate); |
| } |
| } |
| } // namespace |
| |
| SentPacket SimpleTargetRateProducer::ProduceNext( |
| const NetworkControlUpdate& cache, |
| Timestamp current_time, |
| TimeDelta time_delta) { |
| DataRate actual_send_rate = |
| std::max(cache.target_rate->target_rate, cache.pacer_config->pad_rate()); |
| SentPacket packet; |
| packet.send_time = current_time; |
| packet.size = time_delta * actual_send_rate; |
| return packet; |
| } |
| |
| NetworkControllerTester::NetworkControllerTester( |
| NetworkControllerFactoryInterface* factory, |
| NetworkControllerConfig initial_config) |
| : current_time_(Timestamp::seconds(100000)), |
| packet_sequence_number_(1), |
| accumulated_buffer_(TimeDelta::Zero()) { |
| initial_config.constraints.at_time = current_time_; |
| controller_ = factory->Create(initial_config); |
| process_interval_ = factory->GetProcessInterval(); |
| ProcessInterval interval_msg; |
| interval_msg.at_time = current_time_; |
| Update(&state_, controller_->OnProcessInterval(interval_msg)); |
| } |
| |
| NetworkControllerTester::~NetworkControllerTester() = default; |
| |
| void NetworkControllerTester::RunSimulation(TimeDelta duration, |
| TimeDelta packet_interval, |
| DataRate actual_bandwidth, |
| TimeDelta propagation_delay, |
| PacketProducer next_packet) { |
| RTC_CHECK(actual_bandwidth.bps() > 0); |
| Timestamp start_time = current_time_; |
| Timestamp last_process_time = current_time_; |
| while (current_time_ - start_time < duration) { |
| bool send_packet = true; |
| if (state_.congestion_window && state_.congestion_window->IsFinite()) { |
| DataSize data_in_flight = DataSize::Zero(); |
| for (PacketResult& packet : outstanding_packets_) |
| data_in_flight += packet.sent_packet->size; |
| if (data_in_flight > *state_.congestion_window) |
| send_packet = false; |
| } |
| |
| if (send_packet) { |
| SentPacket sent_packet; |
| sent_packet = next_packet(state_, current_time_, packet_interval); |
| sent_packet.sequence_number = packet_sequence_number_++; |
| sent_packet.data_in_flight = sent_packet.size; |
| for (PacketResult& packet : outstanding_packets_) |
| sent_packet.data_in_flight += packet.sent_packet->size; |
| Update(&state_, controller_->OnSentPacket(sent_packet)); |
| |
| TimeDelta time_in_flight = sent_packet.size / actual_bandwidth; |
| accumulated_buffer_ += time_in_flight; |
| TimeDelta total_delay = propagation_delay + accumulated_buffer_; |
| PacketResult result; |
| result.sent_packet = sent_packet; |
| result.receive_time = sent_packet.send_time + total_delay; |
| |
| outstanding_packets_.push_back(result); |
| } |
| |
| TimeDelta buffer_consumed = std::min(accumulated_buffer_, packet_interval); |
| accumulated_buffer_ -= buffer_consumed; |
| |
| if (outstanding_packets_.size() >= 2 && |
| current_time_ >= |
| outstanding_packets_[1].receive_time + propagation_delay) { |
| TransportPacketsFeedback feedback; |
| feedback.prior_in_flight = DataSize::Zero(); |
| for (PacketResult& packet : outstanding_packets_) |
| feedback.prior_in_flight += packet.sent_packet->size; |
| while (!outstanding_packets_.empty() && |
| current_time_ >= outstanding_packets_.front().receive_time + |
| propagation_delay) { |
| feedback.packet_feedbacks.push_back(outstanding_packets_.front()); |
| outstanding_packets_.pop_front(); |
| } |
| feedback.feedback_time = |
| feedback.packet_feedbacks.back().receive_time + propagation_delay; |
| feedback.data_in_flight = DataSize::Zero(); |
| for (PacketResult& packet : outstanding_packets_) |
| feedback.data_in_flight += packet.sent_packet->size; |
| Update(&state_, controller_->OnTransportPacketsFeedback(feedback)); |
| } |
| current_time_ += packet_interval; |
| if (current_time_ - last_process_time > process_interval_) { |
| ProcessInterval interval_msg; |
| interval_msg.at_time = current_time_; |
| Update(&state_, controller_->OnProcessInterval(interval_msg)); |
| } |
| } |
| } |
| |
| } // namespace test |
| } // namespace webrtc |